From dd4ba7ac4734f747649a61e77c249622992b65a4 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Tue, 20 Dec 2022 16:14:00 -0500 Subject: [PATCH 1/2] initial serde support --- Cargo.toml | 1 + src/lib.rs | 36 +++++++++++++++++++++----- src/schema/name.rs | 20 +++++++++++++++ src/schema/variant.rs | 8 ++++++ src/schema/variants.rs | 11 ++++++++ src/value/array.rs | 20 +++++++++++++++ src/value/box.rs | 15 ++++++++++- src/value/boxed_dyn.rs | 15 ++++++++++- src/value/boxed_slice.rs | 19 ++++++++++++++ src/value/enum.rs | 55 ++++++++++++++++++++++++++++++++++++++++ src/value/function.rs | 11 ++++++++ src/value/mod.rs | 24 ++++++++++++++++++ src/value/pointer.rs | 49 +++++++++++++++++++++++++++++++++++ src/value/slice_impl.rs | 19 ++++++++++++++ src/value/str_impl.rs | 12 +++++++++ src/value/struct.rs | 41 +++++++++++++++++++++++++++++- 16 files changed, 346 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 52b56af..1fd5242 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ memmap2 = "0.5.7" once_cell = "1.16.0" procmaps = "0.4.1" rustc-demangle = "0.1.21" +serde = "1.0" thiserror = "1.0.37" itertools = "0.10.5" diff --git a/src/lib.rs b/src/lib.rs index 63e9669..a9bcdad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! //! // initialize the debuginfo provider //! let context = deflect::default_provider()?; -//! +//! //! // create some type-erased data //! let erased: Box = Box::new(Foo { a: 42 }); //! @@ -30,27 +30,27 @@ //! //! // pretty-print the reflected value //! assert_eq!(value.to_string(), "box Foo { a: 42 }"); -//! +//! //! // downcast into a `BoxedDyn` value //! let value: deflect::value::BoxedDyn = value.try_into()?; //! //! // dereference the boxed value //! let value: deflect::Value = value.deref()?; -//! +//! //! // downcast into a `Struct` value //! let value: deflect::value::Struct = value.try_into()?; -//! +//! //! // get the field `a` by name //! let Some(field) = value.field("a")? else { //! panic!("no field named `a`!") //! }; -//! +//! //! // get the value of the field //! let value = field.value()?; -//! +//! //! // downcast into a `u8` //! let value: u8 = value.try_into()?; -//! +//! //! // check that it's equal to `42`! //! assert_eq!(value, 42); //! # Ok::<_, Box>(()) @@ -256,6 +256,7 @@ pub trait Reflect { } } +// Implement `Reflect` for ALL types. impl Reflect for T {} impl dyn Reflect + '_ { @@ -460,6 +461,20 @@ macro_rules! generate_type_and_value { } } + impl<'value, 'dwarf, P> serde::Serialize for Value<'value, 'dwarf, P> + where + P: crate::DebugInfoProvider, + { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + $(Self::$t(v) => v.serialize(serializer),)* + } + } + } + $( #[doc = concat!( "Upcast a [`", @@ -795,3 +810,10 @@ fn fmt_err(err: E) -> fmt::Error { eprintln!("ERROR: {err}"); fmt::Error } + +fn ser_err(e: impl ToString) -> E +where + E: serde::ser::Error, +{ + E::custom(e.to_string()) +} diff --git a/src/schema/name.rs b/src/schema/name.rs index b9be854..a9e5cf1 100644 --- a/src/schema/name.rs +++ b/src/schema/name.rs @@ -67,6 +67,26 @@ where pub fn to_slice(&self) -> Result, crate::Error> { Ok(self.name.to_slice()?) } + + pub(crate) fn to_static_str( + &self, + key: crate::gimli::UnitOffset, + ) -> Result<&'static str, crate::Error> { + use dashmap::DashMap; + use once_cell::sync::Lazy; + + static NAME_CACHE: Lazy> = + Lazy::new(DashMap::new); + + let name = NAME_CACHE.entry(key).or_try_insert_with(|| { + let name = self.to_string_lossy()?; + let name = name.to_string(); + let name = Box::leak(name.into_boxed_str()); + Ok::<_, crate::Error>(name) + })?; + + Ok(*name) + } } impl fmt::Debug for Name diff --git a/src/schema/variant.rs b/src/schema/variant.rs index e67ee3c..804c06f 100644 --- a/src/schema/variant.rs +++ b/src/schema/variant.rs @@ -11,6 +11,7 @@ where unit: &'dwarf crate::gimli::Unit, entry: crate::gimli::DebuggingInformationEntry<'dwarf, 'dwarf, R>, discriminant_val: Option, + index: usize, } impl<'dwarf, R> Variant<'dwarf, R> @@ -22,12 +23,14 @@ where unit: &'dwarf crate::gimli::Unit, entry: crate::gimli::DebuggingInformationEntry<'dwarf, 'dwarf, R>, discriminant_val: Option, + index: usize, ) -> Self { Self { dwarf, unit, entry, discriminant_val, + index, } } @@ -83,6 +86,11 @@ where let tree = self.unit.entries_tree(Some(self.entry.offset()))?; Ok(super::Fields::from_tree(self.dwarf, self.unit, tree)) } + + /// The index of the variant. + pub fn index(&self) -> usize { + self.index + } } impl<'dwarf, R> fmt::Display for Variant<'dwarf, R> diff --git a/src/schema/variants.rs b/src/schema/variants.rs index e484b84..6edf48c 100644 --- a/src/schema/variants.rs +++ b/src/schema/variants.rs @@ -36,6 +36,7 @@ where unit: self.unit, iter: self.tree.root()?.children(), discriminant_type: &self.discriminant_type, + count: 0, }) } } @@ -49,6 +50,7 @@ where unit: &'dwarf crate::gimli::Unit, iter: crate::gimli::EntriesTreeIter<'dwarf, 'dwarf, 'tree, R>, discriminant_type: &'tree super::Type<'dwarf, R>, + count: usize, } impl<'dwarf, 'tree, R: crate::gimli::Reader> VariantsIter<'dwarf, 'tree, R> @@ -75,11 +77,16 @@ where .ok_or_else(|| crate::error::missing_child(crate::gimli::DW_TAG_member))?; let entry = crate::get_type(entry.entry())?; let entry = self.unit.entry(entry)?; + + let index = self.count; + self.count = self.count.wrapping_add(1); + return Ok(Some(super::Variant::new( self.dwarf, self.unit, entry, discriminant_value, + index, ))); } crate::gimli::DW_TAG_enumerator => { @@ -90,11 +97,15 @@ where discriminant_value(self.discriminant_type, dw_at_discr_value) }); + let index = self.count; + self.count = self.count.wrapping_add(1); + return Ok(Some(super::Variant::new( self.dwarf, self.unit, entry.clone(), discriminant_value, + index, ))); } crate::gimli::DW_TAG_member => continue, diff --git a/src/value/array.rs b/src/value/array.rs index 2a97c2b..cf93500 100644 --- a/src/value/array.rs +++ b/src/value/array.rs @@ -84,3 +84,23 @@ where debug_list.finish() } } + +impl<'value, 'dwarf, P> serde::Serialize for Array<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + let len = self.schema.len().map_err(crate::ser_err)?; + let len = Some(usize::try_from(len).map_err(crate::ser_err)?); + let mut ser_seq = serializer.serialize_seq(len).map_err(crate::ser_err)?; + for maybe_elt in self.iter().map_err(crate::ser_err)? { + let elt = maybe_elt.map_err(crate::ser_err)?; + ser_seq.serialize_element(&elt)?; + } + ser_seq.end() + } +} diff --git a/src/value/box.rs b/src/value/box.rs index 46d0823..60b798d 100644 --- a/src/value/box.rs +++ b/src/value/box.rs @@ -88,4 +88,17 @@ where f.write_str("box ")?; self.deref().map_err(crate::fmt_err)?.fmt(f) } -} \ No newline at end of file +} + +impl<'value, 'dwarf, P> serde::Serialize for Box<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let value = self.deref().map_err(crate::ser_err)?; + value.serialize(serializer) + } +} diff --git a/src/value/boxed_dyn.rs b/src/value/boxed_dyn.rs index e966771..d53532a 100644 --- a/src/value/boxed_dyn.rs +++ b/src/value/boxed_dyn.rs @@ -38,7 +38,7 @@ where pub fn schema(&self) -> &crate::schema::BoxedDyn<'dwarf, P::Reader> { &self.schema } - + fn data(&self, size: usize) -> Result, crate::Error> { let field = unsafe { super::Field::new(self.schema.pointer().clone(), self.value, self.provider) }; @@ -108,3 +108,16 @@ where value.fmt(f) } } + +impl<'value, 'dwarf, P> serde::Serialize for BoxedDyn<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let value = self.deref().map_err(crate::ser_err)?; + value.serialize(serializer) + } +} diff --git a/src/value/boxed_slice.rs b/src/value/boxed_slice.rs index 0e2cfb8..e0aa619 100644 --- a/src/value/boxed_slice.rs +++ b/src/value/boxed_slice.rs @@ -102,3 +102,22 @@ where f.write_str("[..]") } } + +impl<'value, 'dwarf, P> serde::Serialize for BoxedSlice<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + let len = Some(self.length().map_err(crate::ser_err)?); + let mut ser_seq = serializer.serialize_seq(len).map_err(crate::ser_err)?; + for maybe_elt in self.iter().map_err(crate::ser_err)? { + let elt = maybe_elt.map_err(crate::ser_err)?; + ser_seq.serialize_element(&elt)? + } + ser_seq.end() + } +} diff --git a/src/value/enum.rs b/src/value/enum.rs index 5eb5c09..c92c3d7 100644 --- a/src/value/enum.rs +++ b/src/value/enum.rs @@ -100,3 +100,58 @@ where self.variant().map_err(crate::fmt_err)?.fmt(f) } } + +impl<'value, 'dwarf, P> serde::Serialize for Enum<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStructVariant; + + let schema = self.schema(); + let offset = schema.entry().offset(); + let type_name = schema.name(); + let type_name = type_name + .to_static_str(offset) + .map_err(crate::ser_err)? + .clone(); + + let variant = self.variant().map_err(crate::ser_err)?; + let variant_schema = variant.schema(); + let offset = variant_schema.entry().offset(); + let variant_name = variant_schema.name().map_err(crate::ser_err)?; + let variant_name = variant_name + .to_static_str(offset) + .map_err(crate::ser_err)? + .clone(); + let variant_index = variant_schema.index(); + + let mut fields = variant.fields().map_err(crate::ser_err)?; + let mut fields_iter = fields.iter().map_err(crate::ser_err)?; + let mut fields = vec![]; + while let Some(f) = fields_iter.try_next().map_err(crate::ser_err)? { + fields.push(f); + } + + let mut s = serializer.serialize_struct_variant( + &type_name, + variant_index.try_into().map_err(crate::ser_err)?, + &variant_name, + fields.len(), + )?; + + fields.into_iter().try_for_each(|field| { + let schema = field.schema(); + let offset = schema.entry().offset(); + let field_name = schema.name().map_err(crate::ser_err)?; + let field_name = field_name.to_static_str(offset).map_err(crate::ser_err)?; + let field_value = field.value().map_err(crate::ser_err)?; + s.serialize_field(&field_name, &field_value) + })?; + + s.end() + } +} diff --git a/src/value/function.rs b/src/value/function.rs index f538675..ae0791c 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -58,3 +58,14 @@ where } } +impl<'value, 'dwarf, P> serde::Serialize for Function<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, _: S) -> Result + where + S: serde::Serializer, + { + Err(crate::ser_err("cannot serialize function")) + } +} diff --git a/src/value/mod.rs b/src/value/mod.rs index 804e529..e07fdc8 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -207,6 +207,18 @@ macro_rules! generate_primitive { } } + impl<'value, 'dwarf, P> serde::Serialize for $t<'value, 'dwarf, P> + where + P: crate::DebugInfoProvider, + { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.value().serialize(serializer) + } + } + generate_primitive_conversions!($t); }; } @@ -360,3 +372,15 @@ where } } } + +impl<'value, 'dwarf, P> serde::Serialize for unit<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.value().serialize(serializer) + } +} diff --git a/src/value/pointer.rs b/src/value/pointer.rs index 7082197..7405541 100644 --- a/src/value/pointer.rs +++ b/src/value/pointer.rs @@ -135,3 +135,52 @@ where } } +impl<'value, 'dwarf, P> serde::Serialize for Pointer<'value, 'dwarf, crate::schema::Shared, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let value = self.deref().map_err(crate::ser_err)?; + value.serialize(serializer) + } +} + +impl<'value, 'dwarf, P> serde::Serialize for Pointer<'value, 'dwarf, crate::schema::Unique, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let value = self.deref().map_err(crate::ser_err)?; + value.serialize(serializer) + } +} + +impl<'value, 'dwarf, P> serde::Serialize for Pointer<'value, 'dwarf, crate::schema::Const, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, _: S) -> Result + where + S: serde::Serializer, + { + Err(crate::ser_err("cannot serialize *const pointer")) + } +} + +impl<'value, 'dwarf, P> serde::Serialize for Pointer<'value, 'dwarf, crate::schema::Mut, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, _: S) -> Result + where + S: serde::Serializer, + { + Err(crate::ser_err("cannot serialize *mut pointer")) + } +} diff --git a/src/value/slice_impl.rs b/src/value/slice_impl.rs index c67a033..31903ac 100644 --- a/src/value/slice_impl.rs +++ b/src/value/slice_impl.rs @@ -101,3 +101,22 @@ where debug_list.finish() } } + +impl<'value, 'dwarf, P> serde::Serialize for Slice<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + let len = Some(self.length().map_err(crate::ser_err)?); + let mut ser_seq = serializer.serialize_seq(len).map_err(crate::ser_err)?; + for maybe_elt in self.iter().map_err(crate::ser_err)? { + let elt = maybe_elt.map_err(crate::ser_err)?; + ser_seq.serialize_element(&elt)?; + } + ser_seq.end() + } +} diff --git a/src/value/str_impl.rs b/src/value/str_impl.rs index e592ae0..f42ac55 100644 --- a/src/value/str_impl.rs +++ b/src/value/str_impl.rs @@ -79,6 +79,18 @@ where } } +impl<'value, 'dwarf, P> serde::Serialize for str<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.value().serialize(serializer) + } +} + impl<'value, 'dwarf, P> From> for &'value std::primitive::str where P: crate::DebugInfoProvider, diff --git a/src/value/struct.rs b/src/value/struct.rs index d48d6f7..02d5f46 100644 --- a/src/value/struct.rs +++ b/src/value/struct.rs @@ -40,7 +40,10 @@ where } /// Get a field of this struct by name. - pub fn field(&self, field_name: N) -> Result>, crate::Error> + pub fn field( + &self, + field_name: N, + ) -> Result>, crate::Error> where N: AsRef<[u8]>, { @@ -96,3 +99,39 @@ where debug_struct.finish() } } + +impl<'value, 'dwarf, P> serde::Serialize for Struct<'value, 'dwarf, P> +where + P: crate::DebugInfoProvider, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let schema = self.schema(); + let offset = schema.entry().offset(); + let type_name = schema.name().map_err(crate::ser_err)?; + let type_name = type_name + .to_static_str(offset) + .map_err(crate::ser_err)? + .clone(); + let mut fields = self.fields().map_err(crate::ser_err)?; + let mut fields_iter = fields.iter().map_err(crate::ser_err)?; + let mut fields = vec![]; + while let Some(f) = fields_iter.try_next().map_err(crate::ser_err)? { + fields.push(f); + } + let mut s = serializer.serialize_struct(&type_name, fields.len())?; + fields.into_iter().try_for_each(|field| { + let schema = field.schema(); + let offset = schema.entry().offset(); + let field_name = schema.name().map_err(crate::ser_err)?; + let field_name = field_name.to_static_str(offset).map_err(crate::ser_err)?; + let field_value = field.value().map_err(crate::ser_err)?; + s.serialize_field(&field_name, &field_value) + })?; + s.end() + } +} From 10c4ddc2e09d7c3695bc0644af536afb8518a394 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 21 Dec 2022 14:23:43 -0500 Subject: [PATCH 2/2] Some flimsy serialization tests. TODO: Proper model-based testing, using something like serde_test's `Token`. --- Cargo.toml | 2 ++ src/lib.rs | 12 ++++++++++++ tests/reflect.rs | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1fd5242..f6f97f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,3 +37,5 @@ itertools = "0.10.5" [dev-dependencies] quickcheck = "1.0" quickcheck_macros = "1.0" +serde_derive = "1.0.151" +serde_json = "1.0.11" diff --git a/src/lib.rs b/src/lib.rs index a9bcdad..8ee6354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -326,6 +326,18 @@ impl fmt::Debug for dyn Reflect { } } +impl serde::Serialize for dyn Reflect + '_ +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let context = default_provider().map_err(crate::ser_err)?; + let value = self.reflect(&context).map_err(crate::ser_err)?; + value.serialize(serializer) + } +} + macro_rules! generate_type_and_value { ($($(#[$attr:meta])* $t:ident,)*) => { /// A reflected type. diff --git a/tests/reflect.rs b/tests/reflect.rs index bcb2727..6f45cd4 100644 --- a/tests/reflect.rs +++ b/tests/reflect.rs @@ -1,6 +1,20 @@ use std::fmt; + struct DisplayDebug(T); +#[track_caller] +fn assert_ser_eq(lhs: T, rhs: U) -> Result<(), serde_json::error::Error> +where + T: serde::Serialize, + U: serde::Serialize, +{ + let lhs = serde_json::to_value(lhs)?; + let rhs = serde_json::to_value(rhs)?; + + assert_eq!(lhs, rhs); + Ok(()) +} + impl fmt::Display for DisplayDebug where T: fmt::Debug, @@ -18,6 +32,8 @@ fn phantom_data() -> Result<(), Box> { let value = erased.reflect(&context)?; let value: deflect::value::Struct<_> = value.try_into()?; assert_eq!(value.to_string(), "PhantomData"); + + Ok(()) } @@ -43,6 +59,7 @@ fn tuple_struct() -> Result<(), Box> { #[test] fn braced_struct() -> Result<(), Box> { + #[derive(serde_derive::Serialize)] struct BracedStruct { #[allow(dead_code)] foo: u8, @@ -51,6 +68,7 @@ fn braced_struct() -> Result<(), Box> { let context = deflect::default_provider()?; let value = erased.reflect(&context)?; assert_eq!(value.to_string(), "BracedStruct { foo: 42 }"); + assert_ser_eq(erased, &BracedStruct { foo: 42 })?; Ok(()) } @@ -87,6 +105,7 @@ mod slice { .try_collect()?; assert_eq!(data, collected); + crate::assert_ser_eq(erased, slice)?; Ok(()) } @@ -109,6 +128,7 @@ mod slice { .try_collect()?; assert_eq!(data, collected); + crate::assert_ser_eq(erased, slice)?; Ok(()) } @@ -122,6 +142,7 @@ fn str(data: String) -> Result<(), Box> { let value = erased.reflect(&context)?; let value: &str = value.try_into()?; assert_eq!(slice, value); + crate::assert_ser_eq(erased, slice)?; Ok(()) } @@ -159,6 +180,7 @@ fn boxed_slice() -> Result<(), Box> { let value: deflect::Value = erased.reflect(&context)?; let value: deflect::value::BoxedSlice = value.try_into()?; assert_eq!(value.to_string(), "box [1, 2, 3][..]"); + crate::assert_ser_eq(erased, &data)?; Ok(()) } @@ -189,6 +211,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -202,6 +225,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -215,6 +239,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -228,6 +253,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -241,6 +267,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -254,6 +281,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -267,6 +295,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -280,6 +309,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -306,6 +336,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -319,6 +350,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -332,6 +364,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -345,6 +378,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -358,6 +392,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } @@ -384,6 +419,7 @@ mod primitive { &n, <&_>::try_from(value).expect("failed to downcast") )); + crate::assert_ser_eq(erased, &n)?; Ok(()) } }