pub struct Writer { /* private fields */ }Expand description
Accumulates the bytes of one sample.
Implementations§
Source§impl Writer
impl Writer
Sourcepub fn new(endianness: Endianness) -> Self
pub fn new(endianness: Endianness) -> Self
A writer in the given byte order.
Sourcepub fn recording_padding(self) -> Self
pub fn recording_padding(self) -> Self
The same writer, keeping a record of every span of alignment padding it emits.
The record is the answer §7.4.1’s alignment rules give for this
type under this key: Writer::align_to is the one place the
walk emits a byte that carries no value, so the spans it notes
are the fill positions of the plan and not an observation about
the octets that came out. Two byte-shifting rewrites happen
after the fact — Writer::promote_pid inserts eight octets
and shorten_emheader removes four — and both move the spans
above them, so the record stays in the finished stream’s
coordinates.
Off by default and allocating only when asked for.
Sourcepub fn padding_spans(&self) -> &[(usize, usize)]
pub fn padding_spans(&self) -> &[(usize, usize)]
The recorded padding spans as (offset, length), in the
finished stream’s coordinates and in ascending order.
Empty when Writer::recording_padding was not asked for,
which is indistinguishable from a stream with no padding. A
caller that needs to tell the two apart asks for the record.
Sourcepub const fn is_recording_padding(&self) -> bool
pub const fn is_recording_padding(&self) -> bool
Whether this writer is keeping the record.
Sourcepub const fn with_wchar_framing(self, framing: WcharFraming) -> Self
pub const fn with_wchar_framing(self, framing: WcharFraming) -> Self
The same writer framing a scalar Char16 another way.
A preset and not a patch, like every other with_* here: the
framing and the width are separate because CORBA makes them
separate — omniORB and TAO write the same framing over two
octets and four.
Sourcepub const fn wchar_framing(&self) -> WcharFraming
pub const fn wchar_framing(&self) -> WcharFraming
The Char16 framing in force.
Sourcepub const fn with_wstring_unit_order(self, order: WstringUnitOrder) -> Self
pub const fn with_wstring_unit_order(self, order: WstringUnitOrder) -> Self
The same writer ordering wide code units another way.
Sourcepub const fn wstring_unit_order(&self) -> WstringUnitOrder
pub const fn wstring_unit_order(&self) -> WstringUnitOrder
The wide code-unit order in force.
Sourcepub const fn with_wchar_width(self, width: WcharWidth) -> Self
pub const fn with_wchar_width(self, width: WcharWidth) -> Self
The same writer putting a Char16 on the wire at another width.
Set it from
zerodds_ast_layout::WstringLengthPolicy::character_width, which
is the same source the layout plan sized the member from. A
writer wider than its plan writes a member the plan did not
reserve room for and every offset after it is wrong.
Sourcepub const fn wchar_width(&self) -> WcharWidth
pub const fn wchar_width(&self) -> WcharWidth
The Char16 width in force.
Sourcepub const fn with_short_length_codes(self, shorten: bool) -> Self
pub const fn with_short_length_codes(self, shorten: bool) -> Self
The same writer shortening an LC4 header whose member turned out to be 1, 2, 4 or 8 bytes long.
Set it from
zerodds_ast_layout::LengthCodePolicy::short_code_where_it_fits.
The plan already picks a short code for every member whose type
fixes the size; this is the other half, for a sequence or a map
whose length is in the value. Fast DDS makes the same choice the
same way — its sequence<short> of two elements is eight bytes
and goes out as 02000030, where three elements would be ten and
go out as LC4.
Sourcepub const fn short_length_codes(&self) -> bool
pub const fn short_length_codes(&self) -> bool
Whether an LC4 header is shortened when its member fits a code.
Sourcepub const fn with_pl_cdr1_framing(self, framing: PlCdr1Framing) -> Self
pub const fn with_pl_cdr1_framing(self, framing: PlCdr1Framing) -> Self
The same writer framing a PL_CDR1 parameter list another way.
Sourcepub const fn pl_cdr1_framing(&self) -> PlCdr1Framing
pub const fn pl_cdr1_framing(&self) -> PlCdr1Framing
The framing in force.
Sourcepub const fn with_minimal_member_trailing_octet(self, on: bool) -> Self
pub const fn with_minimal_member_trailing_octet(self, on: bool) -> Self
The writer, set to append (or not) the RTI/CoreDX minimal-member
trailing octet. See Writer::minimal_member_trailing_octet.
Sourcepub const fn minimal_member_trailing_octet(&self) -> bool
pub const fn minimal_member_trailing_octet(&self) -> bool
Whether this writer appends the RTI/CoreDX minimal-member trailing
octet (XTypes 1.3 §7.3.4.5; docs/omg-xtypes-issues.md §C2).
Sourcepub fn with_max_align(endianness: Endianness, max_align: usize) -> Self
pub fn with_max_align(endianness: Endianness, max_align: usize) -> Self
A writer whose alignment is capped at max_align.
Four for XCDR2, eight for XCDR1 — take it from
zerodds_ast_layout::Encoding::max_alignment rather than
writing a number here.
Sourcepub fn appending(endianness: Endianness, max_align: usize, out: Vec<u8>) -> Self
pub fn appending(endianness: Endianness, max_align: usize, out: Vec<u8>) -> Self
A writer that appends to out, with its alignment cap at
max_align and alignment counted from where out ends.
For an encoder handed a buffer to fill: a writer of its own grows
from empty and its bytes are then copied over, and for a 1 kB sample
that was four reallocations and a copy per write (measured on the
Linux test host). Counting from out’s end makes the bytes the same
as a fresh writer’s whose bytes were appended to out.
Self::finish hands out back with the sample behind what it
held.
Sourcepub fn continuing(
endianness: Endianness,
max_align: usize,
prefix: Vec<u8>,
) -> Self
pub fn continuing( endianness: Endianness, max_align: usize, prefix: Vec<u8>, ) -> Self
A writer that continues a stream whose first octets are prefix:
it appends behind them and counts alignment from the start of
prefix, not from where prefix ends (which is what
Self::appending does).
For a value that is a member of a larger object whose earlier
members were written by someone else — DDS-RPC 1.0 §7.5.1.1.6 puts
the Call union behind a RequestHeader of variable length, and
under XCDR1 the union’s 8-octet members align to the sample, not to
the union. Self::finish hands back prefix with the value
behind it.
Sourcepub const fn endianness(&self) -> Endianness
pub const fn endianness(&self) -> Endianness
The byte order this writer was given.
The counterpart of crate::reader::Reader::endianness, for the
callers that have to put the order they are writing in into the
stream — a CDR encapsulation opens with a byte-order octet that
says which order its body is in.
Sourcepub fn big_endian() -> Self
pub fn big_endian() -> Self
A big-endian writer, which is what a KeyHash holder is.
Sourcepub fn little_endian() -> Self
pub fn little_endian() -> Self
A little-endian writer.
Sourcepub fn begin_packed_element(&mut self) -> usize
pub fn begin_packed_element(&mut self) -> usize
Begin a collection element whose alignment is counted from its own first octet, returning the origin it replaced.
XTypes 1.3 §7.4.1 counts a value’s alignment from the
encapsulation, so an element of an array or a sequence begins at
the next multiple of its alignment and the collection pads
between elements. zerodds_ast_layout::ElementPadding::Packed
is the measured departure: the element begins where the previous
one ended and its own members align from there. Resetting the
origin here is the whole of it; Self::finish_packed_element
puts the stream’s origin back so the collection’s tail aligns
from the encapsulation again.
Sourcepub fn finish_packed_element(&mut self, saved: usize)
pub fn finish_packed_element(&mut self, saved: usize)
Restore the stream origin a packed element displaced. The pair of
Self::begin_packed_element.
Sourcepub fn write_bool(&mut self, value: bool)
pub fn write_bool(&mut self, value: bool)
boolean, one byte, 0 or 1.
Sourcepub fn write_fixed(
&mut self,
text: &str,
digits: u8,
scale: u8,
policy: FixedDigits,
) -> Result<(), WireError>
pub fn write_fixed( &mut self, text: &str, digits: u8, scale: u8, policy: FixedDigits, ) -> Result<(), WireError>
fixed<digits, scale>, as BCD — CORBA 3.3 part 2 §9.3.2.8.
The value arrives as a decimal string and not as a number, because a
fixed<31, 2> is exactly what a f64 cannot carry: the type exists to
hold a decimal exactly, and a binary float on the way in would defeat
it before the first nibble.
Two nibbles to the byte, high first, sign last: 0xd negative, 0xc
otherwise, zero included. A negative zero goes out positive, because
there is one zero to write.
No DDS vendor generates code for fixed — Cyclone, Fast DDS and RTI
emit nothing for it and OpenDDS does not compile it, measured across
the corpus — so there is no vendor oracle here, only the clause and
the twenty other columns of this project that already write it.
§Errors
WireError when the declaration is outside IDL rule (42)’s 31
digits, when scale exceeds digits, or when the text is not a
decimal that fits fixed<digits, scale>. A value that does not fit is
refused rather than truncated: a silently shortened decimal is the
wrong number with no way to notice.
Sourcepub fn write_char(&mut self, value: char) -> Result<(), WireError>
pub fn write_char(&mut self, value: char) -> Result<(), WireError>
char, one byte. DDS-XTypes 1.3 §7.4.1.1.1, Table 31.
§7.2.2.2.1.2.2 gives the whole rule: “This specification does not
define an encoding for the CHAR_8_TYPE. The only constraint is
that it shall be representable using 8 bits.” A code point above
U+00FF is not, and no byte stands for it.
§Errors
WireError::OutOfRange above U+00FF. This used to be
value as u32 as u8, which drops the high bits and puts a
different character on the wire with nothing said.
Sourcepub fn write_wchar(
&mut self,
value: char,
position: WcharPosition,
) -> Result<(), WireError>
pub fn write_wchar( &mut self, value: char, position: WcharPosition, ) -> Result<(), WireError>
wchar: one UTF-16 code unit, at the width
Writer::wchar_width names. DDS-XTypes 1.3 §7.4.1.1.1,
Table 31 gives two bytes; WcharWidth carries the one measured
implementation that writes four and where it does so.
§7.2.2.2.1.2.5: “The CHAR_16_TYPE shall be restricted to
representing Unicode codepoints in the Basic Multilingual Plane.
That is Unicode codepoints from 0x0000 to U+FFFF.” A code point
above the BMP takes two UTF-16 code units and has no wchar.
That is a property of the type and not of the width, so the
four-byte form refuses it too: RTI zero-extends a code unit,
it does not carry a code point.
position says whether this wchar is a member or a collection
element. Under WcharFraming::GiopLengthPrefixedMemberOnly the
two take different octets, and there is no default: a caller that
could leave it out would take the member’s framing for an
element, which is the shape of the defect that put the argument
here. tao_idl writes 04 e4000000 for a wchar member of
primitive-wchar and a bare e4000000 for the first element of
array-1d-primitives.
§Errors
WireError::OutOfRange above U+FFFF, for the reason
Writer::write_char gives at its own width.
Sourcepub fn write_wchar_member(&mut self, value: char) -> Result<(), WireError>
pub fn write_wchar_member(&mut self, value: char) -> Result<(), WireError>
Writer::write_wchar at the member position.
The generated codecs call this and
Writer::write_wchar_element rather than passing a position
along: a collection combinator takes Fn(&mut Writer, &char),
and a two-argument method cannot be handed to one as a path
without a closure that would hide which position it chose.
§Errors
Sourcepub fn write_bitmask(
&mut self,
bit_bound: u16,
bits: u64,
) -> Result<(), WireError>
pub fn write_bitmask( &mut self, bit_bound: u16, bits: u64, ) -> Result<(), WireError>
A bitmask, in the holder Table 33 of XTypes 1.3 §7.4.1.1.3.2
gives for its @bit_bound.
The bound and not the language’s holder: @bit_bound(12) is a
uint16_t in C and a u16 here, and the two octets it writes
carry twelve bits that mean something and four that do not. The
argument arrives from zerodds_ast_layout::plan::scalar_write,
which is the same crossing every other column asks — the C
runtime’s zdw_write_bitmask takes the same pair in the same
order.
§Refused, not masked
A value with a bit set above the bound is refused rather than
truncated to the bound. Masking would put a value on the wire
nobody wrote and report success, and the peer would read a set
the sender never held. runtime/c/src/writer.c refuses the same
value with ZDW_RANGE.
§Errors
WireError::OutOfRange for a bound of zero or above 64, and
for a value that does not fit the bound.
Sourcepub fn write_bitset(
&mut self,
anchor_bytes: u32,
bits: u64,
) -> Result<(), WireError>
pub fn write_bitset( &mut self, anchor_bytes: u32, bits: u64, ) -> Result<(), WireError>
A bitset, as the anchor integer its bitfields pack into.
The anchor width is the layout plan’s answer and arrives as a
byte count, which is what zerodds_ast_layout::xcdr::plan gives
as the type’s extent and what zdw_write_bitset takes.
XTypes 1.3 has no serialisation rule for a bitset — §7.4.3.5.3 runs from (1) to (30) and none matches one. What is implemented is the only reading under which an IDL bitset round-trips through the TypeObject of §7.3.4.6: positions run cumulatively from zero in declaration order, anonymous padding included. The C runtime carries the same paragraph.
§Errors
WireError::OutOfRange for an anchor that is not one, two,
four or eight octets.
Sourcepub fn bitfield(
&mut self,
value: u64,
width: u32,
position: u32,
) -> Result<u64, WireError>
pub fn bitfield( &mut self, value: u64, width: u32, position: u32, ) -> Result<u64, WireError>
One bitfield’s contribution to its bitset’s anchor: the value shifted to its position.
A value wider than the field is refused rather than masked.
Masking would put a different value on the wire than the caller
held and report success — the generated field is as wide as its
holder and not as wide as its bitfield<N>, so bitfield<3> a
is a u8 that can hold 200 and a bitset that can not.
zdw_bitfield refuses the same value with ZDW_RANGE.
§Errors
WireError::OutOfRange for a width outside 1..=64, a field
that runs past the sixty-fourth bit, or a value the width cannot
hold.
Sourcepub fn write_u16_little(&mut self, value: u16)
pub fn write_u16_little(&mut self, value: u16)
A 16-bit value in little-endian order whatever the stream’s order is, aligned to two like any other.
One caller and one reason: Cyclone DDS swaps a wstring’s length
word for a big-endian stream and does not swap its code units.
zerodds_ast_layout::WstringLengthPolicy::UnswappedUnits carries
the measurement and the argument for reproducing it on request.
Nothing else on the wire has this shape, and a member that used
it without that reason would be a member no peer reads.
Sourcepub fn write_u16_big(&mut self, value: u16)
pub fn write_u16_big(&mut self, value: u16)
A 16-bit value in big-endian order whatever the stream’s order is, aligned to two like any other.
The counterpart of Writer::write_u16_little on the other
side of the same axis. Both omniORB and JacORB decode a
wstring’s code units as UTF-16 big-endian whatever the stream
says — the OMG code-set rule for a GIOP 1.2 wstring that
carries no byte-order mark — so this is the form a wstring
written for an ORB takes in a little-endian stream.
Sourcepub fn write_u32_little(&mut self, value: u32)
pub fn write_u32_little(&mut self, value: u32)
A 32-bit value in little-endian order whatever the stream’s order is.
A four-octet transmission code set crossed with a fixed unit
order: reachable as --wstring-length specification-wide-units --wstring-units byte-order-mark and by no dialect, because no
measured implementation writes wide units in a fixed order. It
exists so that two orthogonal settings have an answer for every
combination rather than a hole one of them falls into.
Sourcepub fn write_u32_big(&mut self, value: u32)
pub fn write_u32_big(&mut self, value: u32)
A 32-bit value in big-endian order whatever the stream’s
order is. The counterpart of Writer::write_u32_little.
Sourcepub fn write_f128(&mut self, value: Float128)
pub fn write_f128(&mut self, value: Float128)
long double: sixteen bytes of IEEE 754 binary128.
CORBA 3.3 part 2 §9.3.1.3 with Figure 9.2 gives the layout — one
sign bit, a fifteen-bit exponent, a 112-bit fraction — and shows
the two byte orders as the whole sixteen bytes reversed, not two
eight-byte halves swapped in place. DDS-XTypes 1.3 Table 31 gives
the alignment: eight, capped to four by MAXALIGN under XCDR2,
which is what Writer::align_to already does.
This used to take an f64 and write it followed by eight zero
bytes, because Rust has no stable f128. That was the right
length and the wrong value in every column and it reported
success; zerodds_float128::Float128 carries the value instead.
Nothing here computes with it — a wire runtime never needs to.
Sourcepub fn write_string(&mut self, value: &str)
pub fn write_string(&mut self, value: &str)
A string: a four-byte length including the terminator, the bytes, then a NUL. DDS-XTypes 1.3 §7.4.1.1.
The length counts the terminator, which is the one place XCDR differs from every other length-prefixed encoding.
Sourcepub fn write_string_bounded(
&mut self,
value: &str,
bound: usize,
) -> Result<(), WireError>
pub fn write_string_bounded( &mut self, value: &str, bound: usize, ) -> Result<(), WireError>
A bounded string.
The same bytes as an unbounded one: the bound is a promise about the source, not a difference on the wire. It is checked here rather than trusted, because a value that overruns its bound is one no peer expected.
The bound counts octets, which is what string<N> means to
every peer that has to hold the value — char[N + 1] in the C
mapping of all four DDS implementations, fixed_string<N> in
Fast DDS’s.
§Refused, not truncated
This truncated at a character boundary and reported nothing,
which is AL-14 of docs/wire-feature-inventory.md: acceptable
only while nothing called it. Something does now — the generated
codec emits write_string_bounded for every bounded string
member — and a writer that truncated would put a value on the
wire nobody wrote. §7.2.2.7’s TRIM is a read-side behaviour and
belongs to the receiver’s bound, not the sender’s;
wire-probe/src/encode.rs::write_string refuses the same values
(D6), so the two columns now agree.
§Errors
WireError::OutOfRange for a value longer than the bound.
Sourcepub fn write_wstring(
&mut self,
value: &str,
policy: WstringLengthPolicy,
order: WstringUnitOrder,
position: WirePosition,
) -> Result<(), WireError>
pub fn write_wstring( &mut self, value: &str, policy: WstringLengthPolicy, order: WstringUnitOrder, position: WirePosition, ) -> Result<(), WireError>
A wstring: a four-octet length, then UTF-16 code units, in the
cell policy and order name.
XTypes 1.3 §7.4.3.5.3 rule (4) writes O.ssize as a UInt32
and then the Char16 units, annotated “No NUL” against rule
(3)’s “includes NUL” for a narrow string. What O.ssize counts
is settled in §7.4.1.1.2: “The serialized length of an object of
type String<Char16> shall be the number of bytes in the CDR
buffer taken by the String<Char16> characters. This is twice the
number of characters in the string” — code units, not
characters, so a "𝄞" is a length of four and not of one or
two. The same clause forbids the two things a UTF-16 encoder
would otherwise emit: “The UTF-16 representation … shall not
include a Byte Order Mark (BOM). The representation shall also
not include any terminating NUL character(s).”
That is one cell of eight. WstringLengthPolicy carries the
other seven and the runs that measured five of them, and
WstringUnitOrder carries the fourth axis. Both arrive as
arguments, resolved from zerodds_ast_layout::LayoutKey, for the
reason MapDelimiter arrives as the choice between
Writer::write_map and Writer::write_delimited_map: a
default in the runtime would be a second place the wire format
lives, and the two places would disagree the first time either
moved.
position says whether this wstring is reached as a member or
as a collection element. The nine measured implementations
answer both alike, so it changes nothing today — and it is the
argument that keeps that a measurement rather than an
assumption, the way Writer::write_wchar’s position is the
argument that caught tao_idl writing two different framings.
§Errors
WireError::OutOfRange for a code point outside the Basic
Multilingual Plane under a character count over two-octet
units — the WstringLengthPolicy::CHARACTER_COUNT cell.
Fast CDR counts wcslen characters and then writes each
four-octet wchar_t as two octets, so U+1D11E leaves as
d11e, which is U+D11E, a Hangul syllable and a well-formed
code point. The peer reads a different character and has nothing
to object to, and the sender left no trace in the bytes.
Reproducing a vendor’s length convention is a policy;
reproducing a data loss no reader can see is not.
The refusal is on the pair (characters, two octets) and not on a
named form: it is the narrow unit that loses the high bits, so
WstringLengthPolicy::ROS_TYPE_SUPPORT — a character count
over four-octet units — carries the surrogate pair intact and
is not refused.
Sourcepub fn write_wstring_bounded(
&mut self,
value: &str,
bound: usize,
policy: WstringLengthPolicy,
order: WstringUnitOrder,
position: WirePosition,
) -> Result<(), WireError>
pub fn write_wstring_bounded( &mut self, value: &str, bound: usize, policy: WstringLengthPolicy, order: WstringUnitOrder, position: WirePosition, ) -> Result<(), WireError>
A bounded wstring.
The same octets as an unbounded one of the same length: the bound is a promise about the source, not a difference on the wire.
The bound counts UTF-16 code units, which is what
wstring<N> means to every peer that has to hold the value — an
N-unit buffer in all four DDS implementations’ mappings, and
what §7.4.1.1.2’s own count is in. Counting Unicode scalar
values instead would accept a five-character value of six code
units that no peer can hold; counting octets would make the same
declaration mean two different capacities under C3’s two widths.
The terminator WstringTerminator::Present adds is not
counted against the bound. wstring<5> names a capacity of five
characters and RTI’s XCDR1 form writes six units for five
characters; counting the terminator would refuse a value the
declaration admits.
§Errors
WireError::OutOfRange for a value longer than the bound,
refused and not truncated for the reason
Writer::write_string_bounded gives — §7.2.2.7’s TRIM is a
read-side behaviour and belongs to the receiver’s bound. And
whatever Writer::write_wstring refuses.
Sourcepub fn write_wstring_utf8(
&mut self,
value: &str,
policy: WstringLengthPolicy,
position: WirePosition,
) -> Result<(), WireError>
pub fn write_wstring_utf8( &mut self, value: &str, policy: WstringLengthPolicy, position: WirePosition, ) -> Result<(), WireError>
A wstring whose characters go out as their own UTF-8 octets.
The write side of WstringCodeUnits::Utf8, the measured departure
of one product’s generated serialiser: XTypes 1.3 Table 31 gives a
wstring’s code unit as Char16 and §7.4.1.1.2 makes the length
“twice the number of characters”, so the clause has no UTF-8 form
at all. The length is the UTF-8 octet count plus C2’s terminator
when the cell carries one: under this value C1 and C3 have nothing
to say, because there is no fixed-width code unit for a character
count to count and no width for an octet count to multiply by.
The order axis is not consulted: UTF-8 octets have no byte order of their own.
§Errors
WireError::OutOfRange for an octet count that does not fit the
UInt32 length field, refused rather than written wrapped — a
length that names a prefix of its own content is the silent class,
and the peer would read every following member from inside this
one.
Sourcepub fn write_wstring_utf8_bounded(
&mut self,
value: &str,
bound: usize,
policy: WstringLengthPolicy,
position: WirePosition,
) -> Result<(), WireError>
pub fn write_wstring_utf8_bounded( &mut self, value: &str, bound: usize, policy: WstringLengthPolicy, position: WirePosition, ) -> Result<(), WireError>
A bounded wstring whose characters go out as UTF-8 octets.
The same octets as the unbounded one of the same length; the bound
is a promise about the source and counts UTF-16 code units, as
Writer::write_wstring_bounded does, because that is what
wstring<N> means to a peer whatever the content’s encoding.
§Errors
WireError::OutOfRange for a value longer than the bound, and
whatever Writer::write_wstring_utf8 refuses.
Sourcepub fn write_dheader(&mut self) -> DHeader
pub fn write_dheader(&mut self) -> DHeader
A DHEADER: a four-byte length the members that follow occupy.
Written as a placeholder and patched when the members are done, because the length is not known until then.
Sourcepub fn finish_dheader(&mut self, header: DHeader)
pub fn finish_dheader(&mut self, header: DHeader)
Patch a DHEADER with the length of what followed it.
A DHEADER is a UInt32 and “O.ssize is constrained to being smaller
than 4 Giga Bytes” (XTypes 1.3 §7.4.3.4.1): an object past that has
no DHEADER. This form has no way to return the error, so it records
it: the placeholder stays unpatched, Self::deferred_error returns
the error and Self::finish_checked and Self::check_deferred
refuse the stream. A caller that can return an error uses
Self::try_finish_dheader and gets it at the call.
Sourcepub fn deferred_error(&self) -> Option<&WireError>
pub fn deferred_error(&self) -> Option<&WireError>
The first error an infallible framing call met, if one did.
Set by Self::finish_dheader for an object of 4 GiB or more.
Sourcepub fn check_deferred(&self) -> Result<(), WireError>
pub fn check_deferred(&self) -> Result<(), WireError>
Sourcepub fn finish_checked(self) -> Result<Vec<u8>, WireError>
pub fn finish_checked(self) -> Result<Vec<u8>, WireError>
The bytes, refused when an infallible framing call met an error.
§Errors
Self::deferred_error’s error.
Sourcepub fn try_finish_dheader(&mut self, header: DHeader) -> Result<(), WireError>
pub fn try_finish_dheader(&mut self, header: DHeader) -> Result<(), WireError>
Self::finish_dheader, refusing a length a UInt32 does not
hold.
§Errors
WireError::OutOfRange when the members that followed the
DHEADER occupy 4 GiB or more (XTypes 1.3 §7.4.3.4.1). The buffer is
left as it was, with the placeholder unpatched, for the caller to
discard.
Sourcepub fn write_emheader(
&mut self,
member_id: u32,
length_code: u8,
must_understand: bool,
) -> Result<EmHeader, WireError>
pub fn write_emheader( &mut self, member_id: u32, length_code: u8, must_understand: bool, ) -> Result<EmHeader, WireError>
An XCDR2 EMHEADER: the member id, its length code and the must-understand flag in one 32-bit word.
The length code is the layout plan’s decision and arrives here as a number; this crate does not choose one. XTypes 1.3 §7.4.3.4.2.
§Errors
WireError::OutOfRange for a member id above
E_MEMBER_ID_MASK. §7.2.2.4.4.4.4 runs the ids from 0 to
0x0FFFFFFF and §7.4.3.4.2 leaves them the low 28 bits of the word.
This used to be member_id & 0x0FFF_FFFF, which writes a
well-formed header for a member the caller did not name — the peer
reads the wrong member and nothing at either end says so.
Sourcepub fn finish_emheader(&mut self, header: EmHeader) -> Result<(), WireError>
pub fn finish_emheader(&mut self, header: EmHeader) -> Result<(), WireError>
Patch an EMHEADER’s NEXTINT with the length of what followed.
Under Writer::short_length_codes it may instead delete the
NEXTINT and put the length in the code, which is what Fast DDS
does for a member whose serialized size turns out to be 1, 2, 4
or 8 bytes. See Writer::with_short_length_codes.
§Errors
WireError::OutOfRange when the member written under a code of
0 to 3 is not the length that code declares. §7.4.3.4.2 makes the
code be the length there — 1, 2, 4 or 8 octets — so a value of
another size misdeclares it and the reader’s skip lands inside
data. Codes 4 to 7 carry a NEXTINT and declare nothing of their
own, so they cannot be wrong that way.
Sourcepub fn write_pid(
&mut self,
pid: u16,
role: ParameterRole,
must_understand: bool,
) -> Result<Pid, WireError>
pub fn write_pid( &mut self, pid: u16, role: ParameterRole, must_understand: bool, ) -> Result<Pid, WireError>
A PL_CDR1 parameter header, short form: [id:u16][length:u16].
role says what the length field will count when
Writer::finish_pid patches it; see ParameterRole.
must_understand is bit 14 of the id. §7.4.1.2.2: the flag
“shall be set if and only if the must_understand property of the
member is set to true”. A member declared @must_understand
whose header does not say so goes out looking skippable, and a
peer that does not know it skips it.
§Errors
WireError::OutOfRange for an id above
PlCdr1Framing::highest_short_id. §7.4.1.2.2 gives the short
form the ids 0 to that value inclusive and reserves what is above
it for the protocol’s own parameters — PID_EXTENDED is 0x3F01
itself — so such an id takes Writer::write_pid_extended or it
does not go out. The field was read only by the reader until this
check; the plan chooses the form and this is the floor under a
caller that did not.
Sourcepub fn write_pid_extended(
&mut self,
pid: u32,
role: ParameterRole,
must_understand: bool,
) -> Result<Pid, WireError>
pub fn write_pid_extended( &mut self, pid: u32, role: ParameterRole, must_understand: bool, ) -> Result<Pid, WireError>
A PL_CDR1 parameter header, extended form.
[PID_EXTENDED][8][id:u32][length:u32], required when the id
reaches the reserved range or the value is longer than 0xFFFF,
and used for every member under
zerodds_ast_layout::PlCdr1HeaderPolicy::AlwaysExtended.
XTypes 1.3 §7.4.1.2.
The marker carries the must-understand bit when the framing says
so — Cyclone DDS writes 0x7f01, and its reader would not be
misled by 0x3f01 either, but the bytes differ.
The member’s must-understand is a different bit in a
different word: FLAG_2 of the 32-bit eMemberHeader,
§7.4.1.2.1. Cyclone sets the marker’s bit on every parameter it
writes and FLAG_2 only on the members that declare it —
017f0800 01000040 against 017f0800 02000000 in the same
sample — so reading the member’s property off the marker would
make every Cyclone parameter must-understand.
§Errors
WireError::OutOfRange for a member id above
E_MEMBER_ID_MASK, for the reason
Writer::write_emheader gives: the eMemberHeader of
§7.4.1.2.1 has the same 28 bits, and masking aliases the parameter
onto another member.
Sourcepub fn finish_pid(&mut self, header: Pid)
pub fn finish_pid(&mut self, header: Pid)
Patch a parameter header with its value’s length.
The length field never counts the alignment padding inside the block: a parameter’s value is its own CDR-encapsulated block and counts alignment from its own start, XTypes 1.3 §7.4.1.2, which is why an eight-byte member at the head of one declares eight and not twelve. All three measured implementations agree on that.
Whether it counts the padding that follows the value is
PlCdr1Framing::pads_declared_length, asked per
ParameterRole: Cyclone and RTI round a @mutable member’s
declared length up to four and Fast DDS stops at the value, and
for an @optional member of a non-mutable type only RTI rounds.
An absent @optional member finishes here with nothing written
between the header and this call, which declares the length of
zero §7.4.1.2 asks for.
Sourcepub fn write_sentinel(&mut self)
pub fn write_sentinel(&mut self)
The PID_LIST_END sentinel a PL_CDR1 parameter list ends with.
A reader that stops at the last member it recognises instead of
at the sentinel misreads whatever follows.
The flags come from PlCdr1Framing::pid_flags asked at
WirePosition::Sentinel, which is the only thing that decides
them: PID_LIST_END is not a member and has no declaration of
its own to carry.
Sourcepub fn write_sequence<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
element: F,
) -> Result<(), WireError>
pub fn write_sequence<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], element: F, ) -> Result<(), WireError>
A sequence: a four-byte count, then each element.
The element function is fallible, and every element function is,
whether or not the element itself can refuse. Three of the four
element kinds a collection can hold can — a char outside
Latin-1 (§7.2.2.2.1.2.2), a wchar outside the BMP, and a
nested aggregate whose own encode reaches one — and a second
infallible overload beside this one would be a shape for the
generator to pick between, one construct at a time. Ok(…)
around an infallible write costs nothing and reads as what it
is.
§Errors
Whatever the element function returns.
Sourcepub fn write_array<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
element: F,
) -> Result<(), WireError>
pub fn write_array<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], element: F, ) -> Result<(), WireError>
An array: each element, with no count.
The element count is in the type, not on the wire. XTypes 1.3 §7.4.3.5.
§Errors
Sourcepub fn write_delimited_sequence<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
element: F,
) -> Result<(), WireError>
pub fn write_delimited_sequence<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], element: F, ) -> Result<(), WireError>
A sequence behind a delimiter.
XTypes 1.3 §7.4.3.5 rule (12): under XCDR2 a sequence whose
element type is not primitive carries a DHEADER ahead of the
length. Which sequences those are is
zerodds_ast_layout::collection_is_delimited, not a decision
taken here.
§Errors
As Writer::write_sequence. The delimiter is patched before
the error is returned only when there is no error: a refused
element leaves a partial buffer, which the caller discards.
Sourcepub fn write_delimited_array<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
element: F,
) -> Result<(), WireError>
pub fn write_delimited_array<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], element: F, ) -> Result<(), WireError>
An array behind a delimiter. Rule (9), the array counterpart.
§Errors
Sourcepub fn write_sequence_bounded<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
bound: usize,
element: F,
) -> Result<(), WireError>
pub fn write_sequence_bounded<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], bound: usize, element: F, ) -> Result<(), WireError>
A sequence<T, N>, whose count is checked against N.
The bytes are a plain sequence’s: Table 17’s
O2.length <= T1.length is a property of the value, and the
wire carries no bound to compare it with. Refused rather than
written short, for the reason Writer::write_string_bounded
gives — the receiver’s own sequence<T, N> has room for N, and
a sender that wrote more has written a value of a type nobody
declared.
§Errors
WireError::OutOfRange for more than bound elements, and
whatever the element function returns.
Sourcepub fn write_delimited_sequence_bounded<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>(
&mut self,
values: &[T],
bound: usize,
element: F,
) -> Result<(), WireError>
pub fn write_delimited_sequence_bounded<T, F: Fn(&mut Self, &T) -> Result<(), WireError>>( &mut self, values: &[T], bound: usize, element: F, ) -> Result<(), WireError>
Sourcepub fn write_map<M, K, V, FK, FV>(
&mut self,
entries: &M,
key: FK,
value: FV,
) -> Result<(), WireError>
pub fn write_map<M, K, V, FK, FV>( &mut self, entries: &M, key: FK, value: FV, ) -> Result<(), WireError>
A map: a four-byte entry count, then each entry’s key followed by its value.
§The count is entries and not halves
XTypes 1.3 §7.4.1.1.4 defines a map<K, V> by equivalence to a
sequence<Entry> whose element is the pair, so the O.length
that precedes it counts pairs. Two independent readings say the
same:
- the layout plan.
zerodds_ast_layout::xcdr’sTypeKind::Maparm gives the mapmax(key, value, 4)alignment and oneSEQUENCE_LENGTH_ALIGNMENTlength word, not one per half; - a recorded foreign measurement.
tests/interop-results/sources/vendor-corpus.tsv, casemap-key-stringunderfastdds, XCDR1 big-endian, is00000003followed by three(string, long)pairs and then theffffffffof the trailinglong tail. Three entries, six halves, and the word on the wire is3.
§The entries go out in the order the container holds them
This runtime takes a BTreeMap and walks it, so the order is
ascending by key — which is what
zerodds_ast_layout::MapEntryOrder::AscendingKey is defined as:
what a binding that holds a map in an ordered container writes.
The order is a property of the container the caller already
chose, not a second decision taken here.
Whether a delimited map also carries this count is the one
thing the specification says twice and differently — §7.4.1.1.4
against rule (15) of §7.4.3.5.3 — and it is the caller’s, through
which of these four functions it calls. Fast DDS writes both,
which is zerodds_wire_codec::value::MapLengthPolicy’s default
and what Writer::write_delimited_map does.
§Errors
Whatever either half’s function returns.
Sourcepub fn write_delimited_map<M, K, V, FK, FV>(
&mut self,
entries: &M,
key: FK,
value: FV,
) -> Result<(), WireError>
pub fn write_delimited_map<M, K, V, FK, FV>( &mut self, entries: &M, key: FK, value: FV, ) -> Result<(), WireError>
A map behind a delimiter.
XTypes 1.3 §7.4.3.5 rule (14) exempts a map from the DHEADER
only when both halves are primitive, and rule (15) delimits
every other map under XCDR2. Which maps those are is
zerodds_ast_layout’s TypeLayout::needs_dheader, read through
MapDelimiter, and not a decision taken here.
§Errors
Sourcepub fn write_map_bounded<M, K, V, FK, FV>(
&mut self,
entries: &M,
bound: usize,
key: FK,
value: FV,
) -> Result<(), WireError>
pub fn write_map_bounded<M, K, V, FK, FV>( &mut self, entries: &M, bound: usize, key: FK, value: FV, ) -> Result<(), WireError>
A map<K, V, N>, whose entry count is checked against N.
The bytes are a plain map’s, for the reason
Writer::write_sequence_bounded gives: the wire carries no
bound to compare with, so an over-long value is refused rather
than written short.
§Errors
WireError::OutOfRange for more than bound entries, and
whatever either half’s function returns.
Sourcepub fn write_delimited_map_bounded<M, K, V, FK, FV>(
&mut self,
entries: &M,
bound: usize,
key: FK,
value: FV,
) -> Result<(), WireError>
pub fn write_delimited_map_bounded<M, K, V, FK, FV>( &mut self, entries: &M, bound: usize, key: FK, value: FV, ) -> Result<(), WireError>
Sourcepub fn zero_padded(&self) -> [u8; 16]
pub fn zero_padded(&self) -> [u8; 16]
The holder as a KeyHash, zero-padded to sixteen bytes.
For a holder of sixteen bytes or fewer. DDSI-RTPS 2.5 §9.6.3.8.
Sourcepub fn write_bytes(&mut self, bytes: &[u8])
pub fn write_bytes(&mut self, bytes: &[u8])
bytes as they are, with no alignment and no length in front.
The counterpart of crate::reader::Reader::read_bytes, and the
one way an already-encoded byte string goes into a stream: a
CDR encapsulation built by a second writer, a GIOP request body
whose type only the calling stub knows, the octets of a
sequence<octet> behind their own length.