From 41dd98986687feb80e7f27defbefa9a07fe0dbf7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 2 Dec 2021 14:10:53 +0800 Subject: [PATCH] Support deserialization into byte arrays for BLOB's via serde_bytes. --- CHANGELOG.md | 1 + Cargo.toml | 3 +++ src/serde/de.rs | 31 ++++++++++++++++++++----------- src/serde/ser.rs | 4 ++-- src/types/dynamic.rs | 3 +++ tests/serde.rs | 20 ++++++++++++++++++++ 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 020403dd..d777affa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Enhancements * Added `into_array` and `into_typed_array` for `Dynamic`. * Added `FnPtr::call` and `FnPtr::call_within_context` to simplify calling a function pointer. +* BLob's can now be deserialized (using `from_dynamic`) into `Vec` via [`serde_bytes`](https://crates.io/crates/serde_bytes). Deprecated and Gated API's -------------------------- diff --git a/Cargo.toml b/Cargo.toml index 97461d7f..b2364997 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,9 @@ num-traits = { version = "0.2", default-features = false } smartstring = { version = "0.2.8", default-features = false } rhai_codegen = { version = "1.2", path = "codegen", default-features = false } +[dev-dependencies] +serde_bytes = "0.11" + [features] default = ["ahash/std", "num-traits/std"] unchecked = [] # unchecked arithmetic diff --git a/src/serde/de.rs b/src/serde/de.rs index 9ad18f49..ce602dc2 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -10,7 +10,7 @@ use std::prelude::v1::*; use std::{any::type_name, fmt}; #[cfg(not(feature = "no_index"))] -use crate::Array; +use crate::{Array, Blob}; #[cfg(not(feature = "no_object"))] use crate::Map; @@ -154,7 +154,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_index"))] Union::Array(_, _, _) => self.deserialize_seq(visitor), #[cfg(not(feature = "no_index"))] - Union::Blob(_, _, _) => self.deserialize_seq(visitor), + Union::Blob(_, _, _) => self.deserialize_bytes(visitor), #[cfg(not(feature = "no_object"))] Union::Map(_, _, _) => self.deserialize_map(visitor), Union::FnPtr(_, _, _) => self.type_error(), @@ -357,12 +357,20 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_str(visitor) } - fn deserialize_bytes>(self, _: V) -> Result> { - self.type_error() + fn deserialize_bytes>( + self, + visitor: V, + ) -> Result> { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |x| visitor.visit_bytes(x)) } - fn deserialize_byte_buf>(self, _: V) -> Result> { - self.type_error() + fn deserialize_byte_buf>( + self, + visitor: V, + ) -> Result> { + self.deserialize_bytes(visitor) } fn deserialize_option>( @@ -402,7 +410,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_index"))] return self.value.downcast_ref::().map_or_else( || self.type_error(), - |arr| _visitor.visit_seq(IterateArray::new(arr.iter())), + |arr| _visitor.visit_seq(IterateDynamicArray::new(arr.iter())), ); #[cfg(feature = "no_index")] @@ -497,20 +505,21 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { } /// `SeqAccess` implementation for arrays. -struct IterateArray<'a, ITER: Iterator> { +struct IterateDynamicArray<'a, ITER: Iterator> { /// Iterator for a stream of [`Dynamic`][crate::Dynamic] values. iter: ITER, } -#[cfg(not(feature = "no_index"))] -impl<'a, ITER: Iterator> IterateArray<'a, ITER> { +impl<'a, ITER: Iterator> IterateDynamicArray<'a, ITER> { #[must_use] pub fn new(iter: ITER) -> Self { Self { iter } } } -impl<'a: 'de, 'de, ITER: Iterator> SeqAccess<'de> for IterateArray<'a, ITER> { +impl<'a: 'de, 'de, ITER: Iterator> SeqAccess<'de> + for IterateDynamicArray<'a, ITER> +{ type Error = Box; fn next_element_seed>( diff --git a/src/serde/ser.rs b/src/serde/ser.rs index a784a47e..16fd9d3a 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -257,11 +257,11 @@ impl Serializer for &mut DynamicSerializer { } fn serialize_str(self, v: &str) -> Result> { - Ok(v.to_string().into()) + Ok(v.into()) } fn serialize_bytes(self, v: &[u8]) -> Result> { - Ok(Dynamic::from(v.to_vec())) + Ok(v.into()) } fn serialize_none(self) -> Result> { diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index e0c56a87..38303f11 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -2109,6 +2109,9 @@ impl Dynamic { v.try_cast::().ok_or_else(|| typ) }) .collect(), + Union::Blob(_, _, _) if TypeId::of::() == TypeId::of::() => { + Ok(self.cast::>()) + } #[cfg(not(feature = "no_closure"))] Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] diff --git a/tests/serde.rs b/tests/serde.rs index 95bde973..25929ac5 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -775,3 +775,23 @@ fn test_serde_optional() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(not(feature = "no_index"))] +fn test_serde_blob() -> Result<(), Box> { + let engine = Engine::new(); + + let r = engine.eval::( + " + let x = blob(10); + for i in range(0, 10) { x[i] = i; } + x + ", + )?; + + let r = from_dynamic::(&r)?; + + assert_eq!(r.to_vec(), vec![0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + Ok(()) +}