How can I distinguish between a deserialized field that is missing and a value that is null?

I would like to use Serde to parse some JSON as part of an HTTP PATCH request. Since PATCH requests do not transmit the entire object, but only the relevant data for updating, I need the opportunity to tell between a value that has not been transmitted, a value that is explicitly set to null, and a value that is present.

I have a value object with multiple fields with NULL capability:

struct Resource {
    a: Option<i32>,
    b: Option<i32>,
    c: Option<i32>,
}

If the client sends JSON as follows:

{"a": 42, "b": null}

I would like to change ato Some(42), bon Noneand leave it cunchanged.

I tried wrapping each field on another level Option:

#[derive(Debug, Deserialize)]
struct ResourcePatch {
    a: Option<Option<i32>>,
    b: Option<Option<i32>>,
    c: Option<Option<i32>>,
}

b c; None, , b Some(None).

Option s; , 3 , , , .

+6
2

, - . , , :

fn deserialize_optional_field<'de, T, D>(deserializer: D)
    -> Result<Option<Option<T>>, D::Error>
    where D: Deserializer<'de>,
          T: Deserialize<'de>
{
    Ok(Some(Option::deserialize(deserializer)?))
}

:

#[serde(deserialize_with = "deserialize_optional_field"]
a: Option<Option<i32>>,

#[serde(default)], "" None. , Some.

: , None:

#[serde(deserialize_with = "deserialize_optional_field"]
#[serde(skip_serializing_if = "Option::is_none")]
a: Option<Option<i32>>,

. :

Original JSON: {"a": 42, "b": null}
> Resource { a: Some(Some(42)), b: Some(None), c: None }
< {"a":42,"b":null}
+5

E_net4 answer, :

#[derive(Debug)]
enum Patch<T> {
    Missing,
    Null,
    Value(T),
}

impl<T> Default for Patch<T> {
    fn default() -> Self {
        Patch::Missing
    }
}

impl<T> From<Option<T>> for Patch<T> {
    fn from(opt: Option<T>) -> Patch<T> {
        match opt {
            Some(v) => Patch::Value(v),
            None => Patch::Null,
        }
    }
}

impl<'de, T> Deserialize<'de> for Patch<T>
where
    T: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Option::deserialize(deserializer).map(Into::into)
    }
}

:

#[derive(Debug, Deserialize)]
struct ResourcePatch {
    #[serde(default)]
    a: Patch<i32>,
}

, #[serde(default)] ( ). Deserialize Patch , , .

+3

All Articles