arcium-primitives 0.8.1

Arcium primitives
Documentation
//! Thin wrappers around `bincode`'s free (de)serialization functions that avoid
//! [`bincode::serialize`]'s built-in serialized-size pre-pass.
//!
//! `bincode::serialize` (and `Options::serialize`, which it's built on) always calls
//! `serialized_size` — a full `Serialize::serialize` pass against a `SizeChecker` — before encoding
//! for real into a correctly pre-sized `Vec` (see `bincode`'s internal `serialize` function). For
//! most `#[derive(Serialize)]` types that's cheap: both passes just walk fields, and the size pass
//! does no real work. But `Serialize` impls that build their output eagerly regardless of which
//! serializer is asking — most notably `HeapArray`'s (the [`InPlaceCodec`] fast path), whose
//! `serialize` calls `self.to_inplace_bytes()` unconditionally — end up doing that work twice: once
//! to be measured and thrown away by the `SizeChecker` pass, once for the real encode.
//!
//! [`serialize`] encodes exactly once, writing directly into a growable `Vec` via
//! `bincode::serialize_into` (the same fix already used by `network`'s `IoSink::send`).
//! [`deserialize`] is a plain passthrough to `bincode::deserialize` — bincode's decode path has no
//! equivalent double pass — kept alongside [`serialize`] so callers use one consistent
//! (de)serialization entry point instead of mixing direct `bincode::*` calls with this module.
//!
//! [`InPlaceCodec`]: super::InPlaceCodec

use serde::{de::DeserializeOwned, Serialize};

/// Serialize `value` with `bincode`, without `bincode::serialize`'s serialized-size pre-pass.
pub fn serialize<T: ?Sized + Serialize>(value: &T) -> bincode::Result<Vec<u8>> {
    let mut bytes = Vec::new();
    bincode::serialize_into(&mut bytes, value)?;
    Ok(bytes)
}

/// Deserialize a `T` with `bincode`. A thin passthrough to `bincode::deserialize`, kept alongside
/// [`serialize`] so callers use one consistent (de)serialization entry point.
pub fn deserialize<T: DeserializeOwned>(bytes: &[u8]) -> bincode::Result<T> {
    bincode::deserialize(bytes)
}

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

    #[test]
    fn roundtrips_and_matches_bincode_serialize() {
        let value = (1u64, "hello".to_string(), vec![1u8, 2, 3]);

        let bytes = serialize(&value).unwrap();
        // Same bytes `bincode::serialize` would produce — this is purely a faster encode path,
        // not a different wire format.
        assert_eq!(bytes, bincode::serialize(&value).unwrap());

        let restored: (u64, String, Vec<u8>) = deserialize(&bytes).unwrap();
        assert_eq!(restored, value);
    }
}