Search code examples
serializationrustserdebincode

Including a None in a bincode deserialization will throw an Error despite being contained in an Option variable


I want to write a struct with corresponding (de)serialization from and to bincode. As a MRE this is the struct:

use serde::{Deserialize, Serialize, Deserializer, Serializer};
use serde_with::skip_serializing_none;
use bincode;
use std::net::IpAddr;
use core::str::FromStr;
use core::fmt::Debug;

#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ip_struct {
    pub loc_ip: Option<IpAddr>,
    pub sending_p: Option<u16>,
    pub opt_id: Option<String>,
}

The (de)serialization looks something like this in the implementation block:

impl ip_struct {

    // Serialization/deserialization bincode
    pub fn new_from_bincode(bincode_vec: &Vec<u8>) -> ip_struct {
        bincode::deserialize(&bincode_vec).unwrap()
    }
    pub fn to_bincode(&self) -> Vec<u8> {
        bincode::serialize(&self).unwrap()
    }

}

Running a simple test, the code panics and throws an error.

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_from_to_bincode() {
        let test_flow = ip_struct {
            loc_ip: Some(IpAddr::from_str("0.0.0.0").unwrap()),
            sending_p: Some(443),
            opt_id: None,
        };

        let encoded_vec = test_flow.to_bincode();
        let res = ip_struct::new_from_bincode(&encoded_vec);

    }

}

The error reads:

called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))
thread 'playground::tests::test_from_to_bincode' panicked at 'called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))'

Finding no information about the error online but, I am not quite sure why the program fails. Removing or setting a String in a Some() on opt_id in the ip_struct will result in no error, but my understanding was that the Option module will be able to handle having None as a value, contrary to having any value set as zero. How do I solve this while still being able to handle None values?


Solution

  • You can't skip fields with Bincode.

    Bincode is not self-describing so if you skip a field it can't tell if it is None or if it should continue parsing the rest of the input.

    Just remove #[skip_serializing_none].