1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! Encode the stable IR wire model into `VIR0` bytes.
/// Encode a single [`crate::ir::Expr`] into its wire-format tag and payload.
///
/// # Role
///
/// This is the leaf encoder for the expression tree. It maps each
/// `Expr` variant to a discriminant byte followed by a
/// variant-specific payload (literals, variable names, operation
/// tags, or nested sub-expressions).
///
/// # Invariants
///
/// The output buffer is appended to only; no bytes are removed or
/// reordered. Recursive calls for nested expressions preserve this
/// invariant.
///
/// # Pre-conditions
///
/// The expression must use only enum variants that have a registered
/// stable wire tag. Variants added to `Expr` without an assigned
/// tag will fail encoding (audit L.1.27 / I4).
///
/// # Return semantics
///
/// * `Ok(())` – the expression was fully appended to `out`.
/// * `Err(String)` – an actionable diagnostic starting with `Fix:`
/// describing the unsupported variant or oversized payload.
///
/// # Failure modes
///
/// * **Unmapped variant** – `bin_op_tag`, `un_op_tag`, or
/// `atomic_op_tag` returns `Err` when the op has no wire tag.
/// * **String overflow** – `put_string` rejects names longer than
/// [`crate::serial::wire::MAX_STRING_LEN`].
/// * **Length overflow** – `put_len_u32` rejects argument counts
/// larger than `u32::MAX`.
pub use put_expr;
/// Encode a single [`crate::ir::Node`] into its wire-format tag and payload.
///
/// # Role
///
/// Encodes statement-level IR: bindings, assignments, stores,
/// control flow, barriers, and async operations. Every variant maps
/// to a discriminant byte followed by a payload whose shape mirrors
/// the in-memory `Node` layout.
///
/// # Invariants
///
/// The output buffer is appended to only. Control-flow nodes that
/// contain nested node lists or expressions delegate to
/// [`put_nodes()`] and [`put_expr()`], preserving the append-only
/// invariant.
///
/// # Pre-conditions
///
/// All expressions embedded in the node must satisfy the
/// pre-conditions of [`put_expr()`] (stable wire tags, bounded string
/// lengths).
///
/// # Return semantics
///
/// * `Ok(())` – the node was fully appended to `out`.
/// * `Err(String)` – an actionable diagnostic starting with `Fix:`.
///
/// # Failure modes
///
/// Same as [`put_expr()`] for expression sub-payloads, plus
/// [`put_nodes()`] failures for nested statement lists (e.g. node
/// count exceeds `u32::MAX`).
pub use put_node;
/// Encode a slice of [`crate::ir::Node`]s as a length-prefixed sequence.
///
/// # Role
///
/// This is the canonical encoder for statement lists: entry bodies,
/// `If`/`Loop`/`Block` children, and any other `[Node]` slice. The
/// wire format represents every list as a little-endian `u32` count
/// followed by that many encoded nodes.
///
/// # Invariants
///
/// The output buffer is appended to only. The length field written
/// equals `nodes.len()`; truncation or padding would corrupt the
/// decoder's bounds checks (I10).
///
/// # Pre-conditions
///
/// `nodes.len()` must fit in `u32`; otherwise the wire format cannot
/// represent the sequence.
///
/// # Return semantics
///
/// * `Ok(())` – count and all nodes were appended.
/// * `Err(String)` – an actionable diagnostic starting with `Fix:`.
///
/// # Failure modes
///
/// * **Length overflow** – `put_len_u32` rejects `nodes.len()` >
/// `u32::MAX` with a `Fix:` error advising the caller to split
/// the program.
/// * **Node encoding failure** – any error from [`put_node()`] is
/// propagated upward unchanged.
pub use put_nodes;
/// Serialize a complete [`crate::ir_inner::model::program::Program`] into the versioned `VIR0` wire envelope.
///
/// # Role
///
/// This is the entry-point encoder. It produces the exact byte
/// sequence that [`crate::ir_inner::model::program::Program::from_wire`] expects: magic,
/// version, entry-op id, buffer table, work-group size, and entry
/// body.
///
/// # Invariants
///
/// The output is a fresh `Vec<u8>`; the caller owns it. Capacity is
/// pre-allocated heuristically to avoid reallocations on typical
/// programs, but the vector grows naturally if the estimate is low.
///
/// # Pre-conditions
///
/// The program must use only enum variants that have stable wire
/// tags. A well-formed program should always encode successfully;
/// encoding failure signals either an unsupported variant
/// (audit L.1.27 / I4) or a field that exceeds wire-format bounds
/// (audit I10).
///
/// # Return semantics
///
/// * `Ok(Vec<u8>)` – a complete VIR0 blob starting with
/// [`crate::serial::wire::framing::MAGIC`] and
/// [`crate::serial::wire::framing::WIRE_FORMAT_VERSION`].
/// * `Err(String)` – an actionable diagnostic starting with `Fix:`.
///
/// # Failure modes
///
/// * **Buffer count overflow** – more than `u32::MAX` buffers.
/// * **String overflow** – buffer names or the entry op id longer
/// than [`crate::serial::wire::MAX_STRING_LEN`] are rejected.
/// * **Unmapped variant** – `access_tag`, `put_data_type`, or nested
/// `put_expr` / `put_node` calls fail when an enum variant has no
/// wire tag.
///
/// # Versioning
///
/// The version bytes are emitted immediately after the magic
/// (audit L.1.47). Any breaking schema change must bump
/// [`crate::serial::wire::framing::WIRE_FORMAT_VERSION`] so older
/// decoders reject the payload with a clear version-mismatch
/// message instead of arbitrary downstream parse errors.
pub use to_wire;
pub use to_wire_into;
pub use to_wire_with_buffer_order_into;
/// Zero-allocation error type for hot-path wire encoders.
pub use WireEncodeErr;
/// Expression tag-and-payload encoder.
///
/// Maps each [`crate::ir::Expr`] variant to a discriminant byte
/// followed by type-specific payload bytes. Keeps the tag
/// assignment table in one place so adding a new expression variant
/// requires a single file change.
///
/// See [`put_expr()`] for the public entry point.
pub
/// Node tag-and-payload encoder.
///
/// Maps each [`crate::ir::Node`] variant to a discriminant byte
/// followed by type-specific payload bytes. Control-flow variants
/// recursively encode their body lists via [`put_nodes()`].
///
/// See [`put_node()`] for the public entry point.
pub
/// Sequence-length encoder.
///
/// Prefixes a node slice with a little-endian `u32` count, then
/// encodes each node in order. This is the canonical way to
/// serialize statement lists (entry bodies, `If` branches, `Loop`
/// bodies, etc.).
///
/// See [`put_nodes()`] for the public entry point.
/// Top-level program encoder.
///
/// Emits the `VIR0` magic, schema version, entry-op id, buffer
/// table, work-group size, and entry body in the order defined by
/// the wire specification. Any schema change must bump
/// [`crate::serial::wire::framing::WIRE_FORMAT_VERSION`] (audit L.1.47).
///
/// See [`to_wire()`] for the public entry point.