#![allow(unused_imports)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#[macro_export]
macro_rules! bitfield {
(
$(
struct $name:ident {
$(
$field_name:ident: $field_type:ty $(, $bits:literal)?
),* $(,)?
}
)+
) => {
$(
bitfield!(@single $name { $($field_name: $field_type $(, $bits)?),* });
)+
};
(
struct $name:ident {
$(
$field_name:ident: $field_type:ty $(, $bits:literal)?
),* $(,)?
}
) => {
bitfield!(@single $name { $($field_name: $field_type $(, $bits)?),* });
};
(@single $name:ident { $($field_name:ident: $field_type:ty $(, $bits:literal)?),* }) => {
#[derive(Debug, Clone, PartialEq)]
pub struct $name {
$(
pub $field_name: bitfield!(@field_type $field_type $(, $bits)?),
)*
_internal_data: Vec<u8>,
}
impl $name {
pub fn new() -> Self {
Self {
$(
$field_name: Default::default(),
)*
_internal_data: vec![0; Self::byte_size()],
}
}
pub fn sync_to_data(&mut self) {
self._internal_data = vec![0; Self::byte_size()];
let mut current_bit = 0;
$(
bitfield!(@write_field_to_data self, $field_name, $field_type, current_bit $(, $bits)?);
)*
}
pub fn sync_from_data(&mut self) {
let mut current_bit = 0;
$(
bitfield!(@read_field_from_data self, $field_name, $field_type, current_bit $(, $bits)?);
)*
}
pub fn field_bit_size(field_name: &str) -> Option<usize> {
match field_name {
$(
stringify!($field_name) => Some(bitfield!(@size $field_type $(, $bits)?)),
)*
_ => None,
}
}
pub fn field_bit_offset(field_name: &str) -> Option<usize> {
let mut current_bit = 0;
$(
if field_name == stringify!($field_name) {
return Some(current_bit);
}
current_bit += bitfield!(@size $field_type $(, $bits)?);
)*
None
}
fn read_bits_from_data(data: &[u8], start_bit: usize, num_bits: usize) -> u64 {
$crate::utils::BitReader::read_bits_at(data, start_bit, num_bits)
}
fn write_bits_to_data(data: &mut [u8], start_bit: usize, value: u64, num_bits: usize) {
$crate::utils::BitWriter::write_bits_to(data, start_bit, value, num_bits);
}
}
impl $crate::traits::BitfieldSize for $name {
fn bit_size() -> usize {
0 $(+ bitfield!(@size $field_type $(, $bits)?))*
}
}
impl $crate::traits::BitfieldSerialize for $name {
fn serialize(&self) -> Vec<u8> {
let mut instance = self.clone();
instance.sync_to_data();
instance._internal_data
}
fn deserialize(data: &[u8]) -> Result<Self, String> {
if data.len() != Self::byte_size() {
return Err(format!(
"Data size mismatch: expected {} bytes, got {}",
Self::byte_size(),
data.len()
));
}
let mut instance = Self::new();
instance._internal_data = data.to_vec();
instance.sync_from_data();
Ok(instance)
}
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
};
(@field_type $field_type:ty, $bits:literal) => {
$field_type
};
(@field_type $field_type:ty) => {
$field_type
};
(@write_field_to_data $self:ident, $field_name:ident, $field_type:ty, $current_bit:ident, $bits:literal) => {
{
let value = $self.$field_name as u64;
Self::write_bits_to_data(&mut $self._internal_data, $current_bit, value, $bits);
$current_bit += $bits;
}
};
(@write_field_to_data $self:ident, $field_name:ident, $field_type:ty, $current_bit:ident) => {
{
let serialized = $self.$field_name.serialize();
let bit_size = <$field_type>::bit_size();
for (i, &byte) in serialized.iter().enumerate() {
let byte_start_bit = $current_bit + i * 8;
let remaining_bits = bit_size.saturating_sub(i * 8).min(8);
Self::write_bits_to_data(&mut $self._internal_data, byte_start_bit, byte as u64, remaining_bits);
}
$current_bit += bit_size;
}
};
(@read_field_from_data $self:ident, $field_name:ident, $field_type:ty, $current_bit:ident, $bits:literal) => {
{
let value = Self::read_bits_from_data(&$self._internal_data, $current_bit, $bits);
$self.$field_name = value as $field_type;
$current_bit += $bits;
}
};
(@read_field_from_data $self:ident, $field_name:ident, $field_type:ty, $current_bit:ident) => {
{
let bit_size = <$field_type>::bit_size();
let byte_size = bit_size.div_ceil(8);
let mut field_data = vec![0u8; byte_size];
for i in 0..byte_size {
let byte_start_bit = $current_bit + i * 8;
let remaining_bits = bit_size.saturating_sub(i * 8).min(8);
let byte_value = Self::read_bits_from_data(&$self._internal_data, byte_start_bit, remaining_bits);
field_data[i] = byte_value as u8;
}
match <$field_type>::deserialize(&field_data) {
Ok(value) => $self.$field_name = value,
Err(_) => $self.$field_name = Default::default(),
}
$current_bit += bit_size;
}
};
(@size $field_type:ty, $bits:literal) => {
$bits
};
(@size $field_type:ty) => {
<$field_type>::bit_size()
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::{BitfieldSerialize, BitfieldSize};
bitfield! {
struct TestStruct {
field1: u8, 4,
field2: u8, 4,
}
}
bitfield! {
struct SimpleHeader {
version: u8, 4,
flags: u8, 4,
}
struct ComplexPacket {
header: SimpleHeader,
payload_len: u16, 12,
checksum: u8, 8,
}
}
#[test]
fn test_basic_bitfield() {
let mut test_struct = TestStruct::new();
test_struct.field1 = 0xA;
test_struct.field2 = 0xB;
assert_eq!(TestStruct::bit_size(), 8);
assert_eq!(TestStruct::byte_size(), 1);
let serialized = test_struct.serialize();
assert_eq!(serialized.len(), 1);
let deserialized = TestStruct::deserialize(&serialized).unwrap();
assert_eq!(deserialized.field1, 0xA);
assert_eq!(deserialized.field2, 0xB);
}
#[test]
fn test_nested_bitfield() {
let mut packet = ComplexPacket::new();
packet.header.version = 2;
packet.header.flags = 0xF;
packet.payload_len = 1024;
packet.checksum = 0xFF;
let serialized = packet.serialize();
let deserialized = ComplexPacket::deserialize(&serialized).unwrap();
assert_eq!(deserialized.header.version, 2);
assert_eq!(deserialized.header.flags, 0xF);
assert_eq!(deserialized.payload_len, 1024);
assert_eq!(deserialized.checksum, 0xFF);
}
#[test]
fn test_field_metadata() {
assert_eq!(TestStruct::field_bit_size("field1"), Some(4));
assert_eq!(TestStruct::field_bit_size("field2"), Some(4));
assert_eq!(TestStruct::field_bit_size("nonexistent"), None);
assert_eq!(TestStruct::field_bit_offset("field1"), Some(0));
assert_eq!(TestStruct::field_bit_offset("field2"), Some(4));
assert_eq!(TestStruct::field_bit_offset("nonexistent"), None);
}
#[test]
fn test_hex_serialization() {
let mut test_struct = TestStruct::new();
test_struct.field1 = 0xA;
test_struct.field2 = 0xB;
let hex = test_struct.to_hex();
let from_hex = TestStruct::from_hex(&hex).unwrap();
assert_eq!(from_hex.field1, 0xA);
assert_eq!(from_hex.field2, 0xB);
}
}