feagi_data_serialization/
feagi_byte_container.rs

1use byteorder::{ByteOrder, LittleEndian};
2use feagi_data_structures::FeagiDataError;
3use crate::feagi_serializable::FeagiSerializable;
4use crate::FeagiByteStructureType;
5
6type StructureIndex = usize;
7type ByteIndexReadingStart = usize;
8type NumberBytesToRead = usize;
9
10//region Feagi Byte Container
11
12/// A container for serialized FEAGI data structures with efficient binary format.
13/// 
14/// `FeagiByteContainer` manages multiple serializable structures in a single byte array,
15/// providing methods to read, write, and validate the contained data. The container uses
16/// a header-based format with version control and structure indexing.
17/// 
18/// # Format
19/// - Global header: version (1 byte) + increment counter (2 bytes) + struct count (1 byte)
20/// - Per-structure headers: data length (4 bytes each)
21/// - Structure data: serialized structure bytes
22/// 
23/// # Example
24/// ```
25/// use feagi_data_serialization::FeagiByteContainer;
26/// 
27/// let mut container = FeagiByteContainer::new_empty();
28/// assert!(container.is_valid());
29/// assert_eq!(container.get_number_of_bytes_used(), 4); // Just the header
30/// ```
31#[derive(Debug, Clone)]
32pub struct FeagiByteContainer {
33    /// The actual contained byte data
34    bytes: Vec<u8>,
35    /// If the data inside the array is considered valid. If not, most functionality is disabled
36    is_data_valid: bool,
37    /// A vector of references to where in the bytes to get the slices of specific structs, and what type of Feagi data they are
38    contained_struct_references: Vec<ContainedStructReference>,
39}
40
41impl FeagiByteContainer{
42    pub const CURRENT_SUPPORTED_VERSION: u8 = 2;
43
44    pub const GLOBAL_BYTE_HEADER_BYTE_COUNT: usize = 4; // 1 u8, 1 u16, 1 u8
45
46    pub const PER_STRUCT_HEADER_BYTE_COUNT: usize = 4; // 1 u32
47
48    pub const STRUCT_HEADER_BYTE_COUNT: usize = 2; // 1 u8, 1 u8
49
50    //region Constructors
51
52    /// Creates a new empty container with default header.
53    /// 
54    /// The container starts with a 4-byte header containing version, zero increment counter,
55    /// and zero structure count. The container is initially valid with just a 4 byte header
56    /// stating 0 contained structures
57    /// 
58    /// # Example
59    /// ```
60    /// use feagi_data_serialization::FeagiByteContainer;
61    /// 
62    /// let container = FeagiByteContainer::new_empty();
63    /// assert!(container.is_valid());
64    /// assert_eq!(container.get_number_of_bytes_used(), 4);
65    /// ```
66    pub fn new_empty() -> Self {
67        Self { bytes: vec![Self::CURRENT_SUPPORTED_VERSION, 0, 0, 0], is_data_valid: true, contained_struct_references: Vec::new() }
68    }
69
70    //endregion
71
72    // region Direct Data Access
73
74    /// Returns a reference to the internal byte array.
75    /// 
76    /// Provides direct read access to the raw bytes of the container,
77    /// including headers and all serialized structure data.
78    /// 
79    /// # Example
80    /// ```
81    /// use feagi_data_serialization::FeagiByteContainer;
82    /// 
83    /// let container = FeagiByteContainer::new_empty();
84    /// let bytes = container.get_byte_ref();
85    /// assert_eq!(bytes.len(), 4);
86    /// assert_eq!(bytes[0], 2); // Current version
87    /// ```
88    pub fn get_byte_ref(&self) -> &[u8] {
89        &self.bytes
90    }
91
92    /// Writes data using a callback function and validates the container.
93    /// 
94    /// Allows external code to write directly to the byte array, then validates
95    /// that the resulting data forms a valid container structure.
96    /// 
97    /// # Example
98    /// ```
99    /// use feagi_data_serialization::{FeagiByteContainer};
100    ///
101    /// // NOTE: This function is just here as an example, but this specific implementation is invalid
102    /// let mut container = FeagiByteContainer::new_empty();
103    /// let result = container.try_write_data_to_container_and_verify(&mut |bytes| {
104    ///     *bytes = vec![20u8, 2u8, 3u8]; // This is an invalid byte sequence
105    ///     Ok(())
106    /// });
107    /// // This will fail validation since we're setting invalid data
108    /// assert!(result.is_err());
109    /// ```
110    pub fn try_write_data_to_container_and_verify<F>(&mut self, byte_writer: &mut F) -> Result<(), FeagiDataError>
111    where F: FnMut(&mut Vec<u8>) -> Result<(), FeagiDataError> {
112        byte_writer(&mut self.bytes)?;
113        self.verify_container_valid_and_populate()
114    }
115
116    //endregion
117
118    //region Get Properties
119
120    /// Checks if the container has valid data structure.
121    /// 
122    /// Returns true if the container has been validated and contains properly
123    /// formatted header and structure data.
124    /// 
125    /// # Example
126    /// ```
127    /// use feagi_data_serialization::FeagiByteContainer;
128    /// 
129    /// let container = FeagiByteContainer::new_empty();
130    /// assert!(container.is_valid());
131    /// ```
132    pub fn is_valid(&self) -> bool {
133        self.is_data_valid
134    }
135
136    /// Returns the number of structures contained in this container.
137    /// 
138    /// Only works if the container is valid. Returns an error if the container
139    /// has not been validated or contains invalid data.
140    /// 
141    /// # Example
142    /// ```
143    /// use feagi_data_serialization::FeagiByteContainer;
144    ///
145    /// let container = FeagiByteContainer::new_empty();
146    /// assert_eq!(container.try_get_number_contained_structures().unwrap(), 0);
147    /// ```
148    pub fn try_get_number_contained_structures(&self) -> Result<usize, FeagiDataError> {
149        if self.is_data_valid {
150            return Ok(self.contained_struct_references.len())
151        }
152        Err(FeagiDataError::DeserializationError("Given Byte Container is invalid and thus cannot be read!".into()))
153    }
154
155    /// Returns the total number of bytes currently used by the container.
156    /// 
157    /// This includes headers and all structure data.
158    /// 
159    /// # Example
160    /// ```
161    /// use feagi_data_serialization::FeagiByteContainer;
162    /// 
163    /// let container = FeagiByteContainer::new_empty();
164    /// assert_eq!(container.get_number_of_bytes_used(), 4); // Header only
165    /// ```
166    pub fn get_number_of_bytes_used(&self) -> usize {
167        self.bytes.len()
168    }
169
170    /// Returns the total memory allocated for the byte array.
171    /// 
172    /// This may be larger than the number of bytes used due to Vec capacity.
173    /// 
174    /// # Example
175    /// ```
176    /// use feagi_data_serialization::FeagiByteContainer;
177    /// 
178    /// let container = FeagiByteContainer::new_empty();
179    /// assert!(container.get_number_of_bytes_allocated() >= 4);
180    /// ```
181    pub fn get_number_of_bytes_allocated(&self) -> usize {
182        self.bytes.capacity()
183    }
184
185    /// Returns the increment counter value from the header.
186    /// 
187    /// The increment counter is a 16-bit value stored in bytes 1-2 of the header.
188    /// Only works if the container is valid.
189    /// 
190    /// # Example
191    /// ```
192    /// use feagi_data_serialization::FeagiByteContainer;
193    ///
194    /// let container = FeagiByteContainer::new_empty();
195    /// assert_eq!(container.get_increment_counter().unwrap(), 0u16);
196    /// ```
197    pub fn get_increment_counter(&self) -> Result<u16, FeagiDataError> {
198        if self.is_data_valid {
199            return Ok(LittleEndian::read_u16(&self.bytes[1..3]))
200        }
201        Err(FeagiDataError::DeserializationError("Given Byte Container is invalid and thus cannot be read!".into()))
202    }
203
204    //endregion
205
206    //region Extracting Struct Data
207
208    /// Creates a new structure instance from the data at the specified index.
209    /// 
210    /// Deserializes the structure data at the given index and returns a boxed
211    /// trait object. The structure type is determined from the stored metadata.
212    /// 
213    /// # Example
214    /// ```
215    /// use feagi_data_serialization::FeagiByteContainer;
216    /// 
217    /// let container = FeagiByteContainer::new_empty();
218    /// // This will fail since there are no structures
219    /// assert!(container.try_create_new_struct_from_index(0).is_err());
220    /// ```
221    pub fn try_create_new_struct_from_index(&self, index: StructureIndex) -> Result<Box<dyn FeagiSerializable>, FeagiDataError> {
222        self.verify_structure_index_valid(index)?;
223        let relevant_slice = self.contained_struct_references[index].get_as_byte_slice(&self.bytes);
224        let mut boxed_struct: Box<dyn FeagiSerializable> = self.contained_struct_references[index].structure_type.create_new_struct_of_type();
225        boxed_struct.try_update_from_byte_slice(relevant_slice)?;
226        Ok(boxed_struct)
227    }
228
229    pub fn try_create_struct_from_first_found_struct_of_type(&self, structure_type: FeagiByteStructureType) -> Result<Option<Box<dyn FeagiSerializable>>, FeagiDataError> {
230        let getting_slice = self.try_get_first_structure_slice_of_type(structure_type);
231        if getting_slice.is_none() {
232            return Ok(None);
233        }
234        let mut boxed_struct: Box<dyn FeagiSerializable> = structure_type.create_new_struct_of_type();
235        boxed_struct.try_update_from_byte_slice(getting_slice.unwrap())?;
236        Ok(Some(boxed_struct))
237    }
238
239    pub fn try_update_struct_from_index(&self, index: StructureIndex, updating_boxed_struct: &mut dyn FeagiSerializable) -> Result<(), FeagiDataError> {
240        self.verify_structure_index_valid(index)?;
241        let relevant_slice = self.contained_struct_references[index].get_as_byte_slice(&self.bytes);
242        updating_boxed_struct.verify_byte_slice_is_of_correct_type(relevant_slice)?;
243        updating_boxed_struct.try_update_from_byte_slice(relevant_slice)?;
244        Ok(())
245    }
246
247    pub fn try_update_struct_from_first_found_struct_of_type(&self, updating_boxed_struct: &mut dyn FeagiSerializable) -> Result<bool, FeagiDataError> {
248        let structure_type: FeagiByteStructureType = updating_boxed_struct.get_type();
249        let getting_slice = self.try_get_first_structure_slice_of_type(structure_type);
250        if getting_slice.is_none() {
251            return Ok(false);
252        }
253        updating_boxed_struct.try_update_from_byte_slice(getting_slice.unwrap())?;
254        Ok(true)
255    }
256
257    /// Returns a list of all structure types contained in this container.
258    /// 
259    /// Provides a quick way to see what types of structures are available
260    /// without deserializing them.
261    /// 
262    /// # Example
263    /// ```
264    /// use feagi_data_serialization::FeagiByteContainer;
265    /// 
266    /// let container = FeagiByteContainer::new_empty();
267    /// let types = container.get_contained_struct_types();
268    /// assert_eq!(types.len(), 0); // Empty container
269    /// ```
270    pub fn get_contained_struct_types(&self) -> Vec<FeagiByteStructureType> {
271        let mut output: Vec<FeagiByteStructureType> = Vec::with_capacity(self.contained_struct_references.len());
272        for contained_struct_reference in &self.contained_struct_references {
273            output.push(contained_struct_reference.structure_type);
274        };
275        output
276    }
277
278    //endregion
279
280    //region Overwriting Data
281
282    pub fn overwrite_byte_data_with_multiple_struct_data(&mut self, incoming_structs: Vec<&dyn FeagiSerializable>, new_increment_value: u16) -> Result<(), FeagiDataError> {
283
284        self.bytes.clear();
285        self.contained_struct_references.clear();
286        self.is_data_valid = false;
287
288        let header_total_number_of_bytes: usize = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT +
289            Self::PER_STRUCT_HEADER_BYTE_COUNT * incoming_structs.len();
290
291        // Fill out contained_struct_references, calculate total number of bytes used for the data section
292        let data_total_number_of_bytes = {
293            let mut data_start_index = header_total_number_of_bytes;
294            for incoming_struct in &incoming_structs {
295                let per_struct_number_bytes = incoming_struct.get_number_of_bytes_needed();
296                self.contained_struct_references.push(
297                    ContainedStructReference{
298                        structure_type: incoming_struct.get_type(),
299                        byte_start_index: data_start_index,
300                        number_bytes_to_read: per_struct_number_bytes,
301                    }
302                );
303                data_start_index += per_struct_number_bytes;
304            }
305            data_start_index
306        };
307
308        if data_total_number_of_bytes > self.bytes.capacity() {
309            self.bytes.reserve(data_total_number_of_bytes - self.bytes.capacity());
310        }
311
312        // Every single byte will be overridden, don't worry
313        unsafe {
314            self.bytes.set_len(data_total_number_of_bytes); // Fun!
315        }
316
317        // Setup global header
318        self.bytes[0] = Self::CURRENT_SUPPORTED_VERSION;
319        LittleEndian::write_u16(&mut self.bytes[1..3], new_increment_value); // Next 2 bytes is increment counter
320        self.bytes[3] = incoming_structs.len() as u8; // Struct count
321
322        // Write Header and Data bytes at the same time
323        let mut header_byte_index = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT;
324        for struct_index in 0..incoming_structs.len() {
325            let incoming_struct = &incoming_structs[struct_index];
326            let contained_struct_reference = &self.contained_struct_references[struct_index];
327
328            LittleEndian::write_u32(&mut self.bytes[header_byte_index..header_byte_index + 4], contained_struct_reference.number_bytes_to_read as u32);
329            incoming_struct.try_write_to_byte_slice(contained_struct_reference.get_as_byte_slice_mut(&mut self.bytes))?;
330
331            header_byte_index += Self::PER_STRUCT_HEADER_BYTE_COUNT;
332        };
333
334        self.is_data_valid = true;
335        Ok(())
336
337    }
338
339    pub fn overwrite_byte_data_with_single_struct_data(&mut self, incoming_struct: &dyn FeagiSerializable, new_increment_value: u16) -> Result<(), FeagiDataError> {
340
341        self.bytes.clear();
342        self.contained_struct_references.clear();
343        self.is_data_valid = false;
344
345        let header_total_number_of_bytes: usize = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT +
346            Self::PER_STRUCT_HEADER_BYTE_COUNT; // Only 1 struct now
347
348        // Fill out contained_struct_references, calculate total number of bytes used for the data section
349        let data_total_number_of_bytes = {
350            let data_start_index = header_total_number_of_bytes;
351            let per_struct_number_bytes = incoming_struct.get_number_of_bytes_needed();
352            self.contained_struct_references.push(
353                ContainedStructReference{
354                    structure_type: incoming_struct.get_type(),
355                    byte_start_index: data_start_index,
356                    number_bytes_to_read: per_struct_number_bytes,
357                }
358            );
359            data_start_index + per_struct_number_bytes
360        };
361
362        if data_total_number_of_bytes > self.bytes.capacity() {
363            self.bytes.reserve(data_total_number_of_bytes - self.bytes.capacity());
364        }
365
366        // Every single byte will be overridden, don't worry
367        unsafe {
368            self.bytes.set_len(data_total_number_of_bytes); // Fun!
369        }
370
371        // Setup global header
372        self.bytes[0] = Self::CURRENT_SUPPORTED_VERSION;
373        LittleEndian::write_u16(&mut self.bytes[1..3], new_increment_value); // Next 2 bytes is increment counter
374        self.bytes[3] = 1u8; // Struct count is always 1 for single struct
375
376        // Write Header and Data bytes
377        let header_byte_index = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT;
378        let contained_struct_reference = &self.contained_struct_references[0];
379
380        LittleEndian::write_u32(&mut self.bytes[header_byte_index..header_byte_index + 4], contained_struct_reference.number_bytes_to_read as u32);
381        incoming_struct.try_write_to_byte_slice(contained_struct_reference.get_as_byte_slice_mut(&mut self.bytes))?;
382
383        self.is_data_valid = true;
384        Ok(())
385
386    }
387
388    /// Updates the increment counter in the header.
389    /// 
390    /// Modifies the 16-bit increment counter stored in bytes 1-2 of the header.
391    /// The container must be valid for this operation to succeed.
392    /// 
393    /// # Example
394    /// ```
395    /// use feagi_data_serialization::FeagiByteContainer;
396    /// 
397    /// let mut container = FeagiByteContainer::new_empty();
398    /// container.set_increment_counter_state(42);
399    /// ```
400    pub fn set_increment_counter_state(&mut self, new_increment_value: u16) -> Result<(), FeagiDataError> {
401        if !self.is_data_valid {
402            return Err(FeagiDataError::DeserializationError("Given Byte Container is invalid and thus cannot have its increment counter changed!".into()))
403        };
404        LittleEndian::write_u16(&mut self.bytes[1..3], new_increment_value);
405        Ok(())
406    }
407
408    /// Frees any unused memory allocation in the byte vector.
409    /// 
410    /// Shrinks the capacity of the internal byte vector to match its length,
411    /// potentially reducing memory usage.
412    /// 
413    /// # Example
414    /// ```
415    /// use feagi_data_serialization::FeagiByteContainer;
416    /// 
417    /// let mut container = FeagiByteContainer::new_empty();
418    /// container.free_unused_allocation();
419    /// assert_eq!(container.get_number_of_bytes_allocated(), container.get_number_of_bytes_used());
420    /// ```
421    pub fn free_unused_allocation(&mut self) {
422        self.bytes.shrink_to_fit()
423    }
424
425    //endregion
426
427    //region Internal
428
429    /// Verifies the bytes loaded in create a valid FBC container, with indexing that doesn't leave bounds,
430    /// and also configures contained_struct_references.
431    /// WARNING: Does not verify the contained structures themselves!
432    fn verify_container_valid_and_populate(&mut self) -> Result<(), FeagiDataError> {
433        self.is_data_valid = false;
434        self.contained_struct_references.clear();
435        let byte_length = self.bytes.len();
436
437        // Verify Global Header
438        if byte_length < Self::GLOBAL_BYTE_HEADER_BYTE_COUNT { // If we cant even fit the global header, something is wrong
439            return Err(FeagiDataError::DeserializationError("Given Feagi Byte Structure byte length is too short! (Less than 4!)".into()));
440        }
441        if self.bytes[0] != Self::CURRENT_SUPPORTED_VERSION {
442            return Err(FeagiDataError::DeserializationError(format!("Given FEAGI Byte Structure is using version {} when this application only supports version {}!", self.bytes[0], Self::CURRENT_SUPPORTED_VERSION)));
443        }
444        let number_contained_structs = LittleEndian::read_u16(&self.bytes[1..3]) as usize;
445        if number_contained_structs == 0 {
446            self.is_data_valid = true; // This is technically valid, even though no meaningful data was sent
447            return Ok(())
448            // NOTE: It is possible due to an error, that there is data sent after this point. However, we are going to treat this FBC as empty and report it as such.
449        }
450
451        let minimum_count_header_size = Self::PER_STRUCT_HEADER_BYTE_COUNT * number_contained_structs;
452        let total_header_size = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT + minimum_count_header_size;
453        if byte_length < total_header_size {
454            return Err(FeagiDataError::DeserializationError(format!("Feagi Byte Data specifies the existence of {} structures, but the given byte array is under the required {} byte length!", minimum_count_header_size, Self::GLOBAL_BYTE_HEADER_BYTE_COUNT + minimum_count_header_size)));
455        }
456
457        let mut structure_header_byte_index: usize = Self::GLOBAL_BYTE_HEADER_BYTE_COUNT;
458        let mut structure_data_byte_index: usize = total_header_size;
459        for contained_structure_index in 0..number_contained_structs {
460            let structure_length = LittleEndian::read_u32(&self.bytes[structure_header_byte_index..structure_header_byte_index + 4]);
461
462            if structure_data_byte_index + structure_length as usize > byte_length {
463                return Err(FeagiDataError::DeserializationError(
464                    format!("Structure of index {} goes out of bound reaching position {} when given byte length is only {} long!", contained_structure_index, structure_data_byte_index + structure_length as usize, byte_length)));
465            }
466
467            let structure_type = FeagiByteStructureType::try_from(self.bytes[structure_data_byte_index])?;
468            self.contained_struct_references.push( ContainedStructReference {
469                structure_type,
470                byte_start_index: structure_data_byte_index,
471                number_bytes_to_read: structure_length as usize
472            });
473
474            structure_header_byte_index += 4; // Next u32
475            structure_data_byte_index += structure_length as usize;
476        }
477        Ok(())
478    }
479
480    /// Makes sure the given index is valid (not out of range given number of contained structs)
481    fn verify_structure_index_valid(&self, structure_index: StructureIndex) -> Result<(), FeagiDataError> {
482        if structure_index >= self.contained_struct_references.len() {
483            return Err(FeagiDataError::BadParameters(format!("Structure index {} out of bounds! Feagi Byte Container only contains {} structures!", structure_index, self.contained_struct_references.len())));
484        }
485        Ok(())
486    }
487
488    /// Tries to the get the first structure in the contained structure list that is of the requested type. If none are found, returns None.
489    fn try_get_first_structure_slice_of_type(&self, structure_type: FeagiByteStructureType) -> Option<&[u8]> {
490        for index in 0..self.contained_struct_references.len() {
491            if self.contained_struct_references[index].structure_type == structure_type {
492                return Some(self.contained_struct_references[index].get_as_byte_slice(&self.bytes));
493            }
494        };
495        None
496    }
497
498    //endregion
499
500}
501
502//endregion
503
504//region Contained Struct Reference
505#[derive(Debug, Clone, Hash, PartialEq, Eq)]
506struct ContainedStructReference {
507    structure_type: FeagiByteStructureType,
508    byte_start_index: ByteIndexReadingStart,
509    number_bytes_to_read: NumberBytesToRead
510}
511
512impl ContainedStructReference {
513    pub fn get_as_byte_slice<'a>(&self, byte_source: &'a Vec<u8>) -> &'a [u8] {
514        &byte_source[self.byte_start_index ..self.byte_start_index + self.number_bytes_to_read]
515    }
516
517    pub fn get_as_byte_slice_mut<'a>(&self, byte_source: &'a mut Vec<u8>) -> &'a mut [u8] {
518        &mut byte_source[self.byte_start_index ..self.byte_start_index + self.number_bytes_to_read]
519    }
520}
521
522//endregion