lib/machine/src/fabric/transition/decode.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const admission = @import("../../admission/root.zig");
2 const fabric = @import("../root.zig");
3 const fault = @import("../../fault/root.zig");
4 const instance = @import("../../instance/root.zig");
5 const os = @import("os");
6 const schema = @import("schema.zig");
7 const std = @import("std");
8 const transition_types = @import("types.zig");
9
10 const wire = os.abi.wire;
11
12 pub const Decoded = struct {
13 value: fabric.Transition,
14 owner: fabric.Fabric,
15 };
16
17 pub fn transition(
18 input: *const [schema.stream_bytes]u8,
19 before: *const fabric.Fabric,
20 expected_root: fabric.Root,
21 ) transition_types.Error!Decoded {
22 try validateEnvelope(input);
23 const kind = input[schema.Header.kind_offset];
24 try validateReserved(input, kind);
25 const previous = try decodeRoot(input, schema.Header.previous_offset);
26 if (!std.meta.eql(previous, before.root())) return error.PreviousRootMismatch;
27 const result = try decodeRoot(input, schema.Header.result_offset);
28 if (!std.meta.eql(result, expected_root)) return error.ResultRootMismatch;
29 const entry: fabric.Entry = .{
30 .sequence = get64(input, schema.Header.sequence_offset),
31 .previous = previous,
32 .value = switch (kind) {
33 1 => .{ .admission = try decodeAdmission(input, before) },
34 2 => .{ .settlement = try decodeSettlement(input) },
35 3 => .{ .fault = try decodeFaultEntry(input) },
36 else => return error.UnknownTransitionField,
37 },
38 };
39 var candidate = before.*;
40 const actual = try candidate.replay(entry);
41 if (!std.meta.eql(actual, expected_root)) return error.ResultRootMismatch;
42 std.debug.assert(std.meta.eql(candidate.root(), expected_root));
43 return .{
44 .value = .{ .entry = entry, .root = actual },
45 .owner = candidate,
46 };
47 }
48
49 pub fn validateEnvelope(
50 input: *const [schema.stream_bytes]u8,
51 ) transition_types.Error!void {
52 const layout = schema.Envelope;
53 if (!std.mem.eql(
54 u8,
55 input[layout.magic_offset..layout.version_offset],
56 &schema.magic,
57 )) return error.BadMagic;
58 if (get16(input, layout.version_offset) != schema.version) {
59 return error.UnsupportedVersion;
60 }
61 if (get16(input, layout.stream_bytes_offset) != schema.stream_bytes) {
62 return error.StreamBytesMismatch;
63 }
64 if (get16(input, layout.flags_offset) != schema.flags) {
65 return error.UnsupportedFlags;
66 }
67 if (get16(input, layout.format_offset) != schema.format) {
68 return error.TransitionFormatMismatch;
69 }
70 if (get16(input, layout.fabric_dialect_offset) !=
71 @backingInt(fabric.Dialect.ordered_effect_fabric_v3) or
72 get16(input, layout.fault_dialect_offset) !=
73 @backingInt(fault.Dialect.deterministic_fault_v1))
74 {
75 return error.UnknownTransitionField;
76 }
77 try validateEnvelopeShape(input);
78 }
79
80 fn validateEnvelopeShape(
81 input: *const [schema.stream_bytes]u8,
82 ) transition_types.Error!void {
83 const layout = schema.Envelope;
84 if (get16(input, layout.digest_bytes_offset) != schema.digest_bytes or
85 get16(input, layout.root_bytes_offset) != schema.root_bytes or
86 get16(input, layout.record_bytes_offset) != schema.record_bytes or
87 get16(input, layout.effect_bytes_offset) != schema.effect_bytes or
88 get16(input, layout.fault_effect_bytes_offset) !=
89 schema.fault_effect_bytes or
90 get16(input, layout.decision_bytes_offset) != schema.decision_bytes or
91 get16(input, layout.semantic_bytes_offset) != schema.semantic_bytes)
92 {
93 return error.MetadataShapeMismatch;
94 }
95 }
96
97 pub fn validateReserved(
98 input: *const [schema.stream_bytes]u8,
99 kind: u8,
100 ) transition_types.Error!void {
101 if (!zeroRange(input, schema.Envelope.reserved_offset, schema.Envelope.limit) or
102 !rootReserved(input, schema.Header.previous_offset) or
103 !rootReserved(input, schema.Header.result_offset) or
104 !zeroRange(input, schema.Header.reserved_offset, schema.Header.limit))
105 {
106 return error.ReservedNonzero;
107 }
108 switch (kind) {
109 1 => try validateAdmissionReserved(input),
110 2 => try validateSettlementReserved(input),
111 3 => try validateFaultReserved(input),
112 else => return error.UnknownTransitionField,
113 }
114 }
115
116 fn validateAdmissionReserved(
117 input: *const [schema.stream_bytes]u8,
118 ) transition_types.Error!void {
119 const start = schema.Header.limit;
120 const layout = schema.Admission;
121 if (!zeroRange(
122 input,
123 start + layout.reserved_offset,
124 start + layout.record_offset,
125 ) or !wire.allZero(input[start + layout.limit ..])) {
126 return error.ReservedNonzero;
127 }
128 try validateRecordReserved(
129 input,
130 start + layout.record_offset,
131 input[start + layout.record_kind_offset],
132 );
133 try validateEffectReserved(
134 input,
135 start + layout.effect_offset,
136 input[start + layout.effect_kind_offset],
137 );
138 const present = try boolean(input[start + layout.fault_present_offset]);
139 if (present) {
140 try validateFaultEffectReserved(input, start + layout.fault_effect_offset);
141 if (!zeroRange(
142 input,
143 start + layout.decision_offset + schema.Decision.reserved_offset,
144 start + layout.decision_offset + schema.Decision.basis_offset,
145 )) return error.ReservedNonzero;
146 } else if (!wire.allZero(
147 input[start + layout.fault_effect_offset .. start + layout.limit],
148 )) {
149 return error.ReservedNonzero;
150 }
151 }
152
153 fn validateRecordReserved(
154 input: *const [schema.stream_bytes]u8,
155 start: usize,
156 kind: u8,
157 ) transition_types.Error!void {
158 const layout = schema.Record;
159 switch (kind) {
160 1, 3 => {
161 const length = get16(input, start + layout.payload_length_offset);
162 if (length == 0 or length > admission.terminal_bytes_max) {
163 return error.MetadataShapeMismatch;
164 }
165 if (!zeroRange(
166 input,
167 start + layout.payload_reserved_offset,
168 start + layout.payload_storage_offset,
169 ) or !zeroRange(
170 input,
171 start + layout.payload_storage_offset + length,
172 start + layout.limit,
173 )) return error.ReservedNonzero;
174 },
175 2 => if (!zeroRange(input, start + 16, start + layout.limit)) {
176 return error.ReservedNonzero;
177 },
178 4 => {
179 const length = get16(input, start + layout.effect_length_offset);
180 if (length > admission.effect_result_bytes_max) {
181 return error.MetadataShapeMismatch;
182 }
183 if (!zeroRange(
184 input,
185 start + layout.effect_reserved_offset,
186 start + layout.effect_storage_offset,
187 ) or !zeroRange(
188 input,
189 start + layout.effect_storage_offset + length,
190 start + layout.limit,
191 )) return error.ReservedNonzero;
192 },
193 else => return error.UnknownTransitionField,
194 }
195 }
196
197 fn validateEffectReserved(
198 input: *const [schema.stream_bytes]u8,
199 start: usize,
200 kind: u8,
201 ) transition_types.Error!void {
202 const layout = schema.Effect;
203 switch (kind) {
204 1 => if (!zeroRange(input, start, start + layout.limit)) {
205 return error.ReservedNonzero;
206 },
207 2 => {
208 const length = get16(input, start + layout.length_offset);
209 if (length == 0 or length > fabric.packet_bytes_max) {
210 return error.MetadataShapeMismatch;
211 }
212 if (!zeroRange(
213 input,
214 start + layout.reserved_offset,
215 start + layout.storage_offset,
216 ) or !zeroRange(
217 input,
218 start + layout.storage_offset + length,
219 start + layout.limit,
220 )) return error.ReservedNonzero;
221 },
222 3 => if (!zeroRange(input, start + 8, start + layout.limit)) {
223 return error.ReservedNonzero;
224 },
225 else => return error.UnknownTransitionField,
226 }
227 }
228
229 fn validateSettlementReserved(
230 input: *const [schema.stream_bytes]u8,
231 ) transition_types.Error!void {
232 const start = schema.Header.limit;
233 const layout = schema.Settlement;
234 const semantic = start + layout.semantic_offset;
235 if (!zeroRange(input, start + layout.reserved_offset, semantic) or
236 !zeroRange(
237 input,
238 semantic + schema.Semantic.first_reserved_offset,
239 semantic + schema.Semantic.boundary_block_offset,
240 ) or !zeroRange(
241 input,
242 semantic + schema.Semantic.second_reserved_offset,
243 semantic + schema.Semantic.transcript_offset,
244 ) or !zeroRange(
245 input,
246 semantic + schema.Semantic.third_reserved_offset,
247 semantic + schema.Semantic.limit,
248 ) or !wire.allZero(input[start + layout.limit ..])) {
249 return error.ReservedNonzero;
250 }
251 }
252
253 fn validateFaultReserved(
254 input: *const [schema.stream_bytes]u8,
255 ) transition_types.Error!void {
256 const start = schema.Header.limit;
257 try validateFaultEffectReserved(input, start + schema.Fault.effect_offset);
258 if (!zeroRange(
259 input,
260 start + schema.Fault.decision_offset + schema.Decision.reserved_offset,
261 start + schema.Fault.decision_offset + schema.Decision.basis_offset,
262 ) or !wire.allZero(input[start + schema.Fault.limit ..])) {
263 return error.ReservedNonzero;
264 }
265 }
266
267 fn validateFaultEffectReserved(
268 input: *const [schema.stream_bytes]u8,
269 start: usize,
270 ) transition_types.Error!void {
271 const layout = schema.FaultEffect;
272 if (!zeroRange(
273 input,
274 start + layout.reserved_offset,
275 start + layout.value_offset,
276 )) return error.ReservedNonzero;
277 const used: usize = switch (input[start + layout.kind_offset]) {
278 1 => layout.value_offset + 16,
279 2 => layout.second_offset + 8,
280 3, 9, 11 => layout.limit,
281 4, 8 => layout.value_offset + 8,
282 5, 6 => layout.value_offset + 16,
283 7 => layout.second_offset + 17,
284 10 => layout.value_offset + 2,
285 else => return error.UnknownTransitionField,
286 };
287 if (!zeroRange(input, start + used, start + layout.limit)) {
288 return error.ReservedNonzero;
289 }
290 }
291
292 pub fn decodeRoot(
293 input: *const [schema.stream_bytes]u8,
294 start: usize,
295 ) transition_types.Error!fabric.Root {
296 const layout = schema.RootLayout;
297 return .{
298 .digest = digest(input, start + layout.digest_offset),
299 .dialect = try enumValue(
300 fabric.Dialect,
301 get16(input, start + layout.dialect_offset),
302 ),
303 .machine_contract = .{
304 .digest = digest(input, start + layout.contract_offset),
305 },
306 .entry_frontier = get64(input, start + layout.entry_frontier_offset),
307 .admission_frontier = get64(
308 input,
309 start + layout.admission_frontier_offset,
310 ),
311 .fault_frontier = get64(input, start + layout.fault_frontier_offset),
312 };
313 }
314
315 fn decodeAdmission(
316 input: *const [schema.stream_bytes]u8,
317 before: *const fabric.Fabric,
318 ) transition_types.Error!fabric.AdmissionEntry {
319 const start = schema.Header.limit;
320 const layout = schema.Admission;
321 const node = nodeId(input, start + layout.node_offset);
322 const basis = try nodeBasis(before, node);
323 const record = try decodeRecord(
324 input,
325 start + layout.record_offset,
326 input[start + layout.record_kind_offset],
327 );
328 const prepared = try admission.prepare(basis, record);
329 const effect = try decodeAdmissionEffect(
330 input,
331 start + layout.effect_offset,
332 input[start + layout.effect_kind_offset],
333 );
334 const fault_value: ?fabric.AdmissionFault = if (try boolean(
335 input[start + layout.fault_present_offset],
336 )) .{
337 .effect = try decodeFaultEffect(input, start + layout.fault_effect_offset),
338 .decision = try decodeDecision(input, start + layout.decision_offset),
339 } else null;
340 return .{
341 .node = node,
342 .admission = prepared,
343 .effect = effect,
344 .fault = fault_value,
345 };
346 }
347
348 fn decodeRecord(
349 input: *const [schema.stream_bytes]u8,
350 start: usize,
351 kind: u8,
352 ) transition_types.Error!admission.Record {
353 const layout = schema.Record;
354 return switch (kind) {
355 1 => admission.terminal(
356 get64(input, start + layout.first_offset),
357 payload(input, start, layout.payload_storage_offset, layout.payload_length_offset),
358 ),
359 2 => admission.virtualTime(
360 get64(input, start + layout.first_offset),
361 get64(input, start + layout.second_offset),
362 ),
363 3 => admission.entropy(
364 get64(input, start + layout.first_offset),
365 payload(input, start, layout.payload_storage_offset, layout.payload_length_offset),
366 ),
367 4 => admission.effectResult(
368 digest(input, start + layout.first_offset),
369 get64(input, start + layout.correlation_offset),
370 try enumValue(
371 os.abi.EffectStatus,
372 get16(input, start + layout.status_offset),
373 ),
374 digest(input, start + layout.output_root_offset),
375 payload(input, start, layout.effect_storage_offset, layout.effect_length_offset),
376 ),
377 else => error.UnknownTransitionField,
378 };
379 }
380
381 fn decodeAdmissionEffect(
382 input: *const [schema.stream_bytes]u8,
383 start: usize,
384 kind: u8,
385 ) transition_types.Error!fabric.AdmissionEffect {
386 const layout = schema.Effect;
387 return switch (kind) {
388 1 => .direct,
389 2 => packet: {
390 const length = get16(input, start + layout.length_offset);
391 var storage: [fabric.packet_bytes_max]u8 = @splat(0);
392 @memcpy(
393 storage[0..length],
394 input[start + layout.storage_offset ..][0..length],
395 );
396 break :packet .{ .packet_send = .{
397 .id = get64(input, start + layout.id_offset),
398 .source = nodeId(input, start + layout.source_offset),
399 .destination = nodeId(input, start + layout.destination_offset),
400 .channel = get16(input, start + layout.channel_offset),
401 .request = .{
402 .receipt = .{
403 .digest = digest(input, start + layout.request_receipt_offset),
404 },
405 .correlation = get64(
406 input,
407 start + layout.request_correlation_offset,
408 ),
409 },
410 .length = length,
411 .storage = storage,
412 .digest = digest(input, start + layout.digest_offset),
413 } };
414 },
415 3 => .{ .packet_delivery = get64(input, start + layout.id_offset) },
416 else => error.UnknownTransitionField,
417 };
418 }
419
420 fn decodeSettlement(
421 input: *const [schema.stream_bytes]u8,
422 ) transition_types.Error!fabric.SettlementEntry {
423 const start = schema.Header.limit;
424 const layout = schema.Settlement;
425 const receipt = try decodeSemantic(input, start + layout.semantic_offset);
426 try instance.verifySemanticReceipt(receipt);
427 return .{
428 .node = nodeId(input, start + layout.node_offset),
429 .receipt = receipt,
430 };
431 }
432
433 fn decodeSemantic(
434 input: *const [schema.stream_bytes]u8,
435 start: usize,
436 ) transition_types.Error!instance.SemanticReceipt {
437 const layout = schema.Semantic;
438 return .{
439 .admission_receipt = .{
440 .digest = digest(input, start + layout.admission_offset),
441 },
442 .basis = .{
443 .contract = .{
444 .digest = digest(input, start + layout.contract_offset),
445 },
446 .source_root = digest(input, start + layout.source_root_offset),
447 .frontiers = .{
448 .input = get64(input, start + layout.input_offset),
449 .terminal_input_offset = get64(
450 input,
451 start + layout.terminal_input_offset,
452 ),
453 .virtual_time_tick = get64(
454 input,
455 start + layout.virtual_time_offset,
456 ),
457 .entropy_generation = get64(input, start + layout.entropy_offset),
458 .effect = get64(input, start + layout.effect_offset),
459 },
460 .outstanding_effect = null,
461 },
462 .image_digest = digest(input, start + layout.image_offset),
463 .execution_fingerprint = .{
464 .digest = digest(input, start + layout.execution_offset),
465 },
466 .block_root = .{
467 .generation = get64(input, start + layout.block_generation_offset),
468 .digest = digest(input, start + layout.block_digest_offset),
469 },
470 .boundary = try decodeSemanticBoundary(input, start),
471 .settled = .{
472 .request_cursor = get64(input, start + layout.settled_request_offset),
473 .event_cursor = get64(input, start + layout.settled_event_offset),
474 },
475 .k0 = .{ .counter = input[start + layout.k0_offset] },
476 .semantic_transcript_digest = digest(input, start + layout.transcript_offset),
477 };
478 }
479
480 fn decodeSemanticBoundary(
481 input: *const [schema.stream_bytes]u8,
482 start: usize,
483 ) transition_types.Error!@FieldType(instance.SemanticReceipt, "boundary") {
484 const layout = schema.Semantic;
485 return .{
486 .request_sequence = get64(input, start + layout.request_sequence_offset),
487 .semantic_frontier = get64(input, start + layout.semantic_frontier_offset),
488 .effect_frontier = get64(input, start + layout.effect_frontier_offset),
489 .terminal_offset = get64(input, start + layout.terminal_offset),
490 .virtual_time_tick = get64(
491 input,
492 start + layout.boundary_virtual_time_offset,
493 ),
494 .entropy_generation = get64(
495 input,
496 start + layout.boundary_entropy_offset,
497 ),
498 .request_consumed = get64(input, start + layout.request_consumed_offset),
499 .request_produced = get64(input, start + layout.request_produced_offset),
500 .event_consumed = get64(input, start + layout.event_consumed_offset),
501 .event_produced = get64(input, start + layout.event_produced_offset),
502 .unresolved_effects = get32(
503 input,
504 start + layout.unresolved_effects_offset,
505 ),
506 .scheduler = try enumValue(
507 os.abi.SchedulerState,
508 get16(input, start + layout.scheduler_offset),
509 ),
510 .block_root = digest(input, start + layout.boundary_block_offset),
511 .input_frontier = get64(input, start + layout.boundary_input_offset),
512 .terminal_input_offset = get64(
513 input,
514 start + layout.boundary_terminal_input_offset,
515 ),
516 };
517 }
518
519 fn decodeFaultEntry(
520 input: *const [schema.stream_bytes]u8,
521 ) transition_types.Error!fabric.FaultEntry {
522 const start = schema.Header.limit;
523 return .{
524 .effect = try decodeFaultEffect(input, start + schema.Fault.effect_offset),
525 .decision = try decodeDecision(input, start + schema.Fault.decision_offset),
526 };
527 }
528
529 fn decodeFaultEffect(
530 input: *const [schema.stream_bytes]u8,
531 start: usize,
532 ) transition_types.Error!fabric.FaultEffect {
533 const layout = schema.FaultEffect;
534 const kind = try enumValue(fault.Kind, input[start + layout.kind_offset]);
535 return switch (kind) {
536 .machine_crash => .{
537 .machine_crash = nodeId(input, start + layout.value_offset),
538 },
539 .process_crash => .{ .process_crash = .{
540 .node = nodeId(input, start + layout.value_offset),
541 .process = get64(input, start + layout.second_offset),
542 } },
543 .io_error => .{ .io_error = decodeAlternatives(input, start) },
544 .packet_loss => .{
545 .packet_loss = get64(input, start + layout.value_offset),
546 },
547 .packet_delay => .{ .packet_delay = .{
548 .packet = get64(input, start + layout.value_offset),
549 .until_tick = get64(input, start + layout.value_offset + 8),
550 } },
551 .packet_reorder => .{ .packet_reorder = .{
552 .first = get64(input, start + layout.value_offset),
553 .second = get64(input, start + layout.value_offset + 8),
554 } },
555 .partition => .{ .partition = .{
556 .first = nodeId(input, start + layout.value_offset),
557 .second = nodeId(input, start + layout.second_offset),
558 .active = try boolean(input[start + layout.second_offset + 16]),
559 } },
560 .clock_jump => .{
561 .clock_jump = get64(input, start + layout.value_offset),
562 },
563 .entropy_choice => .{
564 .entropy_choice = decodeAlternatives(input, start),
565 },
566 .capacity_exhaustion => .{ .capacity_exhaustion = .{
567 .resource = try enumValue(
568 fabric.CapacityResource,
569 input[start + layout.value_offset],
570 ),
571 .active = try boolean(input[start + layout.value_offset + 1]),
572 } },
573 .host_service_failure => .{
574 .host_service_failure = decodeAlternatives(input, start),
575 },
576 };
577 }
578
579 fn decodeAlternatives(
580 input: *const [schema.stream_bytes]u8,
581 start: usize,
582 ) fabric.FaultAlternatives {
583 const layout = schema.FaultEffect;
584 return .{
585 .node = nodeId(input, start + layout.value_offset),
586 .bypass = digest(input, start + layout.second_offset),
587 .inject = digest(input, start + layout.third_offset),
588 };
589 }
590
591 fn decodeDecision(
592 input: *const [schema.stream_bytes]u8,
593 start: usize,
594 ) transition_types.Error!fault.Decision {
595 const layout = schema.Decision;
596 const result: fault.Decision = .{
597 .point = .{
598 .id = digest(input, start + layout.id_offset),
599 .dialect = try enumValue(
600 fault.Dialect,
601 get16(input, start + layout.dialect_offset),
602 ),
603 .basis = digest(input, start + layout.basis_offset),
604 .kind = try enumValue(fault.Kind, input[start + layout.kind_offset]),
605 .subject = digest(input, start + layout.subject_offset),
606 },
607 .choice = try enumValue(fault.Choice, input[start + layout.choice_offset]),
608 .digest = digest(input, start + layout.digest_offset),
609 };
610 try fault.verifyDecision(result);
611 return result;
612 }
613
614 fn nodeBasis(
615 before: *const fabric.Fabric,
616 id: fabric.NodeId,
617 ) transition_types.Error!admission.Basis {
618 const count = before.state.node_count;
619 if (count == 0 or count > fabric.node_limit) {
620 return error.NodeCapacityExceeded;
621 }
622 for (before.state.nodes[0..count]) |node| {
623 if (std.meta.eql(node.id, id)) return node.basis;
624 }
625 return error.UnknownNode;
626 }
627
628 fn payload(
629 input: *const [schema.stream_bytes]u8,
630 start: usize,
631 storage_offset: usize,
632 length_offset: usize,
633 ) []const u8 {
634 const length = get16(input, start + length_offset);
635 std.debug.assert(start + storage_offset + length <= input.len);
636 return input[start + storage_offset ..][0..length];
637 }
638
639 fn rootReserved(
640 input: *const [schema.stream_bytes]u8,
641 start: usize,
642 ) bool {
643 return zeroRange(
644 input,
645 start + schema.RootLayout.reserved_offset,
646 start + schema.RootLayout.limit,
647 );
648 }
649
650 pub fn boolean(value: u8) transition_types.Error!bool {
651 return switch (value) {
652 0 => false,
653 1 => true,
654 else => error.UnknownTransitionField,
655 };
656 }
657
658 pub fn enumValue(comptime T: type, value: anytype) transition_types.Error!T {
659 inline for (std.meta.tags(T)) |candidate| {
660 if (@backingInt(candidate) == value) return candidate;
661 }
662 return error.UnknownTransitionField;
663 }
664
665 pub fn nodeId(
666 input: *const [schema.stream_bytes]u8,
667 offset: usize,
668 ) fabric.NodeId {
669 std.debug.assert(offset + 16 <= input.len);
670 return .{ .bytes = input[offset..][0..16].* };
671 }
672
673 pub fn digest(
674 input: *const [schema.stream_bytes]u8,
675 offset: usize,
676 ) os.abi.Digest {
677 std.debug.assert(offset + schema.digest_bytes <= input.len);
678 return input[offset..][0..schema.digest_bytes].*;
679 }
680
681 fn zeroRange(
682 input: *const [schema.stream_bytes]u8,
683 first: usize,
684 last: usize,
685 ) bool {
686 std.debug.assert(first <= last);
687 std.debug.assert(last <= input.len);
688 return wire.allZero(input[first..last]);
689 }
690
691 pub fn get16(input: *const [schema.stream_bytes]u8, offset: usize) u16 {
692 std.debug.assert(offset + 2 <= input.len);
693 return wire.read16(input[offset..][0..2]);
694 }
695
696 pub fn get32(input: *const [schema.stream_bytes]u8, offset: usize) u32 {
697 std.debug.assert(offset + 4 <= input.len);
698 return wire.read32(input[offset..][0..4]);
699 }
700
701 pub fn get64(input: *const [schema.stream_bytes]u8, offset: usize) u64 {
702 std.debug.assert(offset + 8 <= input.len);
703 return wire.read64(input[offset..][0..8]);
704 }