pub struct Python;Expand description
The Python backend.
Trait Implementations§
Source§impl CodecTarget for Python
impl CodecTarget for Python
Source§type Block = Vec<Statement>
type Block = Vec<Statement>
A suite, which in Python is a list of statements and nothing else: there is no brace to hold and the indent belongs to the renderer.
Source§fn scalar(kind: Scalar) -> Self::Type
fn scalar(kind: Scalar) -> Self::Type
One int for every integer width, because Python has one.
Not a simplification. A Python int is unbounded, so octet and
unsigned long long are held exactly by the same type and
neither loses a bit at the assignment. What that costs is that
the type no longer says the width — which is why
adapter::python::type_tag names a codec after the IDL kind and
why adapter/python.rs writes every member’s width into
typing.Annotated metadata rather than into the annotation.
A char and a wchar are a str of one, which is the only
character type Python has, and what runtime/python’s
write_char and write_wchar take.
Source§fn nothing() -> Self::Type
fn nothing() -> Self::Type
None, which is what a Python function that answers with nothing
is annotated with.
Source§fn handle(kind: Handle) -> Self::Type
fn handle(kind: Handle) -> Self::Type
The runtime’s handles, by their exported names.
Each is a dataclass or an Enum in runtime/python, and a
generated module imports it by name.
Source§fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr
fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr
A str of one character is what a char is here.
runtime/python’s write_char takes the character and refuses a
code point above U+00FF rather than truncating it — which is a
decision about the wire and is the runtime’s, not this file’s.
Source§fn constant(which: Constant) -> Self::Expr
fn constant(which: Constant) -> Self::Expr
The runtime’s policy values, in the spelling runtime/python
accepts.
Strings and integers, not an enumeration per axis. That is
the runtime’s shape and not this file’s preference:
Writer.write_wstring matches policy against
_WSTRING_POLICIES and Writer.write_wchar takes width as the
octet count. The spellings are WstringLengthPolicy::as_str and
its siblings in crates/ast-layout/src/key.rs, which is where
the measurement lives, and they are not the TypeScript
column’s: runtime/typescript writes octets-terminated-2 where
this one writes octets/terminated/2, and a value copied across
would be refused by name at the first sample.
crates/lang-rules/tests/python_names_its_runtime.rs reads both
files and compares them, because nothing between this match and
the interpreter looks at the string.
One arm per constant and no catch-all: a policy this column has not implemented has to be a compile error here rather than a value that looks plausible.
Source§fn unsigned_holder(_bits: u16) -> Self::Type
fn unsigned_holder(_bits: u16) -> Self::Type
int, at every bit bound.
The one place this column’s unbounded integer is simply the right
answer: a @bit_bound(64) set and a @bit_bound(3) set are
assembled in the same type and neither can overflow it. The other
columns pick the smallest holder that fits and one of them —
Java — has to go up a signedness to do it.
Source§fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type
The Python type of a value of id.
Not Self::type_name, which is the codec’s tag — p_long,
seq_long — and names a function, not a type.
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 type, which in this column is not a type.
§7.4.1.1.4 defines a map as a sequence of entries, and
adapter/python.rs writes that as list[tuple[K, V]] with no
entry class at all — “the one place this column declares less
than the Java one”. So there is no name to answer with, and the
walk needs one for exactly two things: the element argument of
Self::make_room and the type of Self::storage’s
zd_scratch. Both are answered here from the shape rather than
from a declaration, and this name is what says which shape it is.
A list and not a tuple, because the reader writes each half
into the slot separately — v[i][0] = … — and a tuple cannot be
written into at all. Self::make_room turns the run back into
tuples once both halves are there, so what a decoder answers with
is what from_json built and what the encoder reads.
Source§fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String
fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String
Nothing. adapter/python.rs nests an IDL module in a class and
every reference is written from the module root, which
Self::enumerator_constant and value_type_of do through
declared_path. A prefix would be a second, shorter answer to
the same question.
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 wide_int(value: i128) -> Self::Expr
fn wide_int(value: i128) -> Self::Expr
The number.
The trait’s default is C’s UINT64_C(..), which is a macro no
Python file declares, and the whole reason for a widened literal
is a language whose integer constants have a type. Python’s do
not: 18446744073709551615 is an int and so is
-9223372036854775808.
Source§fn wide_unsigned(value: u64) -> Self::Expr
fn wide_unsigned(value: u64) -> Self::Expr
As Self::wide_int, and the value rather than the
two’s-complement pattern: a Python int is unbounded, so a
negative enumerator is written as the negative number it is.
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.
The trait’s default is C’s 123u. 2u is not a Python
expression at all — it is a SyntaxError, “invalid decimal
literal” — and every array bound and every string bound the
decode walk writes goes through here.
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.
emit/decode.rs’s literal::<T>("false") carries a keyword in
an integer literal, because that variant is the tree’s raw-token
escape and false is what C, C++, C#, Java and TypeScript all
spell a false boolean with. Python spells it False, and a file
carrying zd_seen0 = false is a NameError at the first
@mutable member — or worse, a name something else in scope
bound. Twelve sites in the decode walk reach this.
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 module-level function.
strcmp is the one name the walk hands here that is not a
function this column generates, and it is C’s. See
strcmp_sign for what it becomes and why.
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
w.write_u32(x) — a method on the writer or the reader.
The runtime’s methods are named in the wire’s convention already,
which is snake_case, so unlike the Java, C# and TypeScript
backends there is nothing to convert: write_u32 is
write_u32. What there is to do is name the arguments of the
three operations whose Python signature is not in the walk’s
order — see Python::keywords_for.
Source§fn carries_hdds_axes() -> bool
fn carries_hdds_axes() -> bool
runtime/python carries the three HDDS axes:
begin_packed_element / finish_packed_element on the writer and
the reader, the DHEADER pair for a sequence element’s own length,
and write_wstring_utf8_octets / read_wstring_utf8_octets.
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 the generated module imports from the runtime.
Two of the three the walk asks for are module-level functions in
zerodds_wire — no_dheader, utf8_octets, utf16_units. The
third is not: pid_is_user_member(header) is
PidRead.is_user_member() here, a method on the header the
reader handed back, which is the same difference as C’s free
function against Java’s static and is decided here rather than in
the walk.
Source§fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr
len(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 selected case member.
adapter/python.rs declares a union as one dataclass with _d
and one typing.Optional field per case, so a case member is a
plain attribute. This is the Java shape and not the TypeScript
one, which needs the value narrowed to an arm before the property
exists at all.
Source§fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr
entry[0] and entry[1].
A map’s entry is a two-element sequence here and not a class
with named halves: adapter/python.rs writes
list[tuple[K, V]], and §7.4.1.1.4’s “sequence of entries” is
what the wire form is. The index and not a name because there is
no name to use.
Source§fn materialised(_value: Self::Expr) -> Option<Self::Expr>
fn materialised(_value: Self::Expr) -> Option<Self::Expr>
Nothing.
The guard this asks for is C’s: zdw_read_string_alloc answers
NULL where the reader’s arena is exhausted, and every use of
what it produced is tested against that. A Python str owns its
own storage and there is no such state, so the guard is not
written at all rather than written against a value that is always
there.
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. typing.Optional[T] is the value or None,
with no wrapper to unwrap the way C#’s Nullable<T> has.
Source§fn present(base: &str, field: &str) -> Self::Expr
fn present(base: &str, field: &str) -> Self::Expr
v.field is not None.
is not and not !=. != calls __eq__, which a generated
dataclass defines over its fields, so v.field != None is a
structural comparison against None rather than an identity
test — and for a dataclass whose __eq__ returns
NotImplemented against a non-dataclass, Python falls back to
identity and the two agree only by accident. PEP 8 says the same
thing: “Comparisons to singletons like None should always be done
with is or is not.”
Source§fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt>
Nothing on the way in, v.field = None on the way out.
Writing the member is what makes it present — the field’s
declared default is None and the reader starts from Table 9’s
sample — so the present case has no statement to add.
None in every case field: adapter/python.rs declares them
typing.Optional[...] = None, and the class promises that at most
one is live.
Source§fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
The default’s rows as lists, outermost first: v = list(v), then
v[zd_i0] = list(v[zd_i0]) inside a loop per further dimension.
adapter/python.rs declares an array member tuple[T, …] and
default_python.rs answers a tuple to match, which the reader
cannot assign an element into; Self::close_array turns every
row back once the elements are in.
Source§fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt>
Every row a tuple again, innermost first, so what the reader
answers with is the tuple[T, …] the member declares. A list in
its place compares unequal to the tuple a caller wrote —
(1, 2) == [1, 2] is False — and a sample read back from the
wire was not == to the one written (measured:
idl-conformance/python, combo::Telemetry.window).
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.
adapter/python.rs’s optional member is a typing.Optional[T]
field that already exists on the dataclass, so unlike C++’s
std::optional there is nothing to engage before there is
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 Python’s spelling.
&& and || are and and or, which are not the same
operators as & and |: the bitwise pair does not short-circuit
and returns an integer. The walk uses both — status_is_ok() && reader_position() < zd_end needs the short circuit, and a
bitmask’s undeclared-bit test needs the bitwise & — and mapping
them onto one would break whichever it was not.
= is left as it is and never reaches a rendered expression:
Self::perform is the only thing that receives one and turns
it into a statement.
Source§fn unary(op: &'static str, value: Self::Expr) -> Self::Expr
fn unary(op: &'static str, value: Self::Expr) -> Self::Expr
not a and ~a.
not carries its trailing space because notx is an identifier;
~ takes none. The tree records which, so the renderer does not
have to guess.
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.
Why there is no narrowing. A Python int holds every IDL
width exactly, so (long) x and static_cast<int32_t>(x) have no
counterpart: there is nothing the value could have lost. The
runtime range-checks what it writes — Writer._check — so a value
outside the type raises at the octet rather than being folded
silently, which is the opposite trade from a C cast and is the
one this column wants.
Three rewrites, all at a union’s discriminator. The walk
writes cast(value_type(discriminator), wide_int(label)) for
every case label, and the label arrives as an integer:
- a
charorwchardiscriminator holds astr, andv._d == 97isFalsefor every sample. The label is the code point and the member is the character, so the literal becomes one. - a
booleandiscriminator holds abool.v._d == 1happens to be true in Python —True == 1— butFalseis what the sample carries andTrue/Falseis what says so. signed charis not a Python type at all; seeSIGNED_CHARandstrcmp_sign.
An enumeration discriminator needs none of it: adapter/python.rs
declares an enum.IntEnum, whose members are ints, so the
label compares equal to the enumerator without either side moving.
Source§fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr
fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr
The value, unchanged.
Handoff abstracts C’s &v->x against v.x. Python passes
every object by reference and takes no address, so both forms are
the value.
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: T = value, or name = value where there is nothing to
initialise it with.
The annotation is written because it costs nothing and says the
width the Python type does not: a reader of the generated file
sees zd_n: int = r.read_u32() and knows what the local is for.
An uninitialised local is a binding with no value, which
Python does have — zd_h: EmHeaderRead declares the annotation
and binds nothing — and that is exactly what the walk means when
it declares zd_h and assigns it inside the loop.
Source§fn perform(value: Self::Expr) -> Self::Stmt
fn perform(value: Self::Expr) -> Self::Stmt
An expression evaluated for its effect — or, where the walk built an assignment, the assignment.
a = b is not an expression in Python and (a = b) is a
SyntaxError. The shared walk’s assign helper and its
increment both build T::binary("=", …) and hand it here, and
this is the only place either can arrive: nothing else in
emit/encode.rs or emit/decode.rs puts an = anywhere but
directly inside a T::perform. So the shape is recognised here
and nowhere else, and an = that escaped into a nested
expression would be a SyntaxError in the generated file naming
the line — which is louder than a walrus quietly standing in for
it.
Source§fn give_back(value: Option<Self::Expr>) -> Self::Stmt
fn give_back(value: Option<Self::Expr>) -> Self::Stmt
return v.
Every T::give_back the decode walk builds is give_back(None),
which is C’s shape: a void decoder that wrote through a
pointer. This column’s decoders answer with the sample — see
Self::routine and Self::read_call — so a bare return
would answer None and the caller would assign it. On a refusal
the partially filled v goes back, exactly as the TypeScript
column does, and the caller reads reader_status() to find out
what it is.
Source§fn drop_value(value: Self::Expr) -> Self::Stmt
fn drop_value(value: Self::Expr) -> Self::Stmt
The call, and nothing around it.
The trait’s default is (void) expr;, which is C’s way of saying
an ignored return was meant. Python has no such diagnostic and
(None) expr is not a statement at all, so the call stands
alone.
Source§fn mark_used(_name: &str) -> Vec<Self::Stmt>
fn mark_used(_name: &str) -> Vec<Self::Stmt>
Nothing.
-Wunused-parameter -Werror is what this exists for and Python
has no counterpart; zd_tc on a line of its own is a legal
statement that does nothing, which is worse than no statement.
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 = zd_dec_T(r, zd_tc).
The trait’s default hands the destination to the callee, which
is C’s shape: its decoder takes a T * and fills it. A Python
function has no out-parameter — rebinding a parameter rebinds the
local and nothing else — so this column’s decoders answer with
the value and the destination is assigned at the call site.
Source§fn read_forward(callee: &str) -> Self::Stmt
fn read_forward(callee: &str) -> Self::Stmt
v = 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.
Two shapes, and the difference is assigned_whole — which is the
difference between a slot that is storage and a slot that has
to be one before anything can be written into it.
A sequence (assigned_whole): v = [None] * zd_n, because
the element decoder assigns the slot outright. [None] * n and
not [[..]] * n: None is immutable and repeating it aliases
nothing, which is not true of the map’s shape below.
A map (not assigned_whole): each entry is written half at
a time — v[i][0] = …, v[i][1] = … — so each slot has to be a
distinct mutable pair. [[None, None]] * n would be one list
repeated n times and every entry would be the last one read;
the loop that appends is what makes them distinct. Once both
halves are there the run is turned back into tuples, so what the
decoder answers with is what adapter/python.rs declared —
list[tuple[K, V]] — and what from_json built.
Source§fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>
v = v[:count].
§7.3.1.2.1.12.3’s TRIM for a bounded collection, applied 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 slice and not del v[count:], which does the same thing to a
list and not to a tuple — and the walk reaches this for a
bounded sequence, whose Python holder adapter/python.rs is free
to change.
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.
The seam exists for std::vector<bool>, whose operator[]
answers a proxy. A Python list element is an ordinary
reference 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.
One caller: zd_scratch, the entry of an uncounted map, which
the reader fills a half at a time. There is only one type this is
ever asked for — see Self::map_entry_name — and it is a
two-slot list, so this answers with one rather than with a
constructor call to a class this column does not declare.
Source§fn routine(spec: Routine<Self>) -> Option<Self::Decl>
fn routine(spec: Routine<Self>) -> Option<Self::Decl>
def zd_enc_T(w, v) -> None: and def zd_dec_T(r, zd_tc) -> T:.
A forward declaration is answered with nothing: Python resolves a
global at the call and not at the def, so a recursive or
mutually recursive type needs no declaration ahead of its body.
That is what body: None asks for and None is the honest
answer — the caller emits nothing.
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>
A call to a generated defaulter and not a literal in place.
A literal cannot carry an aggregate, and one written at every
position a member can go missing would put the same answer in the
generated file as many times as the type is reached — where two
copies can differ. crate::default_python carries the whole
table and the argument.
§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_python::member_default: a @default this
column cannot spell as a Python expression is refused rather than
silently 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
a.b.Colour.RED, written from the module root.
The trait’s default answers the bare enumerator name, which is
right for a target that flattens its modules into a prefix and
wrong here: adapter/python.rs nests each IDL module in a class
and an enum.IntEnum inside it, and a generated codec sits at the
module root — where RED resolves to nothing, or to whatever
else happened to be bound.
Source§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 member(base: &str, field: &str) -> Self::Expr
fn member(base: &str, field: &str) -> Self::Expr
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 set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>
@optional member is present, or is not. Read moreSource§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 until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt
Source§fn initialized_reader(
spec: Routine<Self>,
initializer: Self::Stmt,
) -> Option<Self::Decl>
fn initialized_reader( spec: Routine<Self>, initializer: Self::Stmt, ) -> Option<Self::Decl>
Source§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 header_field(value: Self::Expr, field: &str) -> Self::Expr
fn header_field(value: Self::Expr, field: &str) -> Self::Expr
Source§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.