From dd7f83c3ee752b6ceeb013764eec6d30d034afd2 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 26 Nov 2020 13:50:06 +0100 Subject: [PATCH] deserialize by reference Allow deserializing things such as `&[u8]` to reference the original data instead of requiring a `Vec` instead. Introduces `perlmod::from_ref_value` next to `perlmod::from_value` with a new signature. Signed-off-by: Wolfgang Bumiller --- perlmod-macro/src/function.rs | 17 ++++++++-------- perlmod/src/de.rs | 38 ++++++++++++++++++++++++++--------- perlmod/src/lib.rs | 2 +- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/perlmod-macro/src/function.rs b/perlmod-macro/src/function.rs index a845ad6..0f516e1 100644 --- a/perlmod-macro/src/function.rs +++ b/perlmod-macro/src/function.rs @@ -92,14 +92,15 @@ pub fn handle_function( }); } else { deserialized_arguments.extend(quote! { - let #deserialized_name: #arg_type = match ::perlmod::from_value(#extracted_name) { - Ok(data) => data, - Err(err) => { - return Err(::perlmod::Value::new_string(&err.to_string()) - .into_mortal() - .into_raw()); - } - }; + let #deserialized_name: #arg_type = + match ::perlmod::from_ref_value(&#extracted_name) { + Ok(data) => data, + Err(err) => { + return Err(::perlmod::Value::new_string(&err.to_string()) + .into_mortal() + .into_raw()); + } + }; }); } diff --git a/perlmod/src/de.rs b/perlmod/src/de.rs index c8ed720..05ff1d3 100644 --- a/perlmod/src/de.rs +++ b/perlmod/src/de.rs @@ -1,6 +1,8 @@ //! Serde deserializer for perl values. -use serde::de::{self, DeserializeOwned, DeserializeSeed, MapAccess, SeqAccess, Visitor}; +use std::marker::PhantomData; + +use serde::de::{self, Deserialize, DeserializeSeed, MapAccess, SeqAccess, Visitor}; use crate::error::Error; use crate::scalar::Type; @@ -8,26 +10,43 @@ use crate::Value; use crate::{array, ffi, hash}; /// Perl [`Value`](crate::Value) deserializer. -struct Deserializer { +struct Deserializer<'de> { input: Value, option_allowed: bool, + _lifetime: PhantomData<&'de Value>, } /// Deserialize a perl [`Value`](crate::Value). +/// +/// Note that this causes all the underlying data to be copied recursively. pub fn from_value(input: Value) -> Result where - T: DeserializeOwned, + T: serde::de::DeserializeOwned, { - let mut deserializer = Deserializer::from_value(input); + let mut deserializer = Deserializer::<'static>::from_value(input); let out = T::deserialize(&mut deserializer)?; Ok(out) } -impl Deserializer { +/// Deserialize a reference to a perl [`Value`](crate::Value). +/// +/// Note that this causes all the underlying data to be copied recursively, except for data +/// deserialized to `&[u8]`, which will reference the original value. +pub fn from_ref_value<'de, T>(input: &'de Value) -> Result +where + T: Deserialize<'de>, +{ + let mut deserializer = Deserializer::<'de>::from_value(input.clone_ref()); + let out = T::deserialize(&mut deserializer)?; + Ok(out) +} + +impl<'deserializer> Deserializer<'deserializer> { pub fn from_value(input: Value) -> Self { Deserializer { input, option_allowed: true, + _lifetime: PhantomData, } } @@ -60,9 +79,7 @@ impl Deserializer { self.sanity_check()?; Ok(&self.input) } -} -impl Deserializer { /// deserialize_any, preferring a string value fn deserialize_any_string<'de, V>(&mut self, visitor: V) -> Result where @@ -148,7 +165,7 @@ impl Deserializer { } } -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer { +impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result @@ -312,7 +329,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer { use crate::scalar::Flags; if flags.contains(Flags::STRING) { - visitor.visit_bytes(value.pv_bytes()) + let bytes = value.pv_bytes(); + let bytes: &'de [u8] = + unsafe { std::slice::from_raw_parts(bytes.as_ptr(), bytes.len()) }; + visitor.visit_borrowed_bytes(bytes) } else if flags.contains(Flags::DOUBLE) { visitor.visit_f64(value.nv()) } else if flags.contains(Flags::INTEGER) { diff --git a/perlmod/src/lib.rs b/perlmod/src/lib.rs index 4597143..bab41ad 100644 --- a/perlmod/src/lib.rs +++ b/perlmod/src/lib.rs @@ -20,7 +20,7 @@ pub mod ffi; pub mod ser; #[doc(inline)] -pub use de::from_value; +pub use de::{from_ref_value, from_value}; #[doc(inline)] pub use ser::to_value;