rust_bitfield_serializer/
types.rs

1//! Type definitions for bitfield structures and serialization.
2
3use std::collections::HashMap;
4
5/// Represents a field in a bitfield structure.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct BitField {
8    /// The name of the field.
9    pub name: String,
10    /// The number of bits for this field.
11    pub bits: usize,
12    /// The type of the field.
13    pub field_type: FieldType,
14}
15
16impl BitField {
17    /// Create a new BitField.
18    pub fn new(name: impl Into<String>, bits: usize, field_type: FieldType) -> Self {
19        Self {
20            name: name.into(),
21            bits,
22            field_type,
23        }
24    }
25}
26
27/// The type of a bitfield field.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum FieldType {
30    /// 8-bit unsigned integer
31    U8,
32    /// 16-bit unsigned integer
33    U16,
34    /// 32-bit unsigned integer
35    U32,
36    /// 64-bit unsigned integer
37    U64,
38    /// Nested bitfield structure
39    Nested(String),
40}
41
42impl FieldType {
43    /// Get the default bit size for primitive types.
44    pub fn default_bit_size(&self) -> Option<usize> {
45        match self {
46            FieldType::U8 => Some(8),
47            FieldType::U16 => Some(16),
48            FieldType::U32 => Some(32),
49            FieldType::U64 => Some(64),
50            FieldType::Nested(_) => None, // Size depends on the nested structure
51        }
52    }
53}
54
55/// Represents a complete bitfield structure definition.
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct BitfieldStruct {
58    /// The name of the structure.
59    pub name: String,
60    /// The fields in the structure.
61    pub fields: Vec<BitField>,
62}
63
64impl BitfieldStruct {
65    /// Create a new BitfieldStruct.
66    pub fn new(name: impl Into<String>) -> Self {
67        Self {
68            name: name.into(),
69            fields: Vec::new(),
70        }
71    }
72
73    /// Add a field to the structure.
74    pub fn add_field(&mut self, name: impl Into<String>, bits: usize, field_type: FieldType) {
75        self.fields.push(BitField::new(name, bits, field_type));
76    }
77
78    /// Calculate the total bit size of this structure.
79    pub fn bit_size(&self, structs: &HashMap<String, BitfieldStruct>) -> usize {
80        self.fields
81            .iter()
82            .map(|field| match &field.field_type {
83                FieldType::Nested(struct_name) => {
84                    if let Some(nested) = structs.get(struct_name) {
85                        nested.bit_size(structs)
86                    } else {
87                        0 // Unknown nested structure
88                    }
89                }
90                _ => field.bits,
91            })
92            .sum()
93    }
94
95    /// Calculate the total byte size of this structure (rounded up).
96    pub fn byte_size(&self, structs: &HashMap<String, BitfieldStruct>) -> usize {
97        self.bit_size(structs).div_ceil(8)
98    }
99
100    /// Get a field by name.
101    pub fn get_field(&self, name: &str) -> Option<&BitField> {
102        self.fields.iter().find(|field| field.name == name)
103    }
104
105    /// Get the bit offset of a field within the structure.
106    pub fn field_bit_offset(
107        &self,
108        field_name: &str,
109        structs: &HashMap<String, BitfieldStruct>,
110    ) -> Option<usize> {
111        let mut offset = 0;
112        for field in &self.fields {
113            if field.name == field_name {
114                return Some(offset);
115            }
116            offset += match &field.field_type {
117                FieldType::Nested(struct_name) => {
118                    if let Some(nested) = structs.get(struct_name) {
119                        nested.bit_size(structs)
120                    } else {
121                        0
122                    }
123                }
124                _ => field.bits,
125            };
126        }
127        None
128    }
129}
130
131/// Represents a value stored in a bitfield structure.
132#[derive(Debug, Clone, PartialEq)]
133pub struct BitfieldValue {
134    /// The name of the structure this value represents.
135    pub struct_name: String,
136    /// The field values.
137    pub values: HashMap<String, FieldValue>,
138}
139
140impl BitfieldValue {
141    /// Create a new BitfieldValue.
142    pub fn new(struct_name: impl Into<String>) -> Self {
143        Self {
144            struct_name: struct_name.into(),
145            values: HashMap::new(),
146        }
147    }
148
149    /// Set a u8 field value.
150    pub fn set_u8(&mut self, field_name: impl Into<String>, value: u8) {
151        self.values.insert(field_name.into(), FieldValue::U8(value));
152    }
153
154    /// Set a u16 field value.
155    pub fn set_u16(&mut self, field_name: impl Into<String>, value: u16) {
156        self.values
157            .insert(field_name.into(), FieldValue::U16(value));
158    }
159
160    /// Set a u32 field value.
161    pub fn set_u32(&mut self, field_name: impl Into<String>, value: u32) {
162        self.values
163            .insert(field_name.into(), FieldValue::U32(value));
164    }
165
166    /// Set a u64 field value.
167    pub fn set_u64(&mut self, field_name: impl Into<String>, value: u64) {
168        self.values
169            .insert(field_name.into(), FieldValue::U64(value));
170    }
171
172    /// Set a nested structure field value.
173    pub fn set_nested(&mut self, field_name: impl Into<String>, value: BitfieldValue) {
174        self.values
175            .insert(field_name.into(), FieldValue::Nested(Box::new(value)));
176    }
177
178    /// Get a u8 field value.
179    pub fn get_u8(&self, field_name: &str) -> Option<u8> {
180        match self.values.get(field_name)? {
181            FieldValue::U8(val) => Some(*val),
182            _ => None,
183        }
184    }
185
186    /// Get a u16 field value.
187    pub fn get_u16(&self, field_name: &str) -> Option<u16> {
188        match self.values.get(field_name)? {
189            FieldValue::U16(val) => Some(*val),
190            _ => None,
191        }
192    }
193
194    /// Get a u32 field value.
195    pub fn get_u32(&self, field_name: &str) -> Option<u32> {
196        match self.values.get(field_name)? {
197            FieldValue::U32(val) => Some(*val),
198            _ => None,
199        }
200    }
201
202    /// Get a u64 field value.
203    pub fn get_u64(&self, field_name: &str) -> Option<u64> {
204        match self.values.get(field_name)? {
205            FieldValue::U64(val) => Some(*val),
206            _ => None,
207        }
208    }
209
210    /// Get a nested structure field value.
211    pub fn get_nested(&self, field_name: &str) -> Option<&BitfieldValue> {
212        match self.values.get(field_name)? {
213            FieldValue::Nested(val) => Some(val),
214            _ => None,
215        }
216    }
217
218    /// Get a mutable reference to a nested structure field value.
219    pub fn get_nested_mut(&mut self, field_name: &str) -> Option<&mut BitfieldValue> {
220        match self.values.get_mut(field_name)? {
221            FieldValue::Nested(val) => Some(val),
222            _ => None,
223        }
224    }
225}
226
227/// Represents a value stored in a bitfield field.
228#[derive(Debug, Clone, PartialEq)]
229pub enum FieldValue {
230    /// 8-bit unsigned integer value
231    U8(u8),
232    /// 16-bit unsigned integer value
233    U16(u16),
234    /// 32-bit unsigned integer value
235    U32(u32),
236    /// 64-bit unsigned integer value
237    U64(u64),
238    /// Nested bitfield structure value
239    Nested(Box<BitfieldValue>),
240}
241
242impl FieldValue {
243    /// Convert the field value to a u64 for bit operations.
244    pub fn to_u64(&self) -> u64 {
245        match self {
246            FieldValue::U8(val) => *val as u64,
247            FieldValue::U16(val) => *val as u64,
248            FieldValue::U32(val) => *val as u64,
249            FieldValue::U64(val) => *val,
250            FieldValue::Nested(_) => 0, // Nested structures cannot be converted to u64
251        }
252    }
253
254    /// Get the type of this field value.
255    pub fn field_type(&self) -> FieldType {
256        match self {
257            FieldValue::U8(_) => FieldType::U8,
258            FieldValue::U16(_) => FieldType::U16,
259            FieldValue::U32(_) => FieldType::U32,
260            FieldValue::U64(_) => FieldType::U64,
261            FieldValue::Nested(val) => FieldType::Nested(val.struct_name.clone()),
262        }
263    }
264}
265
266#[cfg(test)]
267mod tests {
268    use super::*;
269
270    #[test]
271    fn test_bitfield_struct_creation() {
272        let mut bf_struct = BitfieldStruct::new("TestStruct");
273        bf_struct.add_field("field1", 4, FieldType::U8);
274        bf_struct.add_field("field2", 8, FieldType::U16);
275
276        assert_eq!(bf_struct.name, "TestStruct");
277        assert_eq!(bf_struct.fields.len(), 2);
278        assert_eq!(bf_struct.fields[0].name, "field1");
279        assert_eq!(bf_struct.fields[0].bits, 4);
280    }
281
282    #[test]
283    fn test_bitfield_value_operations() {
284        let mut value = BitfieldValue::new("TestStruct");
285        value.set_u8("field1", 42);
286        value.set_u16("field2", 1024);
287
288        assert_eq!(value.get_u8("field1"), Some(42));
289        assert_eq!(value.get_u16("field2"), Some(1024));
290        assert_eq!(value.get_u8("nonexistent"), None);
291    }
292
293    #[test]
294    fn test_nested_structures() {
295        let mut nested = BitfieldValue::new("NestedStruct");
296        nested.set_u8("inner_field", 100);
297
298        let mut parent = BitfieldValue::new("ParentStruct");
299        parent.set_nested("nested", nested);
300
301        let retrieved = parent.get_nested("nested").unwrap();
302        assert_eq!(retrieved.get_u8("inner_field"), Some(100));
303    }
304
305    #[test]
306    fn test_bit_size_calculation() {
307        let mut structs = HashMap::new();
308
309        let mut bf_struct = BitfieldStruct::new("TestStruct");
310        bf_struct.add_field("field1", 4, FieldType::U8);
311        bf_struct.add_field("field2", 12, FieldType::U16);
312
313        structs.insert("TestStruct".to_string(), bf_struct.clone());
314
315        assert_eq!(bf_struct.bit_size(&structs), 16);
316        assert_eq!(bf_struct.byte_size(&structs), 2);
317    }
318
319    #[test]
320    fn test_field_offset_calculation() {
321        let mut structs = HashMap::new();
322
323        let mut bf_struct = BitfieldStruct::new("TestStruct");
324        bf_struct.add_field("field1", 4, FieldType::U8);
325        bf_struct.add_field("field2", 8, FieldType::U16);
326        bf_struct.add_field("field3", 4, FieldType::U8);
327
328        structs.insert("TestStruct".to_string(), bf_struct.clone());
329
330        assert_eq!(bf_struct.field_bit_offset("field1", &structs), Some(0));
331        assert_eq!(bf_struct.field_bit_offset("field2", &structs), Some(4));
332        assert_eq!(bf_struct.field_bit_offset("field3", &structs), Some(12));
333        assert_eq!(bf_struct.field_bit_offset("nonexistent", &structs), None);
334    }
335}