pub struct Elixir;Expand description
The Elixir backend.
Trait Implementations§
Source§impl CodecTarget for Elixir
impl CodecTarget for Elixir
Source§fn scalar(kind: Scalar) -> Self::Type
fn scalar(kind: Scalar) -> Self::Type
One integer() for every integer width, because Elixir has one.
A char and a wchar are marked with their own tag: both are a
one-character binary at run time, and Self::cast needs to
tell a character place from a string one to rewrite a union
label into the right literal.
Source§fn handle(kind: Handle) -> Self::Type
fn handle(kind: Handle) -> Self::Type
The runtime’s handles are maps and need no declared type; the tag exists so a declaration without an initialiser can be told apart in a debugger of the generator, not of the generated code.
Source§fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr
fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr
A one-character binary is what a char is here; the runtime
takes it whole and refuses what the type cannot hold.
Source§fn constant(which: Constant) -> Self::Expr
fn constant(which: Constant) -> Self::Expr
The runtime’s policy values, as the atoms
runtime/elixir matches on.
Atoms rather than strings because that is what an Elixir function
head matches, and the quoted forms — :"character-count" — keep
the exact spellings of crates/ast-layout/src/key.rs, so the
measurement’s names survive into the generated file. One arm per
constant and no catch-all, for the reason every backend states.
Source§fn unsigned_holder(_bits: u16) -> Self::Type
fn unsigned_holder(_bits: u16) -> Self::Type
integer(), at every bit bound.
Source§fn map_entry_name(_ast: &Ast, _id: Id<TypeNode>) -> String
fn map_entry_name(_ast: &Ast, _id: Id<TypeNode>) -> String
A map’s entry is a two-element list and has no module; see the
module documentation.
Source§fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String
fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String
Nothing: an Elixir module name carries its whole scope and every reference is written from the root.
Source§fn wide_int(value: i128) -> Self::Expr
fn wide_int(value: i128) -> Self::Expr
The number: an Elixir integer is unbounded and needs no suffix.
Source§fn wide_unsigned(value: u64) -> Self::Expr
fn wide_unsigned(value: u64) -> Self::Expr
As Self::wide_int.
Source§fn wide_signed(value: i128) -> Self::Expr
fn wide_signed(value: i128) -> Self::Expr
Source§fn unsigned_int(value: i128) -> Self::Expr
fn unsigned_int(value: i128) -> Self::Expr
The number, with no suffix: 2u is not an Elixir token.
Source§fn literal(value: Literal) -> Self::Expr
fn literal(value: Literal) -> Self::Expr
A literal, with the two raw tokens the walk escapes through
Literal::Int rewritten — true and false are the same
spelling in Elixir, but the tree’s boolean is what says a
boolean was meant.
Source§fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr
fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr
A call to a generated function — or, for strcmp, the sign
expression Elixir’s own binary comparison gives.
Erlang compares binaries bytewise, which is strcmp’s
unsigned char order (C11 §7.24.4), so the sign is two
comparisons and a subtraction.
Source§fn 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, carried as a marked call until a statement seam places it. See the module documentation.
Source§fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr
fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr
A free function of the ZeroddsWire module; every one the walks
ask for is pure.
Source§fn carries_hdds_axes() -> bool
fn carries_hdds_axes() -> bool
runtime/elixir carries the three HDDS axes:
begin_packed_element / finish_packed_element on the writer and
reader_begin_packed_element / reader_finish_packed_element on the
reader, the DHEADER pair for a sequence element’s own length, and
write_wstring_utf8_octets / read_wstring_utf8_octets.
Source§fn member(base: &str, field: &str) -> Self::Expr
fn member(base: &str, field: &str) -> Self::Expr
A field name with dots is a path through the members that hold a base
(parent.x, XTypes 1.3 §7.5.1.4.1.3): one field step per segment, which is what
the place of an update decomposes into.
Source§fn inherited_path(depth: usize) -> Option<String>
fn inherited_path(depth: usize) -> Option<String>
The base is the first member parent (XTypes 1.3 §7.5.1.4.1.3).
Source§fn header_field(value: Self::Expr, field: &str) -> Self::Expr
fn header_field(value: Self::Expr, field: &str) -> Self::Expr
The runtime’s headers are plain maps, but two of their field
names are not Elixir’s to take: end is a reserved word and
does not parse after a dot, so the reader publishes the
sentinel flag as list_end.
Source§fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
length(v), or the bound where the materialiser fixed one.
Source§fn case_member(base: &str, field: &str) -> Self::Expr
fn case_member(base: &str, field: &str) -> Self::Expr
v.field — a union’s case member is a plain struct field, the
materialiser’s one-struct union shape.
Source§fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
ZeroddsWire.entry_half(entry, 0 | 1) on the way out would be
unassignable, so both halves are the index form and the write
side rebuilds through Access.at. See the module documentation.
Source§fn materialised(_value: Self::Expr) -> Option<Self::Expr>
fn materialised(_value: Self::Expr) -> Option<Self::Expr>
Nothing: an Elixir binary owns its storage and a read either produced one or raised.
Source§fn 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 member itself: absence is nil and the value needs no
unwrapping.
Source§fn present(base: &str, field: &str) -> Self::Expr
fn present(base: &str, field: &str) -> Self::Expr
v.field != nil.
!= and not !==: the compared value is nil and nothing else
compares equal to it, so the strict form would claim a
distinction that does not exist here.
Source§fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
v = ZeroddsWire.array_to_lists(v, depth): the tuple
default_elixir.rs answers for an array, as the nested lists
put_in(v, [Access.at(..)], ..) writes into — Access.at/1
refuses a tuple.
Source§fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
v = ZeroddsWire.array_to_tuples(v, depth): the rows back as
the {T, …} the materialiser declares the member as. A list in
its place is not == to the tuple a caller built (measured:
%A{w: [1, 2, 3]} == %A{w: {1, 2, 3}} was false for a decoded
long w[3]).
Source§fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
Nothing on the way in — writing the member is what makes it
present — and v = %{v | field: nil} on the way out.
Source§fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
v = %{v | field: nil} for every case: a union is a struct with
one nullable field per branch, and only the selected one holds a
value. The same statement as an absent
@optional member, Self::set_present with false.
Source§fn optional_destination(
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr)
fn optional_destination( base: &str, field: &str, ) -> (Vec<Self::Stmt>, Self::Expr)
The member, with nothing to do first: a struct field holding
nil is already somewhere to write.
Source§fn 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
The operators, in Elixir’s spelling.
and/or and not &&/||: the strict forms take booleans
only, and everything the walk tests is one — a truthiness
operator would quietly accept a nil where a boolean belongs.
The bitwise four are Bitwise’s operator forms, which the
generated module imports.
Source§fn unary(op: &'static str, value: Self::Expr) -> Self::Expr
fn unary(op: &'static str, value: Self::Expr) -> Self::Expr
not a; bitwise complement is Bitwise.bnot(a) because ~~~
is deprecated in the Elixir this column measures against.
Source§fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr
fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr
The identity on every integer, and a rewrite on three things that are not integers — the same three as the Python column, at a union’s discriminator.
Source§fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr
fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr
The value, unchanged: everything is handed by value and rebuilt by the caller.
Source§fn 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
name = value, or name = nil where the walk declared without
a value — the binding the renderer’s threading needs to exist
before the block that rebinds it.
Source§fn perform(value: Self::Expr) -> Self::Stmt
fn perform(value: Self::Expr) -> Self::Stmt
An expression evaluated for its effect — which in this column is always a rebinding: an assignment the walk built, a runtime call that threads its receiver, or a generated encoder call that threads the writer.
Source§fn give_back(value: Option<Self::Expr>) -> Self::Stmt
fn give_back(value: Option<Self::Expr>) -> Self::Stmt
throw({:zd_return, {v, r}}) — every give_back the decode
walk builds is the bare form, and a decoder here answers the
sample and the reader it consumed. A give_back that ever
arrives with a value answers that value in the sample’s place,
which is what the C shape means by it.
Source§fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
A loop whose condition is re-evaluated per pass, so a
state-changing call inside it has no lowering at all — the three
conditions the walks build are pure, and a fourth that is not
must stop at the generated file rather than run once: the hoist
is kept and a call to a name no module defines goes in front,
so elixirc refuses the file and names the fault, and the loop
can never run with a condition evaluated at the wrong time.
Source§fn drop_value(value: Self::Expr) -> Self::Stmt
fn drop_value(value: Self::Expr) -> Self::Stmt
A value read for its effect: the reader still moves, the value
is discarded by name. Exactly Self::perform’s job — a
runtime call performed for its effect binds {_, receiver},
anything else binds _ — and one implementation rather than a
second copy that could drift into leaving a temporary unread.
Source§fn mark_used(name: &str) -> Vec<Self::Stmt>
fn mark_used(name: &str) -> Vec<Self::Stmt>
_ = zd_tc — the one spelling Elixir gives “this parameter is
deliberately not read”, and warnings are failures in this
column’s compile gates.
Source§fn 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
{<place>, r} = zd_dec_T(r, behaviour) — a generated decoder
answers the value and the reader, and the destination is the
bind’s left-hand side.
Source§fn read_forward(callee: &str) -> Self::Stmt
fn read_forward(callee: &str) -> Self::Stmt
{v, r} = zd_dec_T(r, zd_tc) — a typedef, handed straight on.
Source§fn 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, and the fill inside it.
A sequence’s slots are assigned outright, so List.duplicate
over nil is enough; a map’s are written half at a time, so
each slot is a two-element list — and unlike the Python column
there is no aliasing to avoid, because an Elixir list is
immutable and put_in rebuilds the spine. The entries stay
lists; the filler builds lists and the dumper reads them.
Source§fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
v = Enum.take(v, count) — §7.3.1.2.1.12.3’s TRIM.
Source§fn 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>)
The subscript, with nothing before or after it: a list element is an ordinary value at every element type.
Source§fn storage(type_: Self::Type, name: &str) -> Self::Stmt
fn storage(type_: Self::Type, name: &str) -> Self::Stmt
A local the body writes into: the map scratch entry is a
two-slot list, everything else is an ordinary declaration.
Source§fn routine(spec: Routine<Self>) -> Option<Self::Decl>
fn routine(spec: Routine<Self>) -> Option<Self::Decl>
def zd_enc_T(w, v) do … w end and
def zd_dec_T(r, zd_tc) do v = zd_def_T() … {v, r} end.
A forward declaration is answered with nothing: an Elixir module resolves a local call at run time and a recursive type needs no declaration ahead of its body.
Source§fn 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>
place = zd_def_T() — Table 9, through the generated defaulter.
§Errors
Never; the signature matches the emitters around it.
Source§fn 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>
§Errors
As crate::default_elixir::member_default: a @default this
column cannot spell is refused rather than replaced by Table 9’s
zero.
Source§fn enumerator_constant(
ast: &Ast,
id: Id<TypeNode>,
enumerator: &str,
) -> Self::Expr
fn enumerator_constant( ast: &Ast, id: Id<TypeNode>, enumerator: &str, ) -> Self::Expr
Common.Mode.active() — the enumeration module’s constant
function, which answers the declared integer. The materialiser’s
own module path, so the two cannot part.
Source§type Decl = CodecFunction
type Decl = CodecFunction
Source§fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
id where a codec holds it. Read moreSource§fn type_name(ast: &Ast, id: Id<TypeNode>) -> String
fn type_name(ast: &Ast, id: Id<TypeNode>) -> String
id. Read moreSource§fn escape(name: &str) -> String
fn escape(name: &str) -> String
Source§fn whole(base: &str) -> Self::Expr
fn whole(base: &str) -> Self::Expr
Source§fn elements(base: &str) -> Self::Expr
fn elements(base: &str) -> Self::Expr
Source§fn 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 { .. }Source§fn 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
bound, exclusive. Read moreSource§fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr
fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr
left is less than right as boolean map keys —
false before true, the ascending-key order’s reading of the
one-octet wire value. Read moreSource§fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr
fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr
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. Read moreSource§fn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt>
fn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt>
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.Source§fn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt>
fn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt>
Self::bulk_octets_write: count octets into
base, which already holds room for them.Source§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 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.Source§fn 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
type_. Read moreSource§fn 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
Source§fn case_label(ast: &Ast, discriminator: Id<TypeNode>, value: i128) -> Self::Expr
fn case_label(ast: &Ast, discriminator: Id<TypeNode>, value: i128) -> Self::Expr
Source§fn 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
Source§fn 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)
CodecTarget::behind_indirection:
the same place, and what has to happen before a reader can write
through it. Read moreSource§fn 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
@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. Read moreSource§fn reference_present(base: &str, field: &str) -> Self::Expr
fn reference_present(base: &str, field: &str) -> Self::Expr
CodecTarget::holds_by_reference answers for
is present. Reached only where that answered true.Source§fn 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
Source§fn 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)
id is the member’s type.Source§fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt>
fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt>
Source§fn holds_a_cycle_externally() -> bool
fn holds_a_cycle_externally() -> bool
@external one — through the external_ seams
below, whether or not the member carries the annotation. Read moreSource§fn externals_are_pointers() -> bool
fn externals_are_pointers() -> bool
@external member behind a pointer
of its own, where the member’s value is not a pointer already. Read moreSource§fn optionals_are_pointers() -> bool
fn optionals_are_pointers() -> bool
@optional member behind a pointer
of its own, where the member’s value is not a pointer already. Read moreSource§fn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool
fn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool
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.Source§fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt>
fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt>
@external
member that is not @optional has no value at the time of the
write. Read moreSource§fn 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
@external member, as the member’s codec takes
it. Read moreSource§fn 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)
@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.Source§fn external_present(base: &str, field: &str) -> Self::Expr
fn external_present(base: &str, field: &str) -> Self::Expr
@optional @external member is present. Read moreSource§fn 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>
@optional @external member is present, or is not.
The counterpart of CodecTarget::set_present, split for the
reason CodecTarget::external_present gives.Source§fn 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
@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.Source§fn 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)
@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.