bitfield-serialize 0.1.0

A Rust library for defining and serializing bitfield structures with macro support
Documentation
//! Traits for bitfield serialization and sizing.
extern crate hex;
/// Trait for serializing and deserializing bitfield structures.
pub trait BitfieldSerialize {
    /// Serialize the bitfield to a byte vector.
    fn serialize(&self) -> Vec<u8>;

    /// Deserialize a bitfield from a byte slice.
    fn deserialize(data: &[u8]) -> Result<Self, String>
    where
        Self: Sized;

    /// Serialize to a hexadecimal string.
    fn to_hex(&self) -> String {
        hex::encode(self.serialize())
    }

    /// Deserialize from a hexadecimal string.
    fn from_hex(hex_str: &str) -> Result<Self, String>
    where
        Self: Sized,
    {
        let bytes = hex::decode(hex_str).map_err(|e| format!("Invalid hex string: {}", e))?;
        Self::deserialize(&bytes)
    }
}

/// Trait for getting the size of a bitfield structure.
pub trait BitfieldSize {
    /// Return the total number of bits in the bitfield.
    fn bit_size() -> usize;

    /// Return the number of bytes needed to store the bitfield (rounded up).
    fn byte_size() -> usize {
        Self::bit_size().div_ceil(8)
    }
}

// Implement BitfieldSize for primitive types
impl BitfieldSize for u8 {
    fn bit_size() -> usize {
        8
    }
}

impl BitfieldSize for u16 {
    fn bit_size() -> usize {
        16
    }
}

impl BitfieldSize for u32 {
    fn bit_size() -> usize {
        32
    }
}

impl BitfieldSize for u64 {
    fn bit_size() -> usize {
        64
    }
}

// Implement BitfieldSerialize for primitive types
impl BitfieldSerialize for u8 {
    fn serialize(&self) -> Vec<u8> {
        vec![*self]
    }

    fn deserialize(data: &[u8]) -> Result<Self, String> {
        if data.is_empty() {
            return Err("Empty data".to_string());
        }
        Ok(data[0])
    }
}

impl BitfieldSerialize for u16 {
    fn serialize(&self) -> Vec<u8> {
        self.to_le_bytes().to_vec()
    }

    fn deserialize(data: &[u8]) -> Result<Self, String> {
        if data.len() < 2 {
            return Err("Insufficient data for u16".to_string());
        }
        Ok(u16::from_le_bytes([data[0], data[1]]))
    }
}

impl BitfieldSerialize for u32 {
    fn serialize(&self) -> Vec<u8> {
        self.to_le_bytes().to_vec()
    }

    fn deserialize(data: &[u8]) -> Result<Self, String> {
        if data.len() < 4 {
            return Err("Insufficient data for u32".to_string());
        }
        Ok(u32::from_le_bytes([data[0], data[1], data[2], data[3]]))
    }
}

impl BitfieldSerialize for u64 {
    fn serialize(&self) -> Vec<u8> {
        self.to_le_bytes().to_vec()
    }

    fn deserialize(data: &[u8]) -> Result<Self, String> {
        if data.len() < 8 {
            return Err("Insufficient data for u64".to_string());
        }
        Ok(u64::from_le_bytes([
            data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
        ]))
    }
}

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

    #[test]
    fn test_u8_serialize() {
        let value = 42u8;
        let serialized = value.serialize();
        assert_eq!(serialized, vec![42]);
        assert_eq!(u8::deserialize(&serialized).unwrap(), 42);
    }

    #[test]
    fn test_u16_serialize() {
        let value = 0x1234u16;
        let serialized = value.serialize();
        assert_eq!(serialized, vec![0x34, 0x12]); // Little endian
        assert_eq!(u16::deserialize(&serialized).unwrap(), 0x1234);
    }

    #[test]
    fn test_hex_conversion() {
        let value = 0xABu8;
        let hex = value.to_hex();
        assert_eq!(hex, "ab");
        assert_eq!(u8::from_hex(&hex).unwrap(), 0xAB);
    }

    #[test]
    fn test_bit_sizes() {
        assert_eq!(u8::bit_size(), 8);
        assert_eq!(u16::bit_size(), 16);
        assert_eq!(u32::bit_size(), 32);
        assert_eq!(u64::bit_size(), 64);
    }

    #[test]
    fn test_byte_sizes() {
        assert_eq!(u8::byte_size(), 1);
        assert_eq!(u16::byte_size(), 2);
        assert_eq!(u32::byte_size(), 4);
        assert_eq!(u64::byte_size(), 8);
    }
}