Serde_json serializing f32 via u32

pub struct FInt {
    data: f32,
}

impl serde::Serialize for FInt {
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u32(self.data.to_bits())
    }
}

struct FIntVisitor;

impl<'de> serde::de::Visitor<'de> for FIntVisitor {
    type Value = FInt;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> Result<(), Error> {
        formatter.write_str("an integer between -2^31 and 2^31")
    }

    fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(FInt {
            data: f32::from_bits(value),
        })
    }
}

impl<'de> serde::Deserialize<'de> for FInt {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let x = deserializer.deserialize_u32(FIntVisitor)?;
        Ok(x)
    }
}

Is the above a complete implementation or serializing a f32 as a u32? If not, what am I missing?

I'd suggest implementing the visit_u8, visit_u16, and visit_u64 (and maybe the visit_u128) methods as well. Some formats don't distinguish between integers of different sizes, and others might not respect the original type, and so by default, visit_u8 and visit_u16 forward to visit_u64. This means that you can end up getting an "invalid type" error if you only implement visit_u32.

The right way to implement serializing and deserializing one type as another type would be:

use serde::{Deserialize, Deserializer, Serialize, Serializer};

pub struct FInt {
    data: f32,
}

impl Serialize for FInt {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.data.to_bits().serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for FInt {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let bits = u32::deserialize(deserializer)?;
        let data = f32::from_bits(bits);
        Ok(FInt { data })
    }
}
1 Like

@dtolnay : Very nice, thanks! Also answers Simpler way to write serde custom deserialization?