Ignoring Fields
FlatMessage provides a powerful mechanism to exclude specific fields from serialization and deserialization using the ignore
attribute. This feature is particularly useful for fields that contain runtime-only data, computed values, or zero-sized types that don't need to be persisted. Ignored fields have no impact on the binary representation. The serialized data will not contain any information about ignored fields.
Basic Usage
To ignore a field during serialization and deserialization, use the #[flat_message_item(ignore = true)]
attribute:
#![allow(unused)] fn main() { use flat_message::*; #[derive(FlatMessage)] #[flat_message_options(store_name = false)] struct User { id: u32, name: String, #[flat_message_item(ignore = true)] cached_score: u32, // This field will be ignored } }
When serializing a User
struct, the cached_score
field will not be included in the binary data. During deserialization, this field will be set to its default value.
Alternative Syntax
FlatMessage also supports the skip
attribute as an alias for ignore
:
#![allow(unused)] fn main() { #[derive(FlatMessage)] #[flat_message_options(store_name = false)] struct Data { value: u8, #[flat_message_item(skip = true)] temp_data: u32, // Equivalent to ignore = true } }
Both ignore = true
and skip = true
have identical behavior.
Default Values
Using Type's Default
When a field is ignored, it will be initialized with the type's default value during deserialization:
#![allow(unused)] fn main() { #[derive(FlatMessage)] #[flat_message_options(store_name = false)] struct Example { x: u8, #[flat_message_item(ignore = true)] y: u32, // Will be 0 (u32's default) after deserialization } let data = Example { x: 1, y: 999 }; let mut storage = Storage::default(); data.serialize_to(&mut storage, Config::default()).unwrap(); let deserialized = Example::deserialize_from(&storage).unwrap(); assert_eq!(deserialized.x, 1); assert_eq!(deserialized.y, 0); // Default value, not 999 }
Custom Default Values
You can specify a custom default value for ignored fields using the default
attribute:
#![allow(unused)] fn main() { #[derive(FlatMessage)] #[flat_message_options(store_name = false)] struct Config { version: u8, #[flat_message_item(ignore = true, default = 42)] cache_size: u32, // Will be 42 after deserialization } let config = Config { version: 1, cache_size: 100 }; let mut storage = Storage::default(); config.serialize_to(&mut storage, Config::default()).unwrap(); let deserialized = Config::deserialize_from(&storage).unwrap(); assert_eq!(deserialized.version, 1); assert_eq!(deserialized.cache_size, 42); // Custom default value }
Zero-Sized Types (ZST)
FlatMessage automatically ignores zero-sized types like PhantomData
without requiring explicit attributes:
#![allow(unused)] fn main() { use std::marker::PhantomData; #[derive(Debug, PartialEq, Eq, FlatMessage)] #[flat_message_options(store_name = false)] struct Container<T> { data: u8, _phantom: PhantomData<T>, // Automatically ignored } }
Zero-sized types are treated as if they have ignore = true
applied automatically.
Use Cases
Runtime-Only Data
Ignore fields that are only meaningful during runtime:
#![allow(unused)] fn main() { #[derive(FlatMessage)] struct Session { user_id: u32, created_at: u64, #[flat_message_item(ignore = true)] last_access_time: u64, // Updated frequently, no need to persist #[flat_message_item(ignore = true)] is_active: bool, // Runtime state } }
Computed Values
Ignore fields that can be computed from other data:
#![allow(unused)] fn main() { #[derive(FlatMessage)] struct Rectangle { width: f32, height: f32, #[flat_message_item(ignore = true, default = 0.0)] area: f32, // Can be computed as width * height } impl Rectangle { fn new(width: f32, height: f32) -> Self { Self { width, height, area: width * height, } } fn compute_area(&mut self) { self.area = self.width * self.height; } } }
Temporary Buffers
Ignore fields used as temporary storage:
#![allow(unused)] fn main() { #[derive(FlatMessage)] struct DataProcessor { input: Vec<u8>, output: Vec<u8>, #[flat_message_item(ignore = true)] temp_buffer: Vec<u8>, // Working space, no need to serialize } }
Performance Benefits
Ignoring unnecessary fields can improve performance by:
- Reducing serialized data size
- Decreasing serialization/deserialization time
- Minimizing memory usage for persistent storage
- Enabling better compression ratios