Support deserialization into byte arrays for BLOB's via serde_bytes.

This commit is contained in:
Stephen Chung 2021-12-02 14:10:53 +08:00
parent 70f4c53854
commit 41dd989866
6 changed files with 49 additions and 13 deletions

View File

@ -20,6 +20,7 @@ Enhancements
* Added `into_array` and `into_typed_array` for `Dynamic`. * Added `into_array` and `into_typed_array` for `Dynamic`.
* Added `FnPtr::call` and `FnPtr::call_within_context` to simplify calling a function pointer. * 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<u8>` via [`serde_bytes`](https://crates.io/crates/serde_bytes).
Deprecated and Gated API's Deprecated and Gated API's
-------------------------- --------------------------

View File

@ -22,6 +22,9 @@ num-traits = { version = "0.2", default-features = false }
smartstring = { version = "0.2.8", default-features = false } smartstring = { version = "0.2.8", default-features = false }
rhai_codegen = { version = "1.2", path = "codegen", default-features = false } rhai_codegen = { version = "1.2", path = "codegen", default-features = false }
[dev-dependencies]
serde_bytes = "0.11"
[features] [features]
default = ["ahash/std", "num-traits/std"] default = ["ahash/std", "num-traits/std"]
unchecked = [] # unchecked arithmetic unchecked = [] # unchecked arithmetic

View File

@ -10,7 +10,7 @@ use std::prelude::v1::*;
use std::{any::type_name, fmt}; use std::{any::type_name, fmt};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::Array; use crate::{Array, Blob};
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::Map; use crate::Map;
@ -154,7 +154,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Array(_, _, _) => self.deserialize_seq(visitor), Union::Array(_, _, _) => self.deserialize_seq(visitor),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Blob(_, _, _) => self.deserialize_seq(visitor), Union::Blob(_, _, _) => self.deserialize_bytes(visitor),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Union::Map(_, _, _) => self.deserialize_map(visitor), Union::Map(_, _, _) => self.deserialize_map(visitor),
Union::FnPtr(_, _, _) => self.type_error(), Union::FnPtr(_, _, _) => self.type_error(),
@ -357,12 +357,20 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
self.deserialize_str(visitor) self.deserialize_str(visitor)
} }
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_bytes<V: Visitor<'de>>(
self.type_error() self,
visitor: V,
) -> Result<V::Value, Box<EvalAltResult>> {
self.value
.downcast_ref::<Blob>()
.map_or_else(|| self.type_error(), |x| visitor.visit_bytes(x))
} }
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> { fn deserialize_byte_buf<V: Visitor<'de>>(
self.type_error() self,
visitor: V,
) -> Result<V::Value, Box<EvalAltResult>> {
self.deserialize_bytes(visitor)
} }
fn deserialize_option<V: Visitor<'de>>( fn deserialize_option<V: Visitor<'de>>(
@ -402,7 +410,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return self.value.downcast_ref::<Array>().map_or_else( return self.value.downcast_ref::<Array>().map_or_else(
|| self.type_error(), || self.type_error(),
|arr| _visitor.visit_seq(IterateArray::new(arr.iter())), |arr| _visitor.visit_seq(IterateDynamicArray::new(arr.iter())),
); );
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
@ -497,20 +505,21 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
} }
/// `SeqAccess` implementation for arrays. /// `SeqAccess` implementation for arrays.
struct IterateArray<'a, ITER: Iterator<Item = &'a Dynamic>> { struct IterateDynamicArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
/// Iterator for a stream of [`Dynamic`][crate::Dynamic] values. /// Iterator for a stream of [`Dynamic`][crate::Dynamic] values.
iter: ITER, iter: ITER,
} }
#[cfg(not(feature = "no_index"))] impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateDynamicArray<'a, ITER> {
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateArray<'a, ITER> {
#[must_use] #[must_use]
pub fn new(iter: ITER) -> Self { pub fn new(iter: ITER) -> Self {
Self { iter } Self { iter }
} }
} }
impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for IterateArray<'a, ITER> { impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de>
for IterateDynamicArray<'a, ITER>
{
type Error = Box<EvalAltResult>; type Error = Box<EvalAltResult>;
fn next_element_seed<T: DeserializeSeed<'de>>( fn next_element_seed<T: DeserializeSeed<'de>>(

View File

@ -257,11 +257,11 @@ impl Serializer for &mut DynamicSerializer {
} }
fn serialize_str(self, v: &str) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_str(self, v: &str) -> Result<Self::Ok, Box<EvalAltResult>> {
Ok(v.to_string().into()) Ok(v.into())
} }
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Box<EvalAltResult>> {
Ok(Dynamic::from(v.to_vec())) Ok(v.into())
} }
fn serialize_none(self) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_none(self) -> Result<Self::Ok, Box<EvalAltResult>> {

View File

@ -2109,6 +2109,9 @@ impl Dynamic {
v.try_cast::<T>().ok_or_else(|| typ) v.try_cast::<T>().ok_or_else(|| typ)
}) })
.collect(), .collect(),
Union::Blob(_, _, _) if TypeId::of::<T>() == TypeId::of::<u8>() => {
Ok(self.cast::<Vec<T>>())
}
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(cell, _, _) => { Union::Shared(cell, _, _) => {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]

View File

@ -775,3 +775,23 @@ fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {
Ok(()) Ok(())
} }
#[test]
#[cfg(not(feature = "no_index"))]
fn test_serde_blob() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
let r = engine.eval::<Dynamic>(
"
let x = blob(10);
for i in range(0, 10) { x[i] = i; }
x
",
)?;
let r = from_dynamic::<serde_bytes::ByteBuf>(&r)?;
assert_eq!(r.to_vec(), vec![0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
Ok(())
}