Structures
Custom structs with explicit alignment are supported for serialization and deserialization.
Data Type | Object | Slice | Vector | Option |
---|---|---|---|---|
Custom structs with #[derive(FlatMessageStruct)] | Yes | - | - | Yes |
Supported alignments:
- 4-byte alignment (default)
- 8-byte alignment (if one of the fields requires 64 bits alignament - such as Vec
) - 16-byte alignment (if one of the fields requires 128 bits alignament - such as Vec
)
Remarks:
- Structs must derive
FlatMessageStruct
to be used as nested structures within other FlatMessage types. - When using structs in other structs, you must specify the alignment in the field attribute:
#[flat_message_item(align = 4, kind = struct)]
. - The alignment must match the struct's actual memory alignment requirements based on its fields.
- Structs automatically determine their required alignment based on their largest field's alignment requirements.
- This type of serialization does not support metadata fields like
Timestamp
andUniqueID
. You can add them but they will ont be serialized and in deserialization phase they will be defaulted to 0. - Fields can be marked with
#[flat_message_item(ignore = true)]
to exclude them from serialization.
Example
-
Basic struct usage:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct MyData { a: u8, b: u32, c: u16, d: String, } #[derive(Debug, FlatMessage)] #[flat_message_options(store_name = false)] struct Test { x: u8, #[flat_message_item(align = 4, kind = struct)] data: MyData, y: u8, } }
-
Struct with 8-byte alignment (contains u64 vectors or slices):
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct MyData { a: u8, b: u32, c: u16, d: String, values: Vec<u64>, // Requires 8-byte alignment } #[derive(Debug, FlatMessage)] #[flat_message_options(store_name = false)] struct Test { x: u8, #[flat_message_item(align = 8, kind = struct)] data: MyData, y: u8, } }
-
Struct with 16-byte alignment (contains u128 vectors or slices):
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct MyData { a: u8, values: Vec<u128>, // Requires 16-byte alignment } #[derive(Debug, FlatMessage)] #[flat_message_options(store_name = false)] struct Test { x: u8, #[flat_message_item(align = 16, kind = struct)] data: MyData, y: u8, } }
-
Structs with metadata fields:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct EventData { a: u8, b: u32, timestamp: Timestamp, // ignored - will be defaulted to 0 unique_id: UniqueID, // ignored - will be defaulted to 0 } #[derive(Debug, FlatMessage)] #[flat_message_options(store_name = false)] struct Event { #[flat_message_item(align = 4, kind = struct)] data: EventData, } }
-
Using Option with structs:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct Configuration { timeout: u32, retries: u8, } #[derive(Debug, FlatMessage)] struct Request { #[flat_message_item(align = 4, kind = struct)] config: Option<Configuration>, } }
-
Structs with ignored fields:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct ProcessData { pid: u32, name: String, #[flat_message_item(ignore = true)] runtime_state: String, // Not serialized } #[derive(Debug, FlatMessage)] struct ProcessList { #[flat_message_item(align = 4, kind = struct)] processes: Vec<ProcessData>, } }
-
Nested structs:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct LevelTwo { a: bool, l: Vec<i8>, } #[derive(FlatMessageStruct, Debug, PartialEq, Eq)] struct LevelOne { a: u8, b: u32, c: u16, d: String, #[flat_message_item(align = 4, kind = struct)] e: LevelTwo, } #[derive(FlatMessage, Debug, PartialEq, Eq)] #[flat_message_options(store_name = false)] struct Test { x: u8, #[flat_message_item(align = 4, kind = struct)] d: LevelOne, a: u8, } }
Serialization Behavior
When structs are serialized:
-
Field Ordering: Fields are reordered during serialization based on their alignment requirements (largest alignment first) to optimize memory layout.
-
Hash Table: Each struct maintains a hash table of its fields for efficient deserialization and version compatibility.
-
Reference Table: Offset information for each field is stored to enable random access during deserialization.