zerompk 0.4.1

A zero-copy, zero-dependency, no_std-compatible, extremely fast MessagePack serializer for Rust.
Documentation
use zerompk::{FromMessagePack, ToMessagePack};

#[derive(Debug, PartialEq, Eq)]
struct Timestamp {
    seconds: i64,
    nanoseconds: u32,
}

impl ToMessagePack for Timestamp {
    fn write<W: zerompk::Write>(&self, writer: &mut W) -> Result<(), zerompk::Error> {
        writer.write_timestamp(self.seconds, self.nanoseconds)
    }
}

impl<'a> FromMessagePack<'a> for Timestamp {
    fn read<R: zerompk::Read<'a>>(reader: &mut R) -> Result<Self, zerompk::Error>
    where
        Self: Sized,
    {
        let (seconds, nanoseconds) = reader.read_timestamp()?;
        Ok(Self {
            seconds,
            nanoseconds,
        })
    }
}

#[test]
fn timestamp32_roundtrip() {
    let ts = Timestamp {
        seconds: 1_700_000_000,
        nanoseconds: 0,
    };

    let encoded = zerompk::to_msgpack_vec(&ts).unwrap();
    assert_eq!(encoded, vec![0xd6, 0xff, 0x65, 0x53, 0xf1, 0x00]);

    let decoded: Timestamp = zerompk::from_msgpack(&encoded).unwrap();
    assert_eq!(decoded, ts);
}

#[test]
fn timestamp64_roundtrip() {
    let ts = Timestamp {
        seconds: 4_294_967_296,
        nanoseconds: 1,
    };

    let encoded = zerompk::to_msgpack_vec(&ts).unwrap();
    assert_eq!(
        encoded,
        vec![0xd7, 0xff, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00]
    );

    let decoded: Timestamp = zerompk::from_msgpack(&encoded).unwrap();
    assert_eq!(decoded, ts);
}

#[test]
fn timestamp96_roundtrip() {
    let ts = Timestamp {
        seconds: -1,
        nanoseconds: 123_456_789,
    };

    let encoded = zerompk::to_msgpack_vec(&ts).unwrap();
    assert_eq!(
        encoded,
        vec![
            0xc7, 0x0c, 0xff, 0x07, 0x5b, 0xcd, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff,
        ]
    );

    let decoded: Timestamp = zerompk::from_msgpack(&encoded).unwrap();
    assert_eq!(decoded, ts);
}

#[test]
fn timestamp_rejects_invalid_nanoseconds_on_write() {
    let ts = Timestamp {
        seconds: 1,
        nanoseconds: 1_000_000_000,
    };

    let err = zerompk::to_msgpack_vec(&ts).unwrap_err();
    assert!(matches!(err, zerompk::Error::InvalidTimestamp));
}

#[test]
fn timestamp_rejects_invalid_nanoseconds_on_read() {
    let data = [
        0xc7, 0x0c, 0xff, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];

    let err = zerompk::from_msgpack::<Timestamp>(&data).unwrap_err();
    assert!(matches!(err, zerompk::Error::InvalidTimestamp));
}

#[cfg(feature = "chrono")]
#[test]
fn chrono_datetime_roundtrip() {
    let value = chrono::DateTime::<chrono::Utc>::from_timestamp(1_700_000_000, 0).unwrap();

    let encoded = zerompk::to_msgpack_vec(&value).unwrap();
    assert_eq!(encoded, vec![0xd6, 0xff, 0x65, 0x53, 0xf1, 0x00]);

    let decoded: chrono::DateTime<chrono::Utc> = zerompk::from_msgpack(&encoded).unwrap();
    assert_eq!(decoded, value);
}

#[cfg(feature = "chrono")]
#[test]
fn chrono_naive_datetime_roundtrip() {
    let value = chrono::DateTime::<chrono::Utc>::from_timestamp(-1, 42)
        .unwrap()
        .naive_utc();

    let encoded = zerompk::to_msgpack_vec(&value).unwrap();
    let decoded: chrono::NaiveDateTime = zerompk::from_msgpack(&encoded).unwrap();
    assert_eq!(decoded, value);
}