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