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 }