pub trait CodecTarget {
type Expr: Clone;
type Stmt: Clone;
type Block: Clone;
type Type: Clone;
type Decl;
Show 101 methods
// Required methods
fn scalar(kind: Scalar) -> Self::Type;
fn named(name: &str) -> Self::Type;
fn handle(kind: Handle) -> Self::Type;
fn constant(which: Constant) -> Self::Expr;
fn code_point(value: Self::Expr, narrow: bool) -> Self::Expr;
fn unsigned_holder(bits: u16) -> Self::Type;
fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr;
fn nothing() -> Self::Type;
fn name(text: &str) -> Self::Expr;
fn int(value: i128) -> Self::Expr;
fn literal(value: Literal) -> Self::Expr;
fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr;
fn runtime(
receiver: &str,
method: &str,
args: Vec<Self::Expr>,
) -> Self::Expr;
fn member(base: &str, field: &str) -> Self::Expr;
fn whole(base: &str) -> Self::Expr;
fn wide_int(value: i128) -> Self::Expr;
fn field_of(value: Self::Expr, field: &str) -> Self::Expr;
fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr;
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr;
fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr;
fn unary(op: &'static str, value: Self::Expr) -> Self::Expr;
fn paren(value: Self::Expr) -> Self::Expr;
fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr;
fn handoff(value: Self::Expr, form: Handoff) -> Self::Expr;
fn declare(
type_: Self::Type,
name: &str,
value: Option<Self::Expr>,
) -> Self::Stmt;
fn perform(value: Self::Expr) -> Self::Stmt;
fn give_back(value: Option<Self::Expr>) -> Self::Stmt;
fn when(
condition: Self::Expr,
then: Self::Block,
otherwise: Option<Self::Block>,
) -> Self::Stmt;
fn count_up(
counter: &str,
bound: Self::Expr,
body: Self::Block,
) -> Self::Stmt;
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt;
fn leave() -> Self::Stmt;
fn note(doc: Doc) -> Self::Stmt;
fn make_room(
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt>;
fn sequence_element(
base: &str,
index: Self::Expr,
element: Self::Type,
) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>);
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>;
fn present(base: &str, field: &str) -> Self::Expr;
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>;
fn case_member(base: &str, field: &str) -> Self::Expr;
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr;
fn optional_destination(
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr);
fn optional_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr;
fn elements(base: &str) -> Self::Expr;
fn materialised(value: Self::Expr) -> Option<Self::Expr>;
fn absent() -> Self::Expr;
fn block(statements: Vec<Self::Stmt>) -> Self::Block;
fn into_statements(block: Self::Block) -> Vec<Self::Stmt>;
fn routine(spec: Routine<Self>) -> Option<Self::Decl>;
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type;
fn default_into(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Result<Self::Stmt, EncodeError>;
fn member_default(
ast: &Ast,
node: &MemberNode,
type_: Id<TypeNode>,
place: Self::Expr,
) -> Result<Vec<Self::Stmt>, EncodeError>;
fn escape(name: &str) -> String;
fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String;
fn module_prefix(ast: &Ast, id: Id<TypeNode>) -> String;
fn type_name(ast: &Ast, id: Id<TypeNode>) -> String;
// Provided methods
fn unsigned_less(
octets: u8,
left: Self::Expr,
right: Self::Expr,
) -> Self::Expr { ... }
fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr { ... }
fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr { ... }
fn carries_hdds_axes() -> bool { ... }
fn unsigned_int(value: i128) -> Self::Expr { ... }
fn wide_unsigned(value: u64) -> Self::Expr { ... }
fn wide_signed(value: i128) -> Self::Expr { ... }
fn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt> { ... }
fn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt> { ... }
fn drop_value(value: Self::Expr) -> Self::Stmt { ... }
fn mark_used(name: &str) -> Vec<Self::Stmt> { ... }
fn read_call(
callee: &str,
place: Self::Expr,
form: Handoff,
behaviour: Self::Expr,
) -> Self::Stmt { ... }
fn read_forward(callee: &str) -> Self::Stmt { ... }
fn make_room_of(
_ast: &Ast,
_element_id: Id<TypeNode>,
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt> { ... }
fn store(
place: Self::Expr,
type_: Self::Type,
value: Self::Expr,
) -> Self::Stmt { ... }
fn storage(type_: Self::Type, name: &str) -> Self::Stmt { ... }
fn header_field(value: Self::Expr, field: &str) -> Self::Expr { ... }
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt> { ... }
fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt> { ... }
fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt> { ... }
fn discriminant(base: &str) -> Self::Expr { ... }
fn enumerator_ordinal(
ast: &Ast,
id: Id<TypeNode>,
value: Self::Expr,
) -> Self::Expr { ... }
fn case_label(
ast: &Ast,
discriminator: Id<TypeNode>,
value: i128,
) -> Self::Expr { ... }
fn behind_indirection(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Self::Expr { ... }
fn make_indirection(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> (Vec<Self::Stmt>, Self::Expr) { ... }
fn holds_by_reference(
ast: &Ast,
aggregate: Id<TypeNode>,
member_type: Id<TypeNode>,
optional: bool,
external: bool,
) -> bool { ... }
fn reference_present(base: &str, field: &str) -> Self::Expr { ... }
fn reference_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr { ... }
fn reference_destination(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr) { ... }
fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt> { ... }
fn holds_a_cycle_externally() -> bool { ... }
fn externals_are_pointers() -> bool { ... }
fn optionals_are_pointers() -> bool { ... }
fn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool { ... }
fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt> { ... }
fn external_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
optional: bool,
) -> Self::Expr { ... }
fn external_destination(
base: &str,
field: &str,
optional: bool,
) -> (Vec<Self::Stmt>, Self::Expr) { ... }
fn external_present(base: &str, field: &str) -> Self::Expr { ... }
fn external_set_present(
base: &str,
field: &str,
present: bool,
) -> Vec<Self::Stmt> { ... }
fn external_case_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr { ... }
fn external_case_destination(
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr) { ... }
fn published_name(name: String) -> String { ... }
fn initialized_reader(
_spec: Routine<Self>,
_initializer: Self::Stmt,
) -> Option<Self::Decl> { ... }
fn bitmask_value(
ast: &Ast,
id: Id<TypeNode>,
value: Self::Expr,
) -> Self::Expr { ... }
fn inherited_path(depth: usize) -> Option<String> { ... }
fn map_entry_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type { ... }
fn enumerator_constant(
ast: &Ast,
id: Id<TypeNode>,
enumerator: &str,
) -> Self::Expr { ... }
}Expand description
The syntax a codec walk builds.
Every method is a constructor: the trait holds no state and a backend is a unit type. What varies between backends is spelling, not order — a walk calls these in the sequence the layout plan dictates and the backend never reorders.
Required Associated Types§
Required Methods§
Sourcefn code_point(value: Self::Expr, narrow: bool) -> Self::Expr
fn code_point(value: Self::Expr, narrow: bool) -> Self::Expr
A character’s code point, as the runtime’s parameter wants it.
narrow is a char rather than a wchar: C truncates to an
octet and widens again, which is what its runtime is handed
today and what 17 220 recorded slots agree on. A target whose
character type is already a code unit hands it over and lets the
runtime keep the low byte — the same octet, decided one step
later.
A seam and not a cast, because the width is the backend’s:
Scalar::UInt32 is uint32_t in C and long in Java, and
writeChar takes an int.
Sourcefn unsigned_holder(bits: u16) -> Self::Type
fn unsigned_holder(bits: u16) -> Self::Type
The unsigned type wide enough to hold bits of a bit set.
A @bit_bound(12) set is assembled in something at least twelve
bits wide, and which type that is belongs to the target: C picks
the smallest uintN_t that fits, and a language with no unsigned
types picks the next signed one up and lets the runtime read the
bits. The walk asks for room, not for a spelling.
Sourcefn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr
fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr
An operation on the runtime that has no receiver.
no_dheader is the only one: the plan says a value takes no
delimiter and the walk still needs a handle to hand the close,
so the runtime supplies one that finishes nothing. C exports it
as a free function and Java as a static method on the writer,
which is the same difference as CodecTarget::runtime and not
the same call.
Sourcefn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr
fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr
A call to a free function or, in a target that has no free functions, to the static method standing in for one.
Sourcefn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr
fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr
An operation on the runtime’s writer or reader.
method is the operation’s bare name — write_u32, read_pid,
finish_dheader — and the backend spells it: C prefixes the
runtime’s single namespace and passes the receiver first,
zdw_write_u32(w, x); a target with methods writes
w.writeU32(x). Separate from CodecTarget::call because the
two differ in more than the name, and a walk that built the C
form and let a renderer guess at the other would be deciding a
language question in the walk.
receiver is the local the body holds the writer or reader in,
which is w and r in every backend so far.
Sourcefn member(base: &str, field: &str) -> Self::Expr
fn member(base: &str, field: &str) -> Self::Expr
A member of a value the codec was handed.
v->x where the parameter is a pointer, v.x where it is a
reference. Not CodecTarget::field_of, which reaches into a
value the body already owns.
Sourcefn whole(base: &str) -> Self::Expr
fn whole(base: &str) -> Self::Expr
The whole value the codec was handed, rather than one member.
*v where the parameter is a pointer, v where it is a
reference. What a primitive’s codec writes.
Sourcefn wide_int(value: i128) -> Self::Expr
fn wide_int(value: i128) -> Self::Expr
An integer literal that has to survive its own width.
A union label the size of 16045690984833335998 is not an int
in any of these languages, and a bare decimal is a constant whose
type the compiler picks — with a warning where the reader is
lucky and a quietly different comparison where they are not. C
writes UINT64_C(..), Java an L suffix. Separate from
CodecTarget::int because most literals are small and the
suffixed form would be noise on all of them.
Sourcefn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
How many elements the collection in base holds.
_length on the C sequence struct, .length on a Java array,
and for a fixed-size array the bound the materialiser fixed. The
base name and not an expression, for the reason
CodecTarget::elements takes one: how a target reaches into
its own collection is the target’s.
Sourcefn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr
fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr
a op b, written as given.
Sourcefn paren(value: Self::Expr) -> Self::Expr
fn paren(value: Self::Expr) -> Self::Expr
Parentheses written on purpose.
The trees carry no precedence, so a walk that needs a bracket says so and every backend honours it.
Sourcefn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr
fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr
A conversion the target requires and the walk knows is exact.
Sourcefn handoff(value: Self::Expr, form: Handoff) -> Self::Expr
fn handoff(value: Self::Expr, form: Handoff) -> Self::Expr
A value on its way into a nested codec.
The abstraction of &v->x against v.x; see Handoff.
Sourcefn declare(
type_: Self::Type,
name: &str,
value: Option<Self::Expr>,
) -> Self::Stmt
fn declare( type_: Self::Type, name: &str, value: Option<Self::Expr>, ) -> Self::Stmt
A local declaration with an optional initialiser.
Sourcefn when(
condition: Self::Expr,
then: Self::Block,
otherwise: Option<Self::Block>,
) -> Self::Stmt
fn when( condition: Self::Expr, then: Self::Block, otherwise: Option<Self::Block>, ) -> Self::Stmt
if (cond) { .. } else { .. }
Sourcefn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt
fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt
A counted loop from zero to bound, exclusive.
Given rather than assembled from the pieces because the counter’s
type is the target’s business: C declares size_t, Java int,
and a walk that wrote the declaration itself would be choosing
for both.
Sourcefn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
A loop with no counter.
A @mutable aggregate’s headers run until the delimiter is used
up and a PL_CDR1 list until its sentinel; neither has a bound,
and a counted loop with the clauses left empty would claim an
induction variable somebody forgot.
Sourcefn make_room(
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt>
fn make_room( base: &str, element: Self::Type, count: Self::Expr, assigned_whole: bool, fill: Vec<Self::Stmt>, ) -> Vec<Self::Stmt>
Room for count values of element, with fill inside it.
The one operation in the reader that is not a spelling. C sets
the length, nulls the buffer, allocates count * sizeof(element)
out of the reader’s arena, returns if that fails, and runs the
fill inside the guard — five statements. A target whose
allocation throws rather than returning nothing writes one and
has no guard to put the fill in.
base is the local the codec holds the sequence in, not a
finished expression: how a target reaches into it is the
target’s own — C’s sequence keeps a _length and a _buffer
behind a pointer, and a language with a list type has neither.
fill is the statements that fill it, already built; a backend
may drop the guard but must not drop the fill.
Shaped from the C column, which is the only caller so far. A
second reader backend is what will say whether the shape holds —
a target that appends rather than writing into a slot will want
the element’s place from here too, and it is better to widen this
when that caller exists than to guess at it now.
assigned_whole says what fill does with each slot: assign it
outright, as a sequence’s element decoder does, or write into it,
as a map’s two halves do. It is the difference between a
target whose slot is storage and one whose slot is a reference
that has to point at some — C ignores it and Java does not.
Sourcefn sequence_element(
base: &str,
index: Self::Expr,
element: Self::Type,
) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>)
fn sequence_element( base: &str, index: Self::Expr, element: Self::Type, ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>)
Where a sequence’s element goes while it is being read, and what it takes to get it there: the statements before, the place, and the statements after.
Almost always (nothing, base[index], nothing), and it is a seam
because of one container. std::vector<bool> is specialised —
[vector.bool] — and its operator[] returns a proxy object, not a
bool &. A codec that takes its destination by reference has
nowhere to point, so the C++ column reads into a local and assigns
it back. Every other element of every other target is a real
object and answers with the subscript.
Only a sequence needs it. T a[2] is a std::array, which is not
specialised for any element, and a map’s halves are a
std::pair’s members, which are real objects too.
The write direction has no such problem: reading a proxy is what
a proxy is for, and write_bool(v[i]) converts.
Sourcefn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
Keep the first count elements of the collection in base and
drop the rest.
§7.3.1.2.1.12.3’s TRIM for a bounded collection, which the reader applies after every element has been read: stopping at the bound would leave the rest of the sequence in the stream and put every following member at the wrong offset.
A statement and not an assignment to CodecTarget::count_of,
which is what this used to be. C’s sequence is a _length beside
a _buffer and the length is the answer — the elements past
the bound stay in the buffer, unreferenced. A std::vector knows
its own size and v.size() = 5u is not an assignment; a
List shortens differently again. The walk says how many to
keep and the target says how.
Sourcefn present(base: &str, field: &str) -> Self::Expr
fn present(base: &str, field: &str) -> Self::Expr
Whether an @optional member is present.
The last structural assumption C made and no other target
shares. C declares a boolean _has_m beside the member and this
reads it; adapter/java.rs declares one boxed field and lets
null mean absent, “because a boolean _has_m and an m are
two things that can disagree, and nothing in the type system
stops them”. A backend that inherited C’s flag would reach a
field the materialiser never emitted.
Sourcefn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
Say that an @optional member is present, or is not.
C assigns the parallel flag. A target where absence is the value
assigns nothing on the way in — writing the member is what makes
it present — and assigns CodecTarget::absent on the way out.
Returning no statement is a legitimate answer.
Sourcefn case_member(base: &str, field: &str) -> Self::Expr
fn case_member(base: &str, field: &str) -> Self::Expr
A union’s selected case member.
C declares the cases in an anonymous union _u inside the
struct, so a member is v->_u.x; adapter/java.rs declares one
field per case directly on the class, so it is v.x.
Sourcefn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
One half of a map’s entry.
C generates a struct with key and value; C++’s entry is a
std::pair, whose halves are first and second. The walk asks
for the half and the backend names it.
Sourcefn optional_destination(
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr)
fn optional_destination( base: &str, field: &str, ) -> (Vec<Self::Stmt>, Self::Expr)
Where a reader puts an @optional member’s value, and what it
takes to have somewhere to put it.
The write direction has CodecTarget::optional_value, which
reaches a value that is already there. Reading is the other way
round and the two targets differ in a way no expression covers:
C’s optional member is a plain T beside a _has_ flag, so the
destination is the member and nothing has to happen first; C++’s
is a std::optional<T> and the member’s decoder takes a T&, so
the optional has to be engaged before there is a T to write
into at all.
Returns the statements that make room, followed by the place. The statements go immediately before the read; a backend that needs none returns an empty vector, and the generated source is then exactly what it was before this seam existed.
Not folded into CodecTarget::set_present: that is called
after the read at two of the five sites and before it at the
other three, and moving it would reorder the C column’s output
for a difference that is not C’s.
Sourcefn optional_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr
fn optional_value( ast: &Ast, id: Id<TypeNode>, base: &str, field: &str, ) -> Self::Expr
The value an @optional member holds, given that it holds one.
C’s optional member is a plain T beside a _has_ flag, so this
is the member. C++’s is a std::optional<T> and the codec takes
a T, so it is .value(). Java’s boxed field is already the
value.
The member’s type is a parameter because one target’s answer
depends on it and no other’s does. adapter/csharp.rs wraps a
value type in Nullable<T> and leaves a reference type alone,
so the unwrapping is .Value for the first and nothing for the
second — and string?.Value does not compile any more than
passing an int? where an int is wanted does. A backend that
answered from the name alone would be right for one half of its
own mapping.
Only ever reached inside a branch the presence test guarded, so a target whose accessor throws on an absent value is safe here.
Sourcefn elements(base: &str) -> Self::Expr
fn elements(base: &str) -> Self::Expr
Where a sequence keeps the elements themselves.
C’s sequence is a _length and a _buffer and this is the
buffer; a target whose sequence is the array answers the value.
Sourcefn materialised(value: Self::Expr) -> Option<Self::Expr>
fn materialised(value: Self::Expr) -> Option<Self::Expr>
Whether a value the reader had to materialise is there at all.
C’s zdw_read_string_alloc answers NULL where the reader’s
heap is exhausted, and every use of what it produced is guarded
against that — a decoder that measured a null string would read
through the pointer. A target whose string type owns its own
storage has no such state and answers None, and the guard is
then not written at all rather than written against a value that
is always there: std::string != std::nullopt is not an
expression.
Distinct from CodecTarget::present, which asks about an
@optional member — a property of the sample. This asks whether
the read produced anything, which is a property of the runtime.
Sourcefn absent() -> Self::Expr
fn absent() -> Self::Expr
The value that says a target holds nothing.
NULL in C, null in Java and C#, None in Python. What a
decoder writes into a pointer before it has allocated, and what
it compares against to find out whether the allocation worked.
Sourcefn into_statements(block: Self::Block) -> Vec<Self::Stmt>
fn into_statements(block: Self::Block) -> Vec<Self::Stmt>
A body taken apart again.
A walk that has built a nested block and then finds it belongs
inline — an array’s innermost loop under a DHEADER, a union’s
if-chain after the last arm — would otherwise have to carry a
Vec and a Block in parallel and keep them agreeing.
Sourcefn routine(spec: Routine<Self>) -> Option<Self::Decl>
fn routine(spec: Routine<Self>) -> Option<Self::Decl>
A codec function or method.
body absent asks for a forward declaration, which C needs ahead
of the bodies so a recursive or mutually recursive type does not
depend on the order the walk visited its types in. A target that
has no such thing returns None and the caller emits nothing.
Routine::tolerate_unused marks a codec that may legitimately
have no caller. Generated code is compiled with an uncalled
function as an error, and that is worth keeping: normally it
means the generator emitted the wrong thing. The exception is a
codec reached from one position and written inline at another,
where having a caller is a property of the dialect rather than
of the type graph.
Sourcefn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
How this target spells the type of id where a codec holds it.
The materialiser’s answer, not the walk’s: a sequence<long> is
a struct with a buffer and a length in C, a std::vector in C++
and a List<Integer> in Java, and only the target knows which.
Sourcefn default_into(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Result<Self::Stmt, EncodeError>
fn default_into( ast: &Ast, id: Id<TypeNode>, place: Self::Expr, ) -> Result<Self::Stmt, EncodeError>
Table 9’s value for id, written into place.
What a reader puts where a member the stream did not carry belongs — DDS-XTypes 1.3 Table 9. The value is the specification’s and the same in every column; what differs is where a target keeps it. C calls a generated defaulter because a struct-valued default is not an expression it can assign; a target with literals for its aggregates assigns one.
§Errors
When the target has no form for Table 9’s value. Fallible because a backend under construction has to be able to refuse here: a reader generated with a hole in it and no error is a reader that fails where it runs rather than where it was built, and the two are a long way apart.
Sourcefn member_default(
ast: &Ast,
node: &MemberNode,
type_: Id<TypeNode>,
place: Self::Expr,
) -> Result<Vec<Self::Stmt>, EncodeError>
fn member_default( ast: &Ast, node: &MemberNode, type_: Id<TypeNode>, place: Self::Expr, ) -> Result<Vec<Self::Stmt>, EncodeError>
The declared @default of node, written into place, or
Table 9’s value where the member declares none.
Fallible on purpose: a @default a target cannot spell is
reported rather than quietly replaced by Table 9’s zero, which
is a different sample from the one the designer declared.
§Errors
When the declared default has no form in this target.
Sourcefn escape(name: &str) -> String
fn escape(name: &str) -> String
An IDL identifier as this target spells a member or a field.
Every language escapes the identifiers that collide with its own
keywords, and each escapes them differently — C prefixes, Java
prefixes with a different mark, C# writes @. Both halves of a
column have to agree: a member the materialiser declared escaped
and the codec reaches unescaped is a field no compiler finds.
Sourcefn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String
fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String
The name this target gives a map’s entry type.
A map<K, V> has no direct form in most targets and becomes a
collection of a generated pair; what that pair is called is the
materialiser’s, and the codec has to call it the same thing.
Sourcefn module_prefix(ast: &Ast, id: Id<TypeNode>) -> String
fn module_prefix(ast: &Ast, id: Id<TypeNode>) -> String
The prefix this target puts before a module’s declarations.
C has no namespaces and flattens module a { module b { … } }
into a prefix; a target with namespaces answers the empty
string and lets its own scoping do the work.
Sourcefn type_name(ast: &Ast, id: Id<TypeNode>) -> String
fn type_name(ast: &Ast, id: Id<TypeNode>) -> String
The name this target gives the type of id.
What a generated codec function is named after, and the reason a codec name is built from this rather than from the IDL: two IDL types that collapse to one name in a target must not end up with one codec, and a target that escapes a keyword has to escape it the same way in both halves.
Provided Methods§
Sourcefn unsigned_less(octets: u8, left: Self::Expr, right: Self::Expr) -> Self::Expr
fn unsigned_less(octets: u8, left: Self::Expr, right: Self::Expr) -> Self::Expr
Whether left is less than right as unsigned integers of
this width.
The default is the target’s own <, which is right wherever the
held type is unsigned or strictly wider than the value. Five
columns are not in that position at eight octets, and each
overrides: Java and Kotlin hold an IDL unsigned long long as
the bit pattern in a long and reach Long.compareUnsigned,
Lua reaches math.ult, OCaml’s Int64 reaches its runtime’s
u64_less, and Ada 83 — which has no modular type at all, only
Long_Integer — reaches Zd_Wire83.U64_Less. Every one of them
sorted 16045690984833335998 ahead of 7 in a map’s
ascending-key order before the override existed (measured
against Fast DDS on map-key-ulonglong; Ada 83 against Fast DDS
and OpenDDS, all four encodings, 2026-09-04). A target in that
position overrides.
The narrower widths need no override anywhere: an unsigned long tops out at 4294967295, which every column above holds
zero-extended in a signed type at least 64 bits wide, so the
signed order and the unsigned order are the same order.
Sourcefn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr
fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr
Whether left is less than right as boolean map keys —
false before true, the ascending-key order’s reading of the
one-octet wire value.
The default is the target’s own <, which C, C++, Rust and
Python all give two booleans. A language whose < refuses the
pair — Java, C# and TypeScript name a type error — overrides
with a spelling of the same order.
Sourcefn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr
fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr
The value’s storage bits, zero-extended into the runtime’s
64-bit pattern argument. See BitPatternSource; consumed by
the runtime’s write_union_overlay, which writes the low
octets of the pattern as one integer of that width in wire
endianness — the Cyclone union overlay.
The default spells each form as a free function of the runtime —
bit_pattern_int(value, octets), bit_pattern_bool,
bit_pattern_f32, bit_pattern_f64 — which fits every target
whose CodecTarget::runtime_static names free functions. A
target that routes runtime_static elsewhere, or that has a
native spelling for a form, overrides.
Sourcefn carries_hdds_axes() -> bool
fn carries_hdds_axes() -> bool
Whether this target’s runtime carries the three axes
zerodds_ast_layout::Dialect::Hdds selects.
The axes are zerodds_ast_layout::key::ElementPadding::Packed,
zerodds_ast_layout::key::SequenceElementDelimiter::BeforeEachNonFinalElement
and zerodds_ast_layout::key::WstringCodeUnits::Utf8. The
reference is zerodds-wire-codec; a target whose runtime has the
packed-element origin, the element length in DHEADER form and a
UTF-8 wstring answers true and may be generated under that
dialect. The default is false, so a runtime that has not been
given them is refused with the axis named rather than generated in
the specification’s form — a different octet string wearing this
key’s name.
Sourcefn unsigned_int(value: i128) -> Self::Expr
fn unsigned_int(value: i128) -> Self::Expr
A count, in whatever spelling keeps the target’s conversions quiet.
A sequence bound, an element count and a member id are all
unsigned on the wire, and C writes them with the u suffix so
that a comparison against a uint32_t does not trip
-Wsign-compare. Java has no unsigned literal and 5u is not a
token there at all. The walk asks for a count and each backend
spells it.
Sourcefn wide_unsigned(value: u64) -> Self::Expr
fn wide_unsigned(value: u64) -> Self::Expr
A 64-bit pattern, in a spelling wide enough to survive itself.
A bitmask’s declared-bit mask is sixty-four bits and a bare
decimal is a constant whose type the compiler picks. C writes
UINT64_C(..); Java has no unsigned integer and writes the
signed pattern with an L.
Sourcefn wide_signed(value: i128) -> Self::Expr
fn wide_signed(value: i128) -> Self::Expr
A signed 64-bit constant, as CodecTarget::wide_unsigned.
Sourcefn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt>
fn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt>
All of count octet elements of base at once, in place of the
element loop of a sequence<octet> or a one-dimensional
octet[N] (and the same over uint8); None, the default, keeps
the loop. The octets are the loop’s: an octet has alignment 1 and
no byte order (XTypes 1.3 §7.4.3.4.1), so a run of them is the same
bytes however it is copied. What a target gains is the per-element
call — measured in the C++ column: sequence<octet, 8192> element
by element cost ~100 µs per roundtrip of four codec passes.
Sourcefn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt>
fn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt>
The read side of Self::bulk_octets_write: count octets into
base, which already holds room for them.
Sourcefn drop_value(value: Self::Expr) -> Self::Stmt
fn drop_value(value: Self::Expr) -> Self::Stmt
A value read for its effect and not kept.
(void)zdw_read_dheader(r); in C, where an ignored return is a
-Wunused-result away from a warning and the cast is how a
caller says it meant it. A target where a call is already a
statement writes the call: (void) expr; is not a Java
statement at all.
Sourcefn mark_used(name: &str) -> Vec<Self::Stmt>
fn mark_used(name: &str) -> Vec<Self::Stmt>
How this target says a parameter is deliberately not read.
Most decoders have nothing to do with the try-construct
behaviour — a long has no bound to miss — and the C probe is
built with -Wunused-parameter -Werror, where that fails the
build. (void)zd_tc; is C’s way of saying so. A target whose
compiler does not warn on an unread parameter answers with no
statement, which is a legitimate answer and not an omission:
javac has no such warning, and zd_tc; is not a Java
statement at all.
Sourcefn read_call(
callee: &str,
place: Self::Expr,
form: Handoff,
behaviour: Self::Expr,
) -> Self::Stmt
fn read_call( callee: &str, place: Self::Expr, form: Handoff, behaviour: Self::Expr, ) -> Self::Stmt
zd_dec_<T>(r, <destination>, <behaviour>); — one nested
decoder run, with its answer put where place says.
The read direction’s counterpart of Handoff, and a whole
method rather than an argument form because the two targets do
not put the destination in the same syntactic position. C passes
its address and the callee writes through it. Java has no
address to pass and no out-parameter to pass it in, so the
decoder answers with the value and the destination is the
assignment’s left-hand side — the same decision, one step later.
A backend that overrides this is saying its decoders return
their value; CodecTarget::routine has to agree with it, and
so does CodecTarget::give_back.
Sourcefn read_forward(callee: &str) -> Self::Stmt
fn read_forward(callee: &str) -> Self::Stmt
The whole sample handed straight on to another type’s decoder.
What a typedef reads as: transparent on the wire, transparent
to §7.2.2.7, and in C transparent in storage too — the
destination and the behaviour go through untouched, and neither
an address nor a dereference is taken because v is already the
one the caller gave. Separate from CodecTarget::read_call
because there is no place here to take: the destination is the
parameter itself.
Sourcefn make_room_of(
_ast: &Ast,
_element_id: Id<TypeNode>,
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt>
fn make_room_of( _ast: &Ast, _element_id: Id<TypeNode>, base: &str, element: Self::Type, count: Self::Expr, assigned_whole: bool, fill: Vec<Self::Stmt>, ) -> Vec<Self::Stmt>
CodecTarget::make_room for a sequence whose element is
element_id. A target that cannot spell a slot’s start value from
element alone overrides it: Kotlin’s Array(n) { T() } has no
constructor to call where T is a typealias of Int.
Sourcefn store(place: Self::Expr, type_: Self::Type, value: Self::Expr) -> Self::Stmt
fn store(place: Self::Expr, type_: Self::Type, value: Self::Expr) -> Self::Stmt
One scalar, as it comes off the runtime, into a place of
type_.
C’s runtime hands back the member’s own width and the assignment
is the whole of it. Java has no unsigned type and no integer
narrower than int in an expression: readI8 answers an int
because that is what a number in [-128, 127] is once it has been
widened, and a byte field does not take one without being told
to. Which of its holders need that is the backend’s, and a walk
that cast unconditionally would put a redundant cast in the C
column, where -Wall names it.
Sourcefn storage(type_: Self::Type, name: &str) -> Self::Stmt
fn storage(type_: Self::Type, name: &str) -> Self::Stmt
A local the body writes into rather than assigns.
A C local of a struct type is storage the moment it is declared.
A Java local of a class type is a reference to none, and a body
that assigns its fields would be dereferencing a null. Separate
from CodecTarget::declare, which is for a local the body
assigns before it reads — those need no storage of their own and
a target that made some would be allocating for nothing.
Sourcefn header_field(value: Self::Expr, field: &str) -> Self::Expr
fn header_field(value: Self::Expr, field: &str) -> Self::Expr
One field of a header the runtime handed back.
zd_h.member_id in C. A target whose runtime publishes its
headers behind accessors answers with the call — zd_h.memberId()
— and the walk names the field rather than the spelling. Not
CodecTarget::field_of, which reaches into a value of a
generated type, where both columns write a field.
Sourcefn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
Statements that leave every case member of a union unset, before the member the discriminator selects is read.
The decoder starts from the union’s Table 9 default, which carries
the member the default discriminator selects. A column whose union
has a “not set” for a case field — Python’s and Julia’s None and
nothing, Swift’s nil, Nim’s and OCaml’s Option, a missing
key or property in Lua, Node and TypeScript, Elixir’s nil — and
promises that at most one case is live has to clear that member,
or a decoded sample carries the default branch’s value beside the
one read (measured: idl-conformance/_interop mapenum, a Sel
read with _d = 2 came back with n = 9 and z = 0). Nothing
by default: in C the cases share storage, and where a case field
has no “not set” (C++, C#, Java, Go, D, Zig, F#, Ada, Kotlin) its
default value is what an unselected field holds anyway.
Sourcefn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
Statements that make an array’s Table 9 default writable, before
its elements are read into it; lengths are its dimensions,
outermost first.
Nothing by default: every column but one holds an array in
something its elements can be assigned into. Python declares the
member tuple[T, …] (adapter/python.rs) and a tuple cannot be
written into, so its default is a tuple and the reader turns it
into lists here and back in CodecTarget::close_array.
Sourcefn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
Statements that give a read array the type its member declares,
after its last element is read. Nothing by default; see
CodecTarget::open_array.
Sourcefn discriminant(base: &str) -> Self::Expr
fn discriminant(base: &str) -> Self::Expr
A union’s discriminant.
_d in every column whose materialiser names it that, which is
all of them but one: DDS-TS 1.0 §7.5 names the property
discriminator, and the TypeScript materialiser declares it
under that name. The default is the name the other columns
share, so a column that does not override generates exactly what
it generated before this seam existed.
Sourcefn enumerator_ordinal(
ast: &Ast,
id: Id<TypeNode>,
value: Self::Expr,
) -> Self::Expr
fn enumerator_ordinal( ast: &Ast, id: Id<TypeNode>, value: Self::Expr, ) -> Self::Expr
The integer an enumeration’s value carries, given the value.
The identity in every column but one, and deliberately so: an
enumeration is a numeric constant at the language surface there,
so the value in the variable is the integer — under
zerodds_ast_layout::EnumeratorValue::Declared it is even the
integer that goes on the wire, which is why
encode::enumeration_write emits no chain for that setting.
DDS-TS 1.0 §7.6 makes an enumeration a string-literal union, so
that column has no integer in the variable at all and answers
with a lookup in the generated <Enum>Ordinal table. Measured:
without this seam enum-sparse-values wrote 70 79 87 — the
first code unit of each enumerator’s name — where the ledger has
65535 1 100.
Sourcefn case_label(ast: &Ast, discriminator: Id<TypeNode>, value: i128) -> Self::Expr
fn case_label(ast: &Ast, discriminator: Id<TypeNode>, value: i128) -> Self::Expr
The value a union case label is compared against, in this target’s spelling of the discriminator’s type.
The default is the label folded to an integer and narrowed to the discriminator’s own type, which is what every column with a numeric enumeration needs. A column whose enumeration is not numeric at the language surface — DDS-TS 1.0 §7.6 makes it a string-literal union — cannot compare a discriminant against a number at all, and answers with its own constant.
Sourcefn behind_indirection(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Self::Expr
fn behind_indirection( ast: &Ast, id: Id<TypeNode>, place: Self::Expr, ) -> Self::Expr
The place a member is reached at, given that the column could not put the member’s value inside its own aggregate.
zerodds_ast_layout::member_held_inline_closes_a_cycle is what
says so: the member’s type reaches the aggregate that declares it
over nothing but inline edges, so a column whose member is the
value has no size for it. place is the place the seams below
would have reached — the member, the @optional accessor, the
@external one, or a union branch — and the answer is that place
as the column keeps it once the indirection is there.
The default is the place unchanged, and it is the right answer
for fifteen of the seventeen columns: a member that is already a
reference — Python’s Optional[T], Rust’s Option<Box<T>>,
Java’s boxed field — has a size whatever it points at, so nothing
about it changes when it closes a cycle. C is the column that
asks: T next; beside a _has_next flag is storage that
contains itself, and the member has to become T *next.
Not folded into CodecTarget::optional_value: that seam is
handed the member’s type and not the aggregate that declares it,
and the cycle is a fact about the pair. The call sites hold both
and ask this only where the pair closes one, so a column that
takes the default emits exactly the source it emitted before this
seam existed.
Sourcefn make_indirection(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> (Vec<Self::Stmt>, Self::Expr)
fn make_indirection( ast: &Ast, id: Id<TypeNode>, place: Self::Expr, ) -> (Vec<Self::Stmt>, Self::Expr)
The reading counterpart of CodecTarget::behind_indirection:
the same place, and what has to happen before a reader can write
through it.
A column that keeps an indirection has nothing to write into
until the indirection points somewhere, so this is where the
storage is made. id is the member’s type, which is what an
allocation needs to know the size of.
Returns the statements that make room, followed by the place, in
the shape CodecTarget::optional_destination uses and for the
same reason.
Sourcefn holds_by_reference(
ast: &Ast,
aggregate: Id<TypeNode>,
member_type: Id<TypeNode>,
optional: bool,
external: bool,
) -> bool
fn holds_by_reference( ast: &Ast, aggregate: Id<TypeNode>, member_type: Id<TypeNode>, optional: bool, external: bool, ) -> bool
Whether this column holds an @optional or @external member of
aggregate, of type member_type, behind a reference of its own
— where the shared walk would reach it through
CodecTarget::present, CodecTarget::optional_value and
their external_ counterparts. A member this answers for goes
through CodecTarget::reference_present,
CodecTarget::reference_value,
CodecTarget::reference_destination and
CodecTarget::reference_absent instead.
false by default, which leaves every column’s output as it
was. Ada answers from its adapter
(crate::adapter::ada::held_by_reference): a member whose type is
still incomplete where the aggregate is declared is an access
type there (RM 3.10.1), which depends on the order Ada declares
in and on nothing the layout plans. The generated Ada for
recursive-optional-external asked such a member for Present
and did not compile (44 matrix cells, 2026-10-01).
Sourcefn reference_present(base: &str, field: &str) -> Self::Expr
fn reference_present(base: &str, field: &str) -> Self::Expr
Whether a member CodecTarget::holds_by_reference answers for
is present. Reached only where that answered true.
Sourcefn reference_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr
fn reference_value( ast: &Ast, id: Id<TypeNode>, base: &str, field: &str, ) -> Self::Expr
The value behind such a member, given that it is present.
Sourcefn reference_destination(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr)
fn reference_destination( ast: &Ast, id: Id<TypeNode>, base: &str, field: &str, ) -> (Vec<Self::Stmt>, Self::Expr)
Where a reader puts such a member’s value, and what it takes to
have somewhere to put it; id is the member’s type.
Sourcefn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt>
fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt>
The statements that leave such a member absent.
Sourcefn holds_a_cycle_externally() -> bool
fn holds_a_cycle_externally() -> bool
Whether this column keeps a member that closes a type cycle the
way it keeps an @external one — through the external_ seams
below, whether or not the member carries the annotation.
false by default, which leaves a column’s output as it was. The
columns that answer true are the ones whose @external member
is an indirection of their own (C++’s std::shared_ptr, D’s and
Zig’s pointer, Nim’s ref, Swift’s ZdExternal) and whose plain
member is the value, so a member on a cycle needs the same holder;
crate::adapter::held_externally is the rule, and their adapters
and defaulters ask it too. Ada decides by its declaration order
(CodecTarget::holds_by_reference) and C by the pointer it declares
(behind_pointer), so neither takes this.
Sourcefn externals_are_pointers() -> bool
fn externals_are_pointers() -> bool
Whether this column holds an @external member behind a pointer
of its own, where the member’s value is not a pointer already.
XTypes 1.3 §7.5.1.2.3.1 maps an external member of C to
“pointer-to-X”. The member is then reached through
CodecTarget::behind_indirection and a reader makes storage for
it with CodecTarget::make_indirection, the way both do for a
member that closes a cycle (behind_pointer asks both questions
at once). false by default; the columns that keep an @external
member behind a holder of their own go through the external_
seams instead.
Sourcefn optionals_are_pointers() -> bool
fn optionals_are_pointers() -> bool
Whether this column holds an @optional member behind a pointer
of its own, where the member’s value is not a pointer already.
XTypes 1.3 §7.5.1.2.4.1 maps an optional member of C to
“pointer-to-X” and says “A NULL pointer shall indicate an omitted
value”; §7.5.1.2.4.2 does the same for C++. The member is then
reached through CodecTarget::behind_indirection and a reader
makes storage for it with CodecTarget::make_indirection,
exactly as for an @external one; CodecTarget::present asks
whether the pointer is not NULL. false by default: every other
column holds an absent value in its own way.
Sourcefn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool
fn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool
Whether the column’s value of id is a pointer already, so that
an @external or @optional member of that type needs no pointer
of its own. C’s string, wstring and fixed are
const char * (XTypes 1.3 §7.5.1.2.3.1); a C++ std::string is
a value.
Sourcefn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt>
fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt>
Statements that stop a writer from going on when an @external
member that is not @optional has no value at the time of the
write.
XTypes 1.3 §7.5.1.2.3.1.1 (C) and §7.5.1.2.3.2.1 (C++): “If the
member is only external but not optional, then it is not allowed
for the member to be NULL at the time of a write.” present says
whether the member has a value. Nothing by default: a column that
holds an external member inline has no unset state to refuse.
Sourcefn external_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
optional: bool,
) -> Self::Expr
fn external_value( ast: &Ast, id: Id<TypeNode>, base: &str, field: &str, optional: bool, ) -> Self::Expr
The value of an @external member, as the member’s codec takes
it.
DDS-XTypes 1.3 Table 21: @external changes no octet — it says
where the binding keeps the value. Most columns keep it inline,
and the default is then exactly what the walk wrote before this
seam existed: the member, or the optional accessor where the
member is also @optional. A column that keeps it behind an
indirection — D’s T*, which is also what gives a
self-recursive type a size at all — answers with the
dereference, for both. A walk that reached the member directly
would hand a pointer to a codec that takes the value.
Sourcefn external_destination(
base: &str,
field: &str,
optional: bool,
) -> (Vec<Self::Stmt>, Self::Expr)
fn external_destination( base: &str, field: &str, optional: bool, ) -> (Vec<Self::Stmt>, Self::Expr)
Where a reader puts an @external member’s value, and what it
takes to have somewhere to put it. The reading counterpart of
CodecTarget::external_value, shaped like
CodecTarget::optional_destination and for the same reason: a
column whose member is an indirection has to make storage before
there is a value to write into. The default is the walk’s old
answer for both combinations.
Sourcefn external_present(base: &str, field: &str) -> Self::Expr
fn external_present(base: &str, field: &str) -> Self::Expr
Whether an @optional @external member is present.
Separate from CodecTarget::present because the two
annotations can answer differently in one column: D’s plain
@optional is Nullable!(T) and its isNull, while
@optional @external is one pointer and its null — a wrapper
over the pointer would carry a present-but-null state the wire
form has no encoding for.
Sourcefn external_set_present(
base: &str,
field: &str,
present: bool,
) -> Vec<Self::Stmt>
fn external_set_present( base: &str, field: &str, present: bool, ) -> Vec<Self::Stmt>
Say that an @optional @external member is present, or is not.
The counterpart of CodecTarget::set_present, split for the
reason CodecTarget::external_present gives.
Sourcefn external_case_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> Self::Expr
fn external_case_value( ast: &Ast, id: Id<TypeNode>, base: &str, field: &str, ) -> Self::Expr
The value of an @external union branch, as the branch’s codec
takes it. The union counterpart of
CodecTarget::external_value, reached through
CodecTarget::case_member because that is the accessor a
branch has; there is no optional parameter because no union
member is @optional (DDS-XTypes 1.3 §7.2.2.4.4.4.7). The
default is the accessor itself — the columns that keep the value
inline — and a column that keeps an indirection answers with the
dereference, exactly as it does for a structure member.
Sourcefn external_case_destination(
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr)
fn external_case_destination( base: &str, field: &str, ) -> (Vec<Self::Stmt>, Self::Expr)
Where a reader puts an @external union branch’s value, and
what it takes to have somewhere to put it. The union counterpart
of CodecTarget::external_destination, shaped the same way
and defaulted the same way.
Sourcefn published_name(name: String) -> String
fn published_name(name: String) -> String
One generated name, in the spelling this target publishes it under.
The identity everywhere but Go, and it exists because Go has no
visibility keyword: an identifier is exported if and only if its
first character is upper case (Go specification, “Exported
identifiers”), so a name is the only place a Go column can put
the decision. Applied inside
crate::emit::encode::codec_name and
crate::emit::decode::decoder_name, which is what makes it a
single decision: every caller of either — the walk’s own nested
calls, wireprobe-zerodds-go-gen’s entry point, a test naming a
function — gets the published spelling without asking.
A target that overrides this owes the transform an inverse in name only: it must be injective, or two codecs collide under one name and no compiler reports that as a collision.
Sourcefn initialized_reader(
_spec: Routine<Self>,
_initializer: Self::Stmt,
) -> Option<Self::Decl>
fn initialized_reader( _spec: Routine<Self>, _initializer: Self::Stmt, ) -> Option<Self::Decl>
A new reader entry with an explicit, target-derived initializer. Targets that cannot preserve this contract refuse the new entry only; existing data routines and their initialization remain unchanged.
Sourcefn bitmask_value(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr
fn bitmask_value(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr
The 64-bit pattern a bitmask arrives as, in the bitmask’s own declared type.
One cast to Self::value_type by default, which every target
with a real conversion operator answers with — (Flags)zd_bits
in C, (int) zd_bits in Java. TypeScript overrides it: its
declared bitmask type is an alias whose holder is a number up
to 32 bits, its as is erased and refuses bigint to number
outright (TS2352), so the narrowing has to be a runtime
conversion through the holder before the alias names it.
Sourcefn inherited_path(depth: usize) -> Option<String>
fn inherited_path(depth: usize) -> Option<String>
The path from a derived structure to the base members depth levels up,
for a column that binds inheritance as a first member parent
(XTypes 1.3 §7.5.1.4.1.3), ending in the separator: parent. for the
base, parent.parent. for its base. None, the default, is a column
that declares the base’s members in the derived structure.
Sourcefn map_entry_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
fn map_entry_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
The type a map’s entry is declared with — the reader’s
scratch entry and make_room’s element.
The default names CodecTarget::map_entry_name, which is
right wherever the materialiser declares a type of that name. It
is not right in C++, whose materialiser spells the entry as
std::pair<K, V> and declares nothing under the tag —
map_string_long zd_scratch; was a name no compiler finds (20
zerodds-cpp read cells across the map family).
Sourcefn enumerator_constant(
ast: &Ast,
id: Id<TypeNode>,
enumerator: &str,
) -> Self::Expr
fn enumerator_constant( ast: &Ast, id: Id<TypeNode>, enumerator: &str, ) -> Self::Expr
The constant one enumerator of id is named by.
The materialiser’s spelling. C flattens the modules into a
prefix and writes a bare identifier; Java declares a class of
public static final int and every use is written from the
outer class down — ZdTypes.common.Colour.BLUE. A walk that
built the name from CodecTarget::module_prefix alone would
emit an unqualified BLUE, which in Java names nothing.
The default is C’s and not the general answer: it is
CodecTarget::module_prefix and CodecTarget::escape put
together, which works wherever an enumerator sits in the
enclosing scope. C++ declares a scoped enumeration, so the
same enumerator is ::a::b::Colour::red and carries the type’s
own name in the middle, which no prefix supplies; that column
overrides.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".