Skip to main content

MAX_VALUE_DEPTH

Constant MAX_VALUE_DEPTH 

Source
pub const MAX_VALUE_DEPTH: usize = 64;
Expand description

How many nested aggregates a single value may hold before either walk refuses it.

§What it is for

A recursive type is legal — IDL 4.2 §7.4.1.4.4.4.4 for a cycle through a collection, and the same property in the other form for a cycle through an @optional member — because every value of one carries its own terminator: a sequence of length zero, an absent member. The type is a graph and the value is a tree.

A value whose graph really does have a cycle — a.next = a — has no terminator anywhere in it, and XTypes 1.3 §7.3.1.2.1.4 says of exactly that case “if the graph of objects has cycles, it is not serializable”. Neither walk can see the cycle: a source::Source hands the encoder one member at a time and a byte stream hands the decoder one header at a time, and in both directions the shape is only ever known one step ahead. So the walks count, and a value past the count is refused by name — encode::ProbeError::ValueTooDeep — rather than truncated, looped on, or run into the stack. A silent prefix of an infinite stream is the failure class this project ranks above every other.

§Why this number

Both walks are recursive descent — one write_aggregate frame or one read_aggregate frame per level — so the real ceiling is the thread’s stack, and the limit has to sit below it with room to spare. Measured 2026-08-26 with the guard raised out of the way, in an unoptimized build on the 2 MiB stack the test harness gives a spawned thread, over the Node chain of matrix/cases/recursive-optional-external:

directiondeepest chain that completedoverflowed at
decode160between 160 and 176
encode208between 208 and 224

The decoder is the tighter of the two and the one that faces a hostile peer, so it sets the number: 64 leaves a factor of about 2.5 against the worst measured case, and more than that in a release build or on a main thread’s larger stack.

It is a bound on legitimate values too, and that is stated rather than hidden: a sample carrying a linked list of more than 64 nodes is refused by this walk. The deepest aggregate nesting in the interop corpus is four. Raising the number means raising the measurement above with it, or making the walks iterative.

It is deliberately not zerodds_ast_layout::plan::MAX_DEPTH, which bounds a descent through the type graph and answers a different question: the type of a thousand-node list is two levels deep.