Reputation: 297
I have created a serialize_foo
function that can serialize the Foo
struct.
struct Foo(i32)
<- The Foo
struct looks like this.
The Foo
struct is used in another struct Bar
that looks like this:
struct Bar {
#[serde(serialize_with = "serialize_foo")]
pub x: Foo,
#[serde(serialize_with = "serialize_foo")]
pub y: Option<Foo>
}
The x
field can be serialized with the serialize_foo
function, but the y
field can't. It is because it is an Option
.
How should I serialize an Option
, should there be a new function serialize_foo_option
, but what would the function do if the value is None
.
Upvotes: 6
Views: 4755
Reputation: 71005
If you control the serializer function, you can avoid having to write an addition function for Option
. This is especially important if you have many wrappers, e.g. Vec
, Option
, etc.. You can do that with serde_with
, which has a more composable system of [de]serialization:
use serde::{Serialize, Serializer};
struct SerializeFoo;
impl serde_with::SerializeAs<Foo> for SerializeFoo {
fn serialize_as<S: Serializer>(source: &Foo, serializer: S) -> Result<S::Ok, S::Error> {
// Serialize here...
}
}
#[serde_with::serde_as]
#[derive(Serialize)]
struct Bar {
#[serde_as(as = "SerializeFoo")]
pub x: Foo,
#[serde_as(as = "Option<SerializeFoo>")]
// This works as normal:
// #[serde(skip_serializing_if = "Option::is_none")]
pub y: Option<Foo>,
}
Upvotes: 0
Reputation: 473
This worked for me:
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Deserialize, Serialize)]
struct Golden {
#[serde(serialize_with = "from_evil", deserialize_with = "to_evil")]
one: Option<Evil>,
}
struct Evil {
two: String,
}
fn from_evil<S: Serializer>(v: &Option<Evil>, serializer: S) -> Result<S::Ok, S::Error> {
let v = v.as_ref().and_then(|v| Some(v.two.clone()));
Option::<String>::serialize(&v, serializer)
}
fn to_evil<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<Evil>, D::Error> {
Option::<String>::deserialize(deserializer)
.and_then(|str| Ok(str.and_then(|str| Some(Evil { two: str }))))
}
Also make sure to include required serde features
[dependencies]
serde = {version = "1.0.196", features = ["serde_derive"] }
Upvotes: 1
Reputation: 297
There are multiple ways to solve this problem but this one fits me the best.
I created a new function called serialize_foo_option
that looks like the following:
pub fn serialize_foo_option<S>(
maybe_foo: &Option<Foo>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(some_len)?;
if let Some(foo) = maybe_foo {
map.serialize_entry("key", &foo)?;
}
map.end()
}
This way if None
is provided nothing is serialized.
Upvotes: 5