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    #[must_use]
62    pub fn new(name: Arc<str>, field_descs: Arc<Vec<GenericFieldDesc>>) -> Self {
63        Self {
64            name,
65            field_descs,
66            values: HashMap::new(),
67        }
68    }
69
70    /// Set a field by raw bytes.
71    ///
72    /// If `value` is shorter than the field's declared size it is zero-padded
73    /// (on the right); if it is longer it is truncated.
74    #[must_use]
75    pub fn set(mut self, name: &str, value: Vec<u8>) -> Self {
76        self.values.insert(name.to_string(), value);
77        self
78    }
79
80    /// Set a U8 field by name.
81    #[must_use]
82    pub fn set_u8(self, name: &str, value: u8) -> Self {
83        self.set(name, vec![value])
84    }
85
86    /// Set a U16 field by name (stored big-endian).
87    #[must_use]
88    pub fn set_u16(self, name: &str, value: u16) -> Self {
89        self.set(name, value.to_be_bytes().to_vec())
90    }
91
92    /// Set a U32 field by name (stored big-endian).
93    #[must_use]
94    pub fn set_u32(self, name: &str, value: u32) -> Self {
95        self.set(name, value.to_be_bytes().to_vec())
96    }
97
98    /// Total byte size of the protocol header (sum of all field sizes).
99    #[must_use]
100    pub fn header_size(&self) -> usize {
101        self.field_descs.iter().map(|f| f.size).sum()
102    }
103
104    /// Build the layer into a byte buffer.
105    ///
106    /// Fields not explicitly set fall back to their `default_value`.
107    /// Each field value is copied into the buffer starting at `field.offset`,
108    /// padded with zeros on the right or truncated if the value's length does
109    /// not match `field.size`.
110    #[must_use]
111    pub fn build(&self) -> Vec<u8> {
112        let total = self.header_size();
113        let mut buf = vec![0u8; total];
114
115        for field in self.field_descs.iter() {
116            let src: &[u8] = if let Some(v) = self.values.get(&field.name) {
117                v
118            } else {
119                &field.default_value
120            };
121
122            let dest_start = field.offset;
123            let dest_end = (field.offset + field.size).min(total);
124            let dest_slice = &mut buf[dest_start..dest_end];
125            let copy_len = src.len().min(dest_slice.len());
126
127            // Copy available bytes, leaving remainder zero (already initialised).
128            dest_slice[..copy_len].copy_from_slice(&src[..copy_len]);
129        }
130
131        buf
132    }
133
134    /// Build the byte buffer and wrap it in a [`GenericLayer`].
135    ///
136    /// The returned layer's `LayerIndex` covers `[0..header_size]` within the
137    /// returned byte buffer.
138    #[must_use]
139    pub fn build_layer(&self) -> (GenericLayer, Vec<u8>) {
140        let buf = self.build();
141        let size = buf.len();
142        let index = LayerIndex::new(LayerKind::Generic, 0, size);
143        let layer = GenericLayer::new(index, self.name.clone(), self.field_descs.clone());
144        (layer, buf)
145    }
146
147    /// The protocol name.
148    #[must_use]
149    pub fn name(&self) -> &str {
150        &self.name
151    }
152
153    /// The layer kind (always `LayerKind::Generic`).
154    #[must_use]
155    pub fn kind(&self) -> LayerKind {
156        LayerKind::Generic
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163    use crate::layer::field::FieldType;
164
165    fn make_fields() -> Arc<Vec<GenericFieldDesc>> {
166        Arc::new(vec![
167            GenericFieldDesc {
168                name: "type_id".to_string(),
169                offset: 0,
170                size: 2,
171                field_type: FieldType::U16,
172                default_value: vec![0x00, 0x01],
173            },
174            GenericFieldDesc {
175                name: "flags".to_string(),
176                offset: 2,
177                size: 1,
178                field_type: FieldType::U8,
179                default_value: vec![0xFF],
180            },
181            GenericFieldDesc {
182                name: "payload_len".to_string(),
183                offset: 3,
184                size: 4,
185                field_type: FieldType::U32,
186                default_value: vec![0x00, 0x00, 0x00, 0x00],
187            },
188        ])
189    }
190
191    #[test]
192    fn test_header_size() {
193        let fields = make_fields();
194        let builder = GenericLayerBuilder::new(Arc::from("Test"), fields);
195        assert_eq!(builder.header_size(), 7); // 2 + 1 + 4
196    }
197
198    #[test]
199    fn test_build_defaults() {
200        let fields = make_fields();
201        let builder = GenericLayerBuilder::new(Arc::from("Test"), fields);
202        let buf = builder.build();
203        assert_eq!(buf.len(), 7);
204        // type_id default = 0x0001
205        assert_eq!(buf[0], 0x00);
206        assert_eq!(buf[1], 0x01);
207        // flags default = 0xFF
208        assert_eq!(buf[2], 0xFF);
209        // payload_len default = 0
210        assert_eq!(&buf[3..7], &[0x00, 0x00, 0x00, 0x00]);
211    }
212
213    #[test]
214    fn test_build_with_set_u16() {
215        let fields = make_fields();
216        let builder =
217            GenericLayerBuilder::new(Arc::from("Test"), fields).set_u16("type_id", 0xABCD);
218        let buf = builder.build();
219        assert_eq!(buf[0], 0xAB);
220        assert_eq!(buf[1], 0xCD);
221        // flags still default
222        assert_eq!(buf[2], 0xFF);
223    }
224
225    #[test]
226    fn test_build_with_set_u32() {
227        let fields = make_fields();
228        let builder =
229            GenericLayerBuilder::new(Arc::from("Test"), fields).set_u32("payload_len", 1024);
230        let buf = builder.build();
231        assert_eq!(&buf[3..7], &1024u32.to_be_bytes());
232    }
233
234    #[test]
235    fn test_build_truncation() {
236        let fields = Arc::new(vec![GenericFieldDesc {
237            name: "f".to_string(),
238            offset: 0,
239            size: 2,
240            field_type: FieldType::U16,
241            default_value: vec![0x00, 0x00],
242        }]);
243        // Setting 4 bytes for a 2-byte field — should be truncated.
244        let builder =
245            GenericLayerBuilder::new(Arc::from("T"), fields).set("f", vec![0xAA, 0xBB, 0xCC, 0xDD]);
246        let buf = builder.build();
247        assert_eq!(buf.len(), 2);
248        assert_eq!(buf[0], 0xAA);
249        assert_eq!(buf[1], 0xBB);
250    }
251
252    #[test]
253    fn test_build_zero_padding() {
254        let fields = Arc::new(vec![GenericFieldDesc {
255            name: "f".to_string(),
256            offset: 0,
257            size: 4,
258            field_type: FieldType::U32,
259            default_value: vec![0x00, 0x00, 0x00, 0x00],
260        }]);
261        // Setting 1 byte for a 4-byte field — rest should be zero.
262        let builder = GenericLayerBuilder::new(Arc::from("T"), fields).set("f", vec![0xAA]);
263        let buf = builder.build();
264        assert_eq!(buf, vec![0xAA, 0x00, 0x00, 0x00]);
265    }
266
267    #[test]
268    fn test_build_layer_returns_valid_layer() {
269        let fields = make_fields();
270        let builder = GenericLayerBuilder::new(Arc::from("MyProto"), fields);
271        let (layer, buf) = builder.build_layer();
272        assert_eq!(layer.index.start, 0);
273        assert_eq!(layer.index.end, 7);
274        assert_eq!(buf.len(), 7);
275    }
276
277    #[test]
278    fn test_kind() {
279        let fields = make_fields();
280        let builder = GenericLayerBuilder::new(Arc::from("T"), fields);
281        assert_eq!(builder.kind(), LayerKind::Generic);
282    }
283}