-
-
Notifications
You must be signed in to change notification settings - Fork 857
Description
In order to specially handle the (de)serialization of a custom newtype, I added logic to the serialize_newtype_struct
and deserialize_newtype_struct
methods that only executes if the name of the newtype is recognized, according to the pattern described here (the context is supporting a custom Uuid
wrapper in BSON).
However, this pattern breaks when attempting to deserialize structs that are part of a #[serde(flatten)]
chain, since the root deserializer's deserialize_newtype_struct
method is never actually invoked. Serialization appears unaffected.
e.g. given the following
const NEWTYPE_NAME: &str = "$__myspecialstringtype";
struct MyNewtype(String);
impl Serialize for MyNewtype {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_newtype_struct(NEWTYPE_NAME, &self.0)
}
}
impl<'de> Deserialize<'de> for MyNewtype {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct MyVisitor;
impl<'de> Visitor<'de> for MyVisitor {
type Value = MyNewtype;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
todo!()
}
/* custom visitor stuff here */
}
deserializer.deserialize_newtype_struct(NEWTYPE_NAME, MyVisitor)
}
}
impl<'de> Deserializer<'de> for MyDeserializer {
// ... other deserialize stuff here ...
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if name == NEWTYPE_NAME {
// visit something else
} else {
visitor.visit_newtype_struct(self)
}
}
}
The following struct's derived Deserialize
implementation never calls MyDeserializer::deserialize_newtype_struct
, skipping the custom logic. Instead, it calls it on serde::de::private::ContentDeserializer
, which just calls into visit_newtype_struct
.
#[derive(Deserialize, Serialize)]
struct MyData {
header: String,
#[serde(flatten)]
body: BodyData
}
#[derive(Deserialize, Serialize)]
struct BodyData {
field: i32,
nt: MyNewtype
}