pub struct LayoutKey {Show 32 fields
pub encoding: Encoding,
pub endianness: Endianness,
pub purpose: Purpose,
pub length_codes: LengthCodePolicy,
pub collection_delimiters: CollectionDelimiterPolicy,
pub map_delimiter: MapDelimiter,
pub wstring_length: WstringLengthPolicy,
pub wchar_framing: WcharFraming,
pub wchar_width: WcharWidth,
pub wstring_unit_order: WstringUnitOrder,
pub pl_cdr1_headers: PlCdr1HeaderPolicy,
pub pid_flags: PidFlagPolicy,
pub pl_cdr1_reading: PlCdr1Reading,
pub must_understand: MustUnderstandPolicy,
pub enum_holder: EnumHolderWidth,
pub union_label: UnionLabelMatch,
pub map_entries: MapEntryOrder,
pub array_element_flattening: ArrayElementFlattening,
pub enumerator_value: EnumeratorValue,
pub union_framing: MutableUnionFraming,
pub short_pid_range: ShortPidRange,
pub fixed_digits: FixedDigitCount,
pub default_extensibility: Extensibility,
pub key_holder: KeyHolderExtensibility,
pub key_holder_nesting: KeyHolderNesting,
pub key_holder_order: KeyHolderOrder,
pub key_holder_alignment: KeyHolderAlignment,
pub defaulted_discriminator_member: DefaultedDiscriminatorMember,
pub element_padding: ElementPadding,
pub aggregate_delimiter: AggregateDelimiter,
pub sequence_element_delimiter: SequenceElementDelimiter,
pub wstring_code_units: WstringCodeUnits,
}Expand description
What a layout is computed for.
Member offsets are invariant under endianness — byte order changes the bytes, not where they sit — so the cache shares offset computation between the two and consults the endianness only where it genuinely matters: the big-endian key holder and per-primitive byte order. Spec §7.
Fields§
§encoding: EncodingWhich encoding.
endianness: EndiannessWhich byte order.
purpose: PurposeData or key holder.
length_codes: LengthCodePolicyHow variable-length mutable members are framed.
collection_delimiters: CollectionDelimiterPolicyWhich collections carry a delimiter under XCDR2.
map_delimiter: MapDelimiterWhich of a map’s two halves decides whether the map is
delimited.
wstring_length: WstringLengthPolicyHow a wstring’s length is counted.
wchar_framing: WcharFramingHow a scalar wchar is framed.
wchar_width: WcharWidthHow wide a scalar wchar is, which is not the width of a
wstring’s code units: rmw_cyclonedds_cpp writes two here and
four there.
wstring_unit_order: WstringUnitOrderIn what byte order a wstring’s code units go out.
pl_cdr1_headers: PlCdr1HeaderPolicyHow a @mutable member is framed under XCDR1.
pid_flags: PidFlagPolicyWhat flags a PL_CDR1 parameter id carries, per position.
pl_cdr1_reading: PlCdr1ReadingHow tolerant a PL_CDR1 reader is of another framing.
must_understand: MustUnderstandPolicyWhether a member’s must_understand reaches the wire.
enum_holder: EnumHolderWidthHow wide an enumeration’s holder is.
union_label: UnionLabelMatchWhether a negative case label of a narrow signed discriminator selects its branch.
map_entries: MapEntryOrderIn what order a map’s entries go on the wire.
array_element_flattening: ArrayElementFlatteningWhether an array’s element is flattened before the delimiter
question. See ArrayElementFlattening.
enumerator_value: EnumeratorValueWhich integer an enumerator serialises as.
union_framing: MutableUnionFramingHow a @mutable union numbers its branches, and whether its
XCDR1 parameter list is terminated.
short_pid_range: ShortPidRangeWhich member ids fit a PL_CDR1 short parameter header.
fixed_digits: FixedDigitCountWhether a fixed<P,S> carries its declared digit count or the
value’s.
default_extensibility: ExtensibilityWhat an aggregate whose source said nothing is taken to be.
key_holder: KeyHolderExtensibilityWhether a key holder keeps the type’s extensibility.
key_holder_nesting: KeyHolderNestingHow deep a key holder’s member removal reaches.
key_holder_order: KeyHolderOrderIn what order a key holder’s members are serialized.
key_holder_alignment: KeyHolderAlignmentWhether a key holder’s members are aligned.
defaulted_discriminator_member: DefaultedDiscriminatorMemberWhat becomes of a union’s member when @try_construct(use_default)
defaulted its discriminator.
element_padding: ElementPaddingWhether the elements of a collection carry alignment padding.
aggregate_delimiter: AggregateDelimiterWhether an aggregate’s declared extensibility reaches the wire.
sequence_element_delimiter: SequenceElementDelimiterWhether a sequence element of a non-@final type is preceded
by its own octet length.
wstring_code_units: WstringCodeUnitsWhich octets stand for a wstring’s characters.
Implementations§
Source§impl LayoutKey
impl LayoutKey
Sourcepub const fn pl_cdr1_framing(&self) -> PlCdr1FramingValues
pub const fn pl_cdr1_framing(&self) -> PlCdr1FramingValues
The PL_CDR1 framing this key’s writer and reader use.
The header form is in the plan, because it changes a member’s extent; these values do not, so they ride on the writer and the reader, and both take them from here.
Sourcepub const fn data(encoding: Encoding, endianness: Endianness) -> Self
pub const fn data(encoding: Encoding, endianness: Endianness) -> Self
A data plan in the given encoding and byte order, in the default dialect.
The dialect is Dialect::Specification, so every wire question
the implementations answer differently is answered the way
XTypes 1.3 answers it. LayoutKey::with_dialect selects
another; each with_* method below overrides one setting of
whichever dialect is in force, and overrides it whether or not a
dialect was named.
The variant is named rather than taken from Dialect::default
because this is a const fn and Default::default is not one.
zerodds_ast_layout::key::the_default_dialect_is_one_fact holds
the three spellings — #[default], Dialect::is_default and
this call — to one value, so a change to one of them that misses
the others fails rather than diverging quietly.
Sourcepub const fn in_dialect(
dialect: Dialect,
encoding: Encoding,
endianness: Endianness,
purpose: Purpose,
) -> Self
pub const fn in_dialect( dialect: Dialect, encoding: Encoding, endianness: Endianness, purpose: Purpose, ) -> Self
Every policy of one dialect, for one encoding, byte order and purpose.
The encoding is an argument because one setting depends on it:
RTI counts a wstring’s length differently under the two
versions.
Sourcepub const fn with_dialect(self, dialect: Dialect) -> Self
pub const fn with_dialect(self, dialect: Dialect) -> Self
The same plan with every setting taken from another dialect.
This resets every one of them: it is a preset and not a patch,
so applying it after a with_* call discards that call. The
command-line probes apply the dialect first for that reason.
Sourcepub const fn with_length_codes(self, policy: LengthCodePolicy) -> Self
pub const fn with_length_codes(self, policy: LengthCodePolicy) -> Self
The same plan with a different length-code policy.
Sourcepub const fn with_collection_delimiters(
self,
policy: CollectionDelimiterPolicy,
) -> Self
pub const fn with_collection_delimiters( self, policy: CollectionDelimiterPolicy, ) -> Self
The same plan with a different collection-delimiter policy.
Sourcepub const fn with_element_padding(self, padding: ElementPadding) -> Self
pub const fn with_element_padding(self, padding: ElementPadding) -> Self
The same plan with the elements of a collection packed against one another or aligned as §7.4.1 says.
Sourcepub const fn with_aggregate_delimiter(
self,
delimiter: AggregateDelimiter,
) -> Self
pub const fn with_aggregate_delimiter( self, delimiter: AggregateDelimiter, ) -> Self
The same plan with an aggregate’s declared extensibility reaching the wire or not.
Sourcepub const fn with_sequence_element_delimiter(
self,
delimiter: SequenceElementDelimiter,
) -> Self
pub const fn with_sequence_element_delimiter( self, delimiter: SequenceElementDelimiter, ) -> Self
The same plan with a per-element octet length in front of a
sequence element, or without one.
Sourcepub const fn with_wstring_code_units(self, units: WstringCodeUnits) -> Self
pub const fn with_wstring_code_units(self, units: WstringCodeUnits) -> Self
The same plan with a wstring’s characters in UTF-16 code units
or in UTF-8 octets.
Sourcepub const fn with_wstring_length(self, policy: WstringLengthPolicy) -> Self
pub const fn with_wstring_length(self, policy: WstringLengthPolicy) -> Self
The same plan with a different wstring length policy.
Sourcepub const fn with_wchar_framing(self, framing: WcharFraming) -> Self
pub const fn with_wchar_framing(self, framing: WcharFraming) -> Self
The same plan framing a scalar wchar another way.
Sourcepub const fn with_wchar_width(self, width: WcharWidth) -> Self
pub const fn with_wchar_width(self, width: WcharWidth) -> Self
The same plan at a different scalar wchar width.
Sourcepub const fn with_map_delimiter(self, policy: MapDelimiter) -> Self
pub const fn with_map_delimiter(self, policy: MapDelimiter) -> Self
The same plan asking a different half of a map whether the map
is delimited.
Sourcepub const fn with_wstring_unit_order(self, order: WstringUnitOrder) -> Self
pub const fn with_wstring_unit_order(self, order: WstringUnitOrder) -> Self
The same plan ordering a wstring’s code units another way.
Sourcepub const fn wstring_order_conflicts(self) -> bool
pub const fn wstring_order_conflicts(self) -> bool
Whether two settings of this plan both decide the byte order of a
wstring’s code units.
Always false now, and kept as a signature rather than deleted.
It answered the pair (WstringLengthPolicy::UnswappedUnits, non-Stream), which existed only because a byte order was living
in the length enumeration under a length’s name. Judgement 2 of
docs/wire-axes-followup.md moved it to
WstringUnitOrder::HostUnswapped, and one axis cannot conflict
with itself: the four orders are four points of one setting and
any of them can be combined with any cell of C1 × C2 × C3.
The method stays because a caller refusing an impossible pair is cheap and a caller that stops refusing a possible one is not. If a second setting ever claims the same byte order, this is where it is caught.
Sourcepub const fn with_pl_cdr1_headers(self, policy: PlCdr1HeaderPolicy) -> Self
pub const fn with_pl_cdr1_headers(self, policy: PlCdr1HeaderPolicy) -> Self
The same plan with a different PL_CDR1 header policy.
Sourcepub fn for_sample(
self,
ast: &Ast,
root: Id<TypeNode>,
) -> Result<Self, LayoutError>
pub fn for_sample( self, ast: &Ast, root: Id<TypeNode>, ) -> Result<Self, LayoutError>
The plan for a sample of root: a PL_CDR1 header policy that is
decided per sample
becomes PlCdr1HeaderPolicy::ExtendedForConstructed when the
sample’s type can exceed the short form’s length and
PlCdr1HeaderPolicy::ShortRoundedLength when it cannot. Any other
key is returned as it is.
A writer and a reader of a whole sample call this once, with the sample’s type, and frame every type nested in it with the key it returns: RTI decides the form for the sample, and a nested type that is small on its own is framed by its sample’s choice.
§Errors
crate::plan::LayoutError when the sample’s type cannot be sized: an
unresolved reference, an unevaluable bound, a nesting past the
planner’s bound.
Sourcepub const fn with_pl_cdr1_reading(self, reading: PlCdr1Reading) -> Self
pub const fn with_pl_cdr1_reading(self, reading: PlCdr1Reading) -> Self
The same plan with a reader that takes another framing’s PL_CDR1 streams, or does not.
Sourcepub const fn with_pid_flags(self, policy: PidFlagPolicy) -> Self
pub const fn with_pid_flags(self, policy: PidFlagPolicy) -> Self
The same plan putting different flags on a parameter id.
Sourcepub const fn with_must_understand(self, policy: MustUnderstandPolicy) -> Self
pub const fn with_must_understand(self, policy: MustUnderstandPolicy) -> Self
The same plan writing or omitting a member’s must-understand flag.
Sourcepub const fn with_enum_holder(self, policy: EnumHolderWidth) -> Self
pub const fn with_enum_holder(self, policy: EnumHolderWidth) -> Self
The same plan giving an enumeration a holder of another width.
Sourcepub const fn with_union_label(self, policy: UnionLabelMatch) -> Self
pub const fn with_union_label(self, policy: UnionLabelMatch) -> Self
The same plan matching a negative case label another way.
Sourcepub const fn with_array_element_flattening(
self,
policy: ArrayElementFlattening,
) -> Self
pub const fn with_array_element_flattening( self, policy: ArrayElementFlattening, ) -> Self
The same key with another array-element flattening.
Sourcepub const fn with_map_entries(self, policy: MapEntryOrder) -> Self
pub const fn with_map_entries(self, policy: MapEntryOrder) -> Self
The same plan ordering a map’s entries another way.
Sourcepub const fn with_enumerator_value(self, policy: EnumeratorValue) -> Self
pub const fn with_enumerator_value(self, policy: EnumeratorValue) -> Self
The same plan with a different enumerator-value policy.
Sourcepub const fn with_union_framing(self, policy: MutableUnionFraming) -> Self
pub const fn with_union_framing(self, policy: MutableUnionFraming) -> Self
The same plan with a different @mutable union framing.
Sourcepub const fn with_short_pid_range(self, policy: ShortPidRange) -> Self
pub const fn with_short_pid_range(self, policy: ShortPidRange) -> Self
The same plan with a different short-PID range.
Sourcepub const fn with_fixed_digits(self, policy: FixedDigitCount) -> Self
pub const fn with_fixed_digits(self, policy: FixedDigitCount) -> Self
The same plan counting a fixed’s digits another way.
Sourcepub const fn with_key_holder(self, policy: KeyHolderExtensibility) -> Self
pub const fn with_key_holder(self, policy: KeyHolderExtensibility) -> Self
The same plan with a different key-holder rule.
Sourcepub const fn with_key_holder_nesting(self, policy: KeyHolderNesting) -> Self
pub const fn with_key_holder_nesting(self, policy: KeyHolderNesting) -> Self
The same plan with a different key-holder nesting rule.
Sourcepub const fn with_key_holder_order(self, policy: KeyHolderOrder) -> Self
pub const fn with_key_holder_order(self, policy: KeyHolderOrder) -> Self
The same plan ordering a key holder’s members differently.
Sourcepub const fn with_key_holder_alignment(self, policy: KeyHolderAlignment) -> Self
pub const fn with_key_holder_alignment(self, policy: KeyHolderAlignment) -> Self
The same plan aligning a key holder’s members differently.
Sourcepub const fn with_defaulted_discriminator_member(
self,
policy: DefaultedDiscriminatorMember,
) -> Self
pub const fn with_defaulted_discriminator_member( self, policy: DefaultedDiscriminatorMember, ) -> Self
The same plan giving a union’s member another answer when
@try_construct(use_default) defaulted its discriminator.
Sourcepub const fn with_default_extensibility(
self,
extensibility: Extensibility,
) -> Self
pub const fn with_default_extensibility( self, extensibility: Extensibility, ) -> Self
The same plan reading an unannotated aggregate as something else.
XTypes 1.3 §7.3.1.2.1.8 sanctions the knob outright:
In the event that the representation of a given type does not indicate the type’s extensibility kind, the type shall be considered appendable. Implementations may provide a mechanism to override this default behavior; for example, IDL compilers may provide configuration options to allow users to specify whether types of unspecified extensibility are to be considered final, appendable, or mutable.
Sourcepub const fn key(encoding: Encoding) -> Self
pub const fn key(encoding: Encoding) -> Self
The key-holder plan, which is always big-endian. DDSI-RTPS 2.5 §9.6.3.8.
In Dialect::Specification, the default, for the reason
Self::data is: the dialect reaches the holder — whether an
unannotated keyed aggregate carries a DHEADER depends on what
unannotated means — and crate::keyhash::key_holder_plan_with
is the way to plan a holder under some other dialect.
Sourcepub const fn member_pid_carries_must_understand(self) -> bool
pub const fn member_pid_carries_must_understand(self) -> bool
Whether a member’s own parameter id carries its
must-understand bit — the M in a short PID’s 16-bit flags and
FLAG_2 in PID_EXTENDED’s eMemberHeader (§7.4.1.2.3).
Two policies cross here. MustUnderstandPolicy::writes_flag
says whether the member’s declaration reaches any flag at all.
PidFlagPolicy::ImplExtensionOnMembers — OpenDDS — sets
FLAG_IMPL_EXTENSION | FLAG_MUST_UNDERSTAND on every 16-bit
member id as fixed framing, and writes nothing
declaration-dependent anywhere in a PID: measured 2026-08-24 on
identifier-keyword-member-ids under XCDR1, where the @key
member’s eMemberHeader is 0x0FEDF2A2 — the bare hash, no
FLAG_2 — while the same member’s XCDR2 EMHEADER carries
M_FLAG (which is what put DeclaredAndKey in the OpenDDS
dialect). §7.4.1.2.3 as written wants the bit in the
eMemberHeader, so the specification dialect keeps it.
Sourcepub const fn offset_key(self) -> OffsetKey
pub const fn offset_key(self) -> OffsetKey
The part of the key that actually affects offsets.
Two keys sharing this share their offset computation, which is what lets one cache entry serve both byte orders.
Endianness is not in it: byte order changes the bytes, not
where they sit.
Everything else is. CollectionDelimiterPolicy was left out
until this cache served an RTI-dialect plan, with no delimiter,
to a Cyclone-dialect request that needed one: two keys that
differ in a four-byte header do not share an offset computation.
WstringLengthPolicy was left out for the reason that a
wstring plans as Extent::Unbounded under every variant, which
is true and was not the whole question: the policy also fixes the
width of a scalar wchar, and a four-byte one aligns to four and
moves every member behind it. WcharFraming is in for the
second half of the same reason — GIOP 1.2’s wchar is one octet
longer than its code unit and aligns to one, so a plan built
for it puts every following member somewhere a fixed-width plan
does not.
WstringUnitOrder is not in it, and that is a claim rather
than an omission: a wstring plans as Extent::Unbounded under
all three orders, and the byte-order mark makes it two octets
longer without making it any less unbounded. Nothing an order
changes reaches an offset.
EnumHolderWidth is in it, and it is the plainest case of
all: an @bit_bound(8) enumeration is one octet under one value
and four under the other, so it changes the type’s own extent, its
alignment and the offset of every member behind it. A cache that
left it out would hand a one-octet plan to a caller that asked for
the four-octet holder.
UnionLabelMatch is not in it, and that is a claim rather
than an omission. A union’s extent is the discriminator plus the
widest branch under both values: with no default: the
suppressed match writes less than the extent, which the extent
already bounds, and with one it writes the default branch,
which the extent already covers. Nothing it changes reaches an
offset —
crates/wire-probe/tests/union_label_match.rs::the_extent_is_the_same_under_both_values
is that claim as a test rather than as this sentence.
MapEntryOrder is not in it, and that is a claim rather
than an omission for the plainest reason of the three: a
permutation of a map’s entries writes the same entries, so the
count, the byte extent and every offset behind it are the same
under both values.
crates/wire-probe/tests/map_entry_order.rs::the_extent_is_the_same_under_both_values
is that claim as a test.
FixedDigitCount is in it, and it is the second plainest
case after EnumHolderWidth: a fixed<9,3> is five octets
under one value and as many as the value needs under the other,
so the type stops being fixed-size and every member behind it
moves. A cache that left it out would hand a five-octet plan to a
caller that asked for the value’s digits.
EnumeratorValue is not in it, and it is the sharpest
contrast with EnumHolderWidth beside it: the two axes reach
the same construct and only one of them reaches an offset. The
holder’s width is a length; which integer goes into it is a
value, and @value(200) and the ordinal 2 occupy the same
holder.
crates/wire-probe/tests/enumerator_value.rs::the_extent_is_the_same_under_both_values
is that claim as a test.