guardian-db 0.19.0

High-performance, local-first decentralized database built on Rust and Iroh
Documentation
use crate::guardian::error::GuardianError;
use crate::guardian::serializer;
use crate::traits::{MessageExchangeHeads, MessageMarshaler};

/// Marshaler using Postcard (binary, deterministic, performant).
///
/// **Characteristics:**
/// - 70-85% smaller than JSON
/// - ~6x faster than JSON
/// - Deterministic (consistent BLAKE3 hash)
/// - Compatible with iroh-blobs
/// - Zero-copy deserialization
pub struct PostcardMarshaler;

impl Default for PostcardMarshaler {
    fn default() -> Self {
        Self::new()
    }
}

impl PostcardMarshaler {
    pub fn new() -> Self {
        Self
    }
}

impl MessageMarshaler for PostcardMarshaler {
    type Error = GuardianError;

    fn marshal(&self, m: &MessageExchangeHeads) -> std::result::Result<Vec<u8>, Self::Error> {
        serializer::serialize(m)
    }

    fn unmarshal(&self, data: &[u8]) -> std::result::Result<MessageExchangeHeads, Self::Error> {
        serializer::deserialize(data)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::log::entry::Entry;
    use crate::log::identity::{Identity, Signatures};

    fn create_test_message() -> MessageExchangeHeads {
        let signatures = Signatures::new("test_id_sig", "test_pubkey_sig");

        let identity = Identity::new("test_peer", "test_pubkey", signatures);

        let entry1 = Entry::new(identity.clone(), "test_log", b"test_data_1", &[], None);

        let entry2 = Entry::new(identity, "test_log", b"test_data_2", &[], None);

        MessageExchangeHeads {
            address: "test_address".to_string(),
            heads: vec![entry1, entry2],
        }
    }

    #[test]
    fn test_postcard_roundtrip() {
        let marshaler = PostcardMarshaler::new();
        let message = create_test_message();

        let bytes = marshaler.marshal(&message).expect("Marshal failed");
        let decoded = marshaler.unmarshal(&bytes).expect("Unmarshal failed");

        assert_eq!(message.address, decoded.address);
        assert_eq!(message.heads.len(), decoded.heads.len());
        println!("✅ Postcard roundtrip: {} bytes", bytes.len());
    }

    #[test]
    fn test_postcard_determinism() {
        let marshaler = PostcardMarshaler::new();
        let message = create_test_message();

        // Serialize 5 times.
        let hashes: Vec<String> = (0..5)
            .map(|_| {
                let bytes = marshaler.marshal(&message).expect("Marshal failed");
                blake3::hash(&bytes).to_hex().to_string()
            })
            .collect();

        // All hashes must be identical.
        let first = &hashes[0];
        for hash in &hashes[1..] {
            assert_eq!(first, hash, "Determinism broken!");
        }

        println!("✅ Postcard deterministic hash: {}", first);
    }
}