1use super::header::DxMachineHeader;
4use super::slot::{DxMachineSlot, MAX_INLINE_SIZE};
5
6pub struct DxMachineBuilder<'a> {
12 buffer: &'a mut Vec<u8>,
14 heap_cursor: usize,
16 header: DxMachineHeader,
18}
19
20impl<'a> DxMachineBuilder<'a> {
21 #[inline]
27 pub fn new(buffer: &'a mut Vec<u8>, fixed_size: usize, slot_count: usize) -> Self {
28 let header = DxMachineHeader::new();
29
30 let heap_offset = DxMachineHeader::size() + fixed_size + (slot_count * 16);
32
33 buffer.clear();
35 buffer.reserve(heap_offset + 256); buffer.extend_from_slice(&[0u8; 4]);
39
40 buffer.resize(heap_offset, 0);
42
43 Self {
44 buffer,
45 heap_cursor: heap_offset,
46 header,
47 }
48 }
49
50 #[inline]
52 #[allow(unsafe_code)]
53 pub fn write_fixed<T: Copy>(&mut self, offset: usize, value: T) {
54 let bytes = unsafe {
57 std::slice::from_raw_parts(&value as *const T as *const u8, std::mem::size_of::<T>())
58 };
59
60 let start = DxMachineHeader::size() + offset;
61 self.buffer[start..start + bytes.len()].copy_from_slice(bytes);
62 }
63
64 #[inline]
66 pub fn write_u8(&mut self, offset: usize, value: u8) {
67 self.buffer[DxMachineHeader::size() + offset] = value;
68 }
69
70 #[inline]
72 pub fn write_u16(&mut self, offset: usize, value: u16) {
73 let start = DxMachineHeader::size() + offset;
74 self.buffer[start..start + 2].copy_from_slice(&value.to_le_bytes());
75 }
76
77 #[inline]
79 pub fn write_u32(&mut self, offset: usize, value: u32) {
80 let start = DxMachineHeader::size() + offset;
81 self.buffer[start..start + 4].copy_from_slice(&value.to_le_bytes());
82 }
83
84 #[inline]
86 pub fn write_u64(&mut self, offset: usize, value: u64) {
87 let start = DxMachineHeader::size() + offset;
88 self.buffer[start..start + 8].copy_from_slice(&value.to_le_bytes());
89 }
90
91 #[inline]
93 pub fn write_i8(&mut self, offset: usize, value: i8) {
94 self.write_u8(offset, value as u8);
95 }
96
97 #[inline]
99 pub fn write_i16(&mut self, offset: usize, value: i16) {
100 self.write_u16(offset, value as u16);
101 }
102
103 #[inline]
105 pub fn write_i32(&mut self, offset: usize, value: i32) {
106 self.write_u32(offset, value as u32);
107 }
108
109 #[inline]
111 pub fn write_i64(&mut self, offset: usize, value: i64) {
112 self.write_u64(offset, value as u64);
113 }
114
115 #[inline]
117 pub fn write_f32(&mut self, offset: usize, value: f32) {
118 let start = DxMachineHeader::size() + offset;
119 self.buffer[start..start + 4].copy_from_slice(&value.to_le_bytes());
120 }
121
122 #[inline]
124 pub fn write_f64(&mut self, offset: usize, value: f64) {
125 let start = DxMachineHeader::size() + offset;
126 self.buffer[start..start + 8].copy_from_slice(&value.to_le_bytes());
127 }
128
129 #[inline]
131 pub fn write_bool(&mut self, offset: usize, value: bool) {
132 self.write_u8(offset, value as u8);
133 }
134
135 #[inline]
137 pub fn write_string(&mut self, slot_offset: usize, value: &str) {
138 self.write_bytes(slot_offset, value.as_bytes());
139 }
140
141 #[inline]
143 pub fn write_bytes(&mut self, slot_offset: usize, bytes: &[u8]) {
144 let slot_pos = DxMachineHeader::size() + slot_offset;
145
146 if bytes.len() <= MAX_INLINE_SIZE {
147 let mut slot = DxMachineSlot::new();
149 if slot.write_inline(bytes).is_err() {
152 return;
154 }
155 self.buffer[slot_pos..slot_pos + 16].copy_from_slice(&slot.data);
156 } else {
157 let heap_start = self.heap_cursor - (DxMachineHeader::size() + slot_offset);
159 let offset = (self.heap_cursor - heap_start) as u32;
160
161 let slot = DxMachineSlot::heap_reference(offset, bytes.len() as u32);
162 self.buffer[slot_pos..slot_pos + 16].copy_from_slice(&slot.data);
163
164 self.buffer.extend_from_slice(bytes);
166 self.heap_cursor += bytes.len();
167 self.header.set_has_heap(true);
168 }
169 }
170
171 #[inline]
173 #[allow(unsafe_code)]
174 pub fn write_array<T: Copy>(&mut self, slot_offset: usize, values: &[T]) {
175 let bytes = unsafe {
178 std::slice::from_raw_parts(values.as_ptr() as *const u8, std::mem::size_of_val(values))
179 };
180 self.write_bytes(slot_offset, bytes);
181 }
182
183 #[inline]
185 pub fn finish(self) -> usize {
186 self.header.write_to(&mut self.buffer[0..4]);
188
189 self.buffer.truncate(self.heap_cursor);
191
192 self.heap_cursor
193 }
194
195 #[inline]
197 pub fn heap_position(&self) -> usize {
198 self.heap_cursor
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_builder_basic() {
208 let mut buffer = Vec::new();
209 let mut builder = DxMachineBuilder::new(&mut buffer, 8, 1); builder.write_u64(0, 12345);
212 builder.write_string(8, "test");
213
214 let _size = builder.finish();
215
216 assert!(_size > 0);
217 assert_eq!(buffer[0], 0x5A); assert_eq!(buffer[1], 0x44);
219 }
220
221 #[test]
222 fn test_builder_inline_string() {
223 let mut buffer = Vec::new();
224 let mut builder = DxMachineBuilder::new(&mut buffer, 0, 1);
225
226 builder.write_string(0, "Hello"); let _size = builder.finish();
229
230 let slot_data = &buffer[4..20];
232 assert_eq!(slot_data[0], 5); assert_eq!(slot_data[15], 0x00); assert_eq!(&slot_data[1..6], b"Hello");
235 }
236
237 #[test]
238 fn test_builder_heap_string() {
239 let mut buffer = Vec::new();
240 let mut builder = DxMachineBuilder::new(&mut buffer, 0, 1);
241
242 let long_str = "This is a very long string that exceeds 14 bytes";
243 builder.write_string(0, long_str);
244
245 let size = builder.finish();
246
247 let slot_data = &buffer[4..20];
249 assert_eq!(slot_data[15], 0xFF); assert!(size > 20);
253 }
254
255 #[test]
256 #[allow(clippy::approx_constant)] fn test_builder_multiple_fields() {
258 let mut buffer = Vec::new();
259 let mut builder = DxMachineBuilder::new(&mut buffer, 17, 2);
260
261 builder.write_u64(0, 999);
262 builder.write_u32(8, 42);
263 builder.write_bool(12, true);
264 builder.write_f32(13, 3.14);
265 builder.write_string(17, "name");
266 builder.write_string(33, "email");
267
268 let _size = builder.finish();
269 assert!(_size > 0);
270 }
271
272 #[test]
273 fn test_builder_primitive_types() {
274 let mut buffer = Vec::new();
275 let mut builder = DxMachineBuilder::new(&mut buffer, 30, 0);
276
277 builder.write_u8(0, 255);
278 builder.write_i8(1, -128);
279 builder.write_u16(2, 65535);
280 builder.write_i16(4, -32768);
281 builder.write_u32(6, 4294967295);
282 builder.write_i32(10, -2147483648);
283 builder.write_u64(14, u64::MAX);
284 builder.write_i64(22, i64::MIN);
285
286 builder.finish();
287
288 assert_eq!(buffer[4], 255); assert_eq!(buffer[5] as i8, -128); }
292}