state.rs
Overview
`state.rs` defines the `SerializerState` struct, a compact and efficient representation of the internal state used during serialization operations. It encapsulates recursion and default call counts within a single 32-bit integer, allowing the serializer to track limits and manage nested or default serialization calls safely.
This file primarily provides mechanisms to:
Store serialization options and counters in a packed
u32integer.Check if recursion or default call limits are reached.
Generate updated states for recursive and default calls by incrementing corresponding counters.
These capabilities are critical to prevent infinite recursion or excessive default calls during serialization, which can occur in complex or cyclic data structures.
Detailed Explanation
Constants
RECURSION_SHIFT: usize = 24
Bit position where the recursion counter starts within the 32-bitstate.RECURSION_MASK: u32 = 255 << RECURSION_SHIFT
Mask to isolate the 8-bit recursion counter (bits 24-31).DEFAULT_SHIFT: usize = 16
Bit position where the default calls counter starts.DEFAULT_MASK: u32 = 255 << DEFAULT_SHIFT
Mask to isolate the 8-bit default calls counter (bits 16-23).
These masks and shifts enable packing two 8-bit counters into a single `u32` while leaving the lower 16 bits for storing options.
Struct: SerializerState
#[repr(transparent)]
#[derive(Copy, Clone)]
pub(crate) struct SerializerState {
state: u32,
}
Purpose:
A lightweight wrapper over a 32-bit integer encoding serializer options and counters.Representation:
Uses#[repr(transparent)]for ABI compatibility withu32. DerivesCopyandClonefor efficient value semantics.Internal Layout (bit fields):
Bits 0-15: Serializer options (
opts)Bits 16-23: Default calls count
Bits 24-31: Recursion count
Methods
new(opts: Opt) -> Self
Creates a new `SerializerState` initialized with the given options.
Parameters:
opts:Opt— Serializer options value convertible tou16(ensured by debug assertion).Returns:
A newSerializerStatewithstateset to theoptsvalue (lower 16 bits).Usage Example:
let opts = Opt::default(); // hypothetical Opt value
let state = SerializerState::new(opts);
opts(self) -> u32
Returns the raw options bits stored in `state`.
Returns:
u32representing the entire stored state (including recursion and default counters).Usage Example:
let options_bits = state.opts();
recursion_limit(self) -> bool
Checks if the recursion counter has reached its maximum value (`255`).
Returns:
trueif recursion counter bits equalRECURSION_MASK, otherwisefalse.Usage Example:
if state.recursion_limit() {
// Handle recursion limit reached
}
default_calls_limit(self) -> bool
Checks if the default calls counter has reached its maximum value (`255`).
Returns:
trueif default calls counter bits equalDEFAULT_MASK, otherwisefalse.Usage Example:
if state.default_calls_limit() {
// Handle default calls limit reached
}
copy_for_recursive_call(self) -> Self
Produces a new `SerializerState` with the recursion counter incremented by 1.
Returns:
A newSerializerStatewith the recursion count increased, preserving other bits.Implementation Detail:
Clears recursion bits using
!RECURSION_MASK.Extracts current recursion count, increments it, then shifts back.
Combines incremented recursion bits with other bits.
Usage Example:
let next_state = state.copy_for_recursive_call();
copy_for_default_call(self) -> Self
Produces a new `SerializerState` with the default calls counter incremented by 1.
Returns:
A newSerializerStatewith the default calls count incremented, preserving other bits.Implementation Detail:
Clears default call bits using
!DEFAULT_MASK.Extracts current default calls count, increments it, then shifts back.
Combines incremented default calls bits with other bits.
Usage Example:
let next_state = state.copy_for_default_call();
Important Implementation Details
Bit Packing:
The use of bit shifts and masks packs multiple counters and options into a singleu32for efficient storage and transmission.Counters as 8-bit Fields:
Both recursion and default call counters are stored as 8-bit values (max 255), which is reasonable for typical serialization use cases.Use of
#[repr(transparent)]:
Guarantees thatSerializerStatehas the same memory layout asu32, enabling zero-cost abstraction.Increment Operations:
Incrementing counters involves masking out the old value and inserting the new incremented value, preserving the rest of the bits (options).Safety Checks:
debug_assert!ensures that options fit within 16 bits when creating a new state.
Interaction with Other Parts of the System
OptType:
TheSerializerStatedepends on theOpttype fromcrate::opt::Optas a bitfield or integer representing serialization options. This implies that other parts of the system define and manage serialization options and pass them here.Serialization Process:
TheSerializerStatewould be used internally by the serializer component to:Track recursion depth to avoid stack overflows or infinite loops.
Track the number of default serialization calls to avoid excessive fallback processing.
Pass updated state when recursive or default serialization calls are made.
Limits Enforcement:
By checking limits withrecursion_limit()anddefault_calls_limit(), the serializer can gracefully handle situations where recursion or default serialization calls become too deep or numerous.
Visual Diagram
classDiagram
class SerializerState {
-state: u32
+new(opts: Opt) SerializerState
+opts() u32
+recursion_limit() bool
+default_calls_limit() bool
+copy_for_recursive_call() SerializerState
+copy_for_default_call() SerializerState
}
Summary
`state.rs` defines a compact `SerializerState` struct to manage serialization options and recursion/default call counters efficiently using bit manipulation. It provides methods to create new states, check limits, and produce incremented states for recursive or default serialization calls, aiding in controlling serialization flow and preventing overflow or infinite loops in complex data structures. This file is a foundational utility in the serialization subsystem, interacting closely with option definitions and the serialization logic.