Skip to main content

feagi_serialization/
feagi_byte_container.rs

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