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