From 87c102370e108479ff94ec3cb5d524da00fcedb0 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 23 Nov 2020 15:51:50 +0100 Subject: [PATCH] add methods to 'bless' values Signed-off-by: Wolfgang Bumiller --- perlmod/Cargo.toml | 1 + perlmod/src/error.rs | 26 +++++++------------------- perlmod/src/ffi.rs | 3 +++ perlmod/src/glue.c | 8 ++++++++ perlmod/src/lib.rs | 1 + perlmod/src/value.rs | 31 +++++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/perlmod/Cargo.toml b/perlmod/Cargo.toml index 4e01bb6..1d41c15 100644 --- a/perlmod/Cargo.toml +++ b/perlmod/Cargo.toml @@ -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"] diff --git a/perlmod/src/error.rs b/perlmod/src/error.rs index 51f567a..bc1e2bd 100644 --- a/perlmod/src/error.rs +++ b/perlmod/src/error.rs @@ -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(msg: T) -> Self { Self(msg.to_string()) diff --git a/perlmod/src/ffi.rs b/perlmod/src/ffi.rs index ae4191a..cb673fb 100644 --- a/perlmod/src/ffi.rs +++ b/perlmod/src/ffi.rs @@ -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. diff --git a/perlmod/src/glue.c b/perlmod/src/glue.c index a12f507..174e228 100644 --- a/perlmod/src/glue.c +++ b/perlmod/src/glue.c @@ -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 diff --git a/perlmod/src/lib.rs b/perlmod/src/lib.rs index c3ef620..d7b3aa0 100644 --- a/perlmod/src/lib.rs +++ b/perlmod/src/lib.rs @@ -14,6 +14,7 @@ //! [`make_package!`]: macro.make_package.html pub(crate) mod error; +pub use error::Error; pub mod de; pub mod ffi; diff --git a/perlmod/src/value.rs b/perlmod/src/value.rs index f85844b..ea26ce5 100644 --- a/perlmod/src/value.rs +++ b/perlmod/src/value.rs @@ -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 { + 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 { + 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