Serde deserialize_option based on type value

Hi,

I'm trying to write a deserializer using serde for a binary format where a null value is encoded into the type value in some cases but i'm struggling to figure out any way of doing this. I have no flexibility on changing the binary format. Apologies i have no sample code as I'm perplexed on how to do this. Any tips or example deserializers I can learn from would be appreciated.

# Sample format
i16 -> null value = i16::MIN
i32 -> null value = i32::MIN
...
etc.

e.g. If the value is equal to i16::MIN, then return None, else Some(v)

Not supported nulls:
bool
i8/u8
Sequences
Strings
Maps

I'm not sure I fully understand your problem. Can you give an example input file with a couple of lines?

Relatively straightforward:

fn min_bound_as_none<'de, D, T>(deserializier: D) -> Result<Option<T>, D::Error>
where
    T: Deserialize<'de> + num::Bounded,
    D: Deserializer<'de>
{
    let Some(val) = Option::<T>::deserialize(deserializer)? else {
        return Ok(None);
    };
    
    if val == T::min_value() {
        return Ok(None);
    }
    
    Ok(Some(val))
}

and then use it like

#[derive(Deserialize)]
struct SomeStruct {
    #[serde(default, deserialize_with = "min_bound_as_none")]
    foo: Option<i32>,
}

(the default is required if you wish to maintain serde's default behaviour of defaulting to none if the field is not there with a custom deserializer)

Alternatively, if you do not wish to rely on the num family of crates, you can of course implement the deserializer for a non-generic parameter:

fn i32_min_bound_as_none<'de, D>(deserializier: D) -> Result<Option<i32>, D::Error>
where
    D: Deserializer<'de>,
{
    let Some(val) = Option::<i32>::deserialize(deserializer)? else {
        return Ok(None);
    };
    
    if val == i32::MIN {
        return Ok(None);
    }
    
    Ok(Some(val))
}
1 Like