Skip to main content

stackforge_core/layer/generic/
builder.rs

1//! Builder for dynamically-defined custom protocol layers.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use super::{GenericFieldDesc, GenericLayer};
7use crate::layer::{LayerIndex, LayerKind};
8
9/// Builder for dynamically-defined custom protocol layers.
10///
11/// This builder is intended to be constructed once per protocol definition
12/// (e.g. in Python via the PyO3 bindings) and then used to produce byte
13/// buffers that conform to the protocol layout.
14///
15/// # Example
16///
17/// ```rust
18/// use std::sync::Arc;
19/// use stackforge_core::layer::generic::builder::GenericLayerBuilder;
20/// use stackforge_core::layer::generic::GenericFieldDesc;
21/// use stackforge_core::layer::field::FieldType;
22///
23/// let fields = Arc::new(vec![
24///     GenericFieldDesc {
25///         name: "type_id".to_string(),
26///         offset: 0,
27///         size: 2,
28///         field_type: FieldType::U16,
29///         default_value: vec![0x00, 0x01],
30///     },
31///     GenericFieldDesc {
32///         name: "flags".to_string(),
33///         offset: 2,
34///         size: 1,
35///         field_type: FieldType::U8,
36///         default_value: vec![0x00],
37///     },
38/// ]);
39///
40/// let buf = GenericLayerBuilder::new(Arc::from("MyProto"), fields)
41///     .set_u16("type_id", 0x0042)
42///     .build();
43///
44/// assert_eq!(buf.len(), 3);
45/// assert_eq!(buf[0], 0x00);
46/// assert_eq!(buf[1], 0x42);
47/// assert_eq!(buf[2], 0x00);
48/// ```
49#[derive(Debug, Clone)]
50pub struct GenericLayerBuilder {
51    /// Protocol name.
52    name: Arc<str>,
53    /// Field descriptors shared with all instances.
54    field_descs: Arc<Vec<GenericFieldDesc>>,
55    /// Explicitly set field values (raw bytes, may be padded/truncated to field size).
56    values: HashMap<String, Vec<u8>>,
57}
58
59impl GenericLayerBuilder {
60    /// Create a builder for the named protocol with the given field descriptors.
61    pub fn new(name: Arc<str>, field_descs: Arc<Vec<GenericFieldDesc>>) -> Self {
62        Self {
63            name,
64            field_descs,
65            values: HashMap::new(),
66        }
67    }
68
69    /// Set a field by raw bytes.
70    ///
71    /// If `value` is shorter than the field's declared size it is zero-padded
72    /// (on the right); if it is longer it is truncated.
73    pub fn set(mut self, name: &str, value: Vec<u8>) -> Self {
74        self.values.insert(name.to_string(), value);
75        self
76    }
77
78    /// Set a U8 field by name.
79    pub fn set_u8(self, name: &str, value: u8) -> Self {
80        self.set(name, vec![value])
81    }
82
83    /// Set a U16 field by name (stored big-endian).
84    pub fn set_u16(self, name: &str, value: u16) -> Self {
85        self.set(name, value.to_be_bytes().to_vec())
86    }
87
88    /// Set a U32 field by name (stored big-endian).
89    pub fn set_u32(self, name: &str, value: u32) -> Self {
90        self.set(name, value.to_be_bytes().to_vec())
91    }
92
93    /// Total byte size of the protocol header (sum of all field sizes).
94    pub fn header_size(&self) -> usize {
95        self.field_descs.iter().map(|f| f.size).sum()
96    }
97
98    /// Build the layer into a byte buffer.
99    ///
100    /// Fields not explicitly set fall back to their `default_value`.
101    /// Each field value is copied into the buffer starting at `field.offset`,
102    /// padded with zeros on the right or truncated if the value's length does
103    /// not match `field.size`.
104    pub fn build(&self) -> Vec<u8> {
105        let total = self.header_size();
106        let mut buf = vec![0u8; total];
107
108        for field in self.field_descs.iter() {
109            let src: &[u8] = if let Some(v) = self.values.get(&field.name) {
110                v
111            } else {
112                &field.default_value
113            };
114
115            let dest_start = field.offset;
116            let dest_end = (field.offset + field.size).min(total);
117            let dest_slice = &mut buf[dest_start..dest_end];
118            let copy_len = src.len().min(dest_slice.len());
119
120            // Copy available bytes, leaving remainder zero (already initialised).
121            dest_slice[..copy_len].copy_from_slice(&src[..copy_len]);
122        }
123
124        buf
125    }
126
127    /// Build the byte buffer and wrap it in a [`GenericLayer`].
128    ///
129    /// The returned layer's `LayerIndex` covers `[0..header_size]` within the
130    /// returned byte buffer.
131    pub fn build_layer(&self) -> (GenericLayer, Vec<u8>) {
132        let buf = self.build();
133        let size = buf.len();
134        let index = LayerIndex::new(LayerKind::Generic, 0, size);
135        let layer = GenericLayer::new(index, self.name.clone(), self.field_descs.clone());
136        (layer, buf)
137    }
138
139    /// The protocol name.
140    pub fn name(&self) -> &str {
141        &self.name
142    }
143
144    /// The layer kind (always `LayerKind::Generic`).
145    pub fn kind(&self) -> LayerKind {
146        LayerKind::Generic
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use crate::layer::field::FieldType;
154
155    fn make_fields() -> Arc<Vec<GenericFieldDesc>> {
156        Arc::new(vec![
157            GenericFieldDesc {
158                name: "type_id".to_string(),
159                offset: 0,
160                size: 2,
161                field_type: FieldType::U16,
162                default_value: vec![0x00, 0x01],
163            },
164            GenericFieldDesc {
165                name: "flags".to_string(),
166                offset: 2,
167                size: 1,
168                field_type: FieldType::U8,
169                default_value: vec![0xFF],
170            },
171            GenericFieldDesc {
172                name: "payload_len".to_string(),
173                offset: 3,
174                size: 4,
175                field_type: FieldType::U32,
176                default_value: vec![0x00, 0x00, 0x00, 0x00],
177            },
178        ])
179    }
180
181    #[test]
182    fn test_header_size() {
183        let fields = make_fields();
184        let builder = GenericLayerBuilder::new(Arc::from("Test"), fields);
185        assert_eq!(builder.header_size(), 7); // 2 + 1 + 4
186    }
187
188    #[test]
189    fn test_build_defaults() {
190        let fields = make_fields();
191        let builder = GenericLayerBuilder::new(Arc::from("Test"), fields);
192        let buf = builder.build();
193        assert_eq!(buf.len(), 7);
194        // type_id default = 0x0001
195        assert_eq!(buf[0], 0x00);
196        assert_eq!(buf[1], 0x01);
197        // flags default = 0xFF
198        assert_eq!(buf[2], 0xFF);
199        // payload_len default = 0
200        assert_eq!(&buf[3..7], &[0x00, 0x00, 0x00, 0x00]);
201    }
202
203    #[test]
204    fn test_build_with_set_u16() {
205        let fields = make_fields();
206        let builder =
207            GenericLayerBuilder::new(Arc::from("Test"), fields).set_u16("type_id", 0xABCD);
208        let buf = builder.build();
209        assert_eq!(buf[0], 0xAB);
210        assert_eq!(buf[1], 0xCD);
211        // flags still default
212        assert_eq!(buf[2], 0xFF);
213    }
214
215    #[test]
216    fn test_build_with_set_u32() {
217        let fields = make_fields();
218        let builder =
219            GenericLayerBuilder::new(Arc::from("Test"), fields).set_u32("payload_len", 1024);
220        let buf = builder.build();
221        assert_eq!(&buf[3..7], &1024u32.to_be_bytes());
222    }
223
224    #[test]
225    fn test_build_truncation() {
226        let fields = Arc::new(vec![GenericFieldDesc {
227            name: "f".to_string(),
228            offset: 0,
229            size: 2,
230            field_type: FieldType::U16,
231            default_value: vec![0x00, 0x00],
232        }]);
233        // Setting 4 bytes for a 2-byte field — should be truncated.
234        let builder =
235            GenericLayerBuilder::new(Arc::from("T"), fields).set("f", vec![0xAA, 0xBB, 0xCC, 0xDD]);
236        let buf = builder.build();
237        assert_eq!(buf.len(), 2);
238        assert_eq!(buf[0], 0xAA);
239        assert_eq!(buf[1], 0xBB);
240    }
241
242    #[test]
243    fn test_build_zero_padding() {
244        let fields = Arc::new(vec![GenericFieldDesc {
245            name: "f".to_string(),
246            offset: 0,
247            size: 4,
248            field_type: FieldType::U32,
249            default_value: vec![0x00, 0x00, 0x00, 0x00],
250        }]);
251        // Setting 1 byte for a 4-byte field — rest should be zero.
252        let builder = GenericLayerBuilder::new(Arc::from("T"), fields).set("f", vec![0xAA]);
253        let buf = builder.build();
254        assert_eq!(buf, vec![0xAA, 0x00, 0x00, 0x00]);
255    }
256
257    #[test]
258    fn test_build_layer_returns_valid_layer() {
259        let fields = make_fields();
260        let builder = GenericLayerBuilder::new(Arc::from("MyProto"), fields);
261        let (layer, buf) = builder.build_layer();
262        assert_eq!(layer.index.start, 0);
263        assert_eq!(layer.index.end, 7);
264        assert_eq!(buf.len(), 7);
265    }
266
267    #[test]
268    fn test_kind() {
269        let fields = make_fields();
270        let builder = GenericLayerBuilder::new(Arc::from("T"), fields);
271        assert_eq!(builder.kind(), LayerKind::Generic);
272    }
273}