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