add methods to 'bless' values

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-11-23 15:51:50 +01:00
parent 5d716926a8
commit 87c102370e
6 changed files with 51 additions and 19 deletions

View File

@ -19,6 +19,7 @@ bitflags = "1.2.1"
libc = "0.2"
perlmod-macro = { path = "../perlmod-macro", optional = true, version = "0.1" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
[features]
default = ["exporter"]

View File

@ -1,16 +1,12 @@
#[derive(Debug)]
use thiserror::Error as ThisError;
#[derive(ThisError, Debug)]
#[error("wrong type")]
pub struct CastError;
impl std::fmt::Display for CastError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "wrong type")
}
}
impl std::error::Error for CastError {}
#[derive(Clone, Debug)]
pub struct Error(String);
#[derive(ThisError, Clone, Debug)]
#[error("error: {0}")]
pub struct Error(pub(crate) String);
impl Error {
#[inline]
@ -24,14 +20,6 @@ impl Error {
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "error: {}", self.0)
}
}
impl std::error::Error for Error {}
impl serde::de::Error for Error {
fn custom<T: std::fmt::Display>(msg: T) -> Self {
Self(msg.to_string())

View File

@ -91,6 +91,9 @@ extern "C" {
pub fn RSPL_hv_iternext(hv: *mut HV) -> *mut HE;
pub fn RSPL_hv_iterkeysv(he: *mut HE) -> *mut SV;
pub fn RSPL_hv_iterval(hv: *mut HV, he: *mut HE) -> *mut SV;
pub fn RSPL_gv_stashsv(name: *const SV, flags: i32) -> *mut HV;
pub fn RSPL_sv_bless(sv: *mut SV, stash: *mut HV) -> *mut SV;
}
/// Argument marker for the stack.

View File

@ -270,6 +270,14 @@ extern SV* RSPL_hv_iterval(HV *hv, HE *he) {
return hv_iterval(hv, he);
}
extern HV* RSPL_gv_stashsv(SV *name, int32_t flags) {
return gv_stashsv(name, flags);
}
extern SV* RSPL_sv_bless(SV *sv, HV *stash) {
return sv_bless(sv, stash);
}
/*
These make are convoluted brainfarts:
SVt_NULL undef

View File

@ -14,6 +14,7 @@
//! [`make_package!`]: macro.make_package.html
pub(crate) mod error;
pub use error::Error;
pub mod de;
pub mod ffi;

View File

@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use crate::ffi::{self, SV};
use crate::scalar::ScalarRef;
use crate::Error;
use crate::{Array, Hash, Scalar};
/// A higher level value. This is basically an `SV` already cast to `AV` or `HV` for arrays and
@ -58,6 +59,36 @@ impl Value {
Value::Reference(unsafe { Scalar::from_raw_move(ffi::RSPL_newRV_inc(value.sv())) })
}
/// Bless a value into a package. This turns the value into a reference and forwards to
/// [`Value::bless_ref`].
pub fn bless_value(&self, package: &str) -> Result<Value, Error> {
self.clone_ref().bless_ref(package)
}
/// Bless a reference into a package. The `Value` must be a reference.
pub fn bless_ref(&self, package: &str) -> Result<Value, Error> {
let value = match self {
Value::Reference(v) => v,
_ => Error::fail("trying to bless a non-reference")?,
};
let pkgsv = Scalar::new_string(package);
let stash = unsafe { ffi::RSPL_gv_stashsv(pkgsv.sv(), 0) };
if stash.is_null() {
return Err(Error(format!("failed to find package {:?}", package)));
}
let value = unsafe { ffi::RSPL_sv_bless(value.sv(), stash) };
if value.is_null() {
return Err(Error(format!(
"failed to bless value into package {:?}",
package
)));
}
Ok(Value::Reference(unsafe { Scalar::from_raw_move(value) }))
}
/// Take over a raw `SV` value, assuming that we then own a reference to it.
///
/// # Safety