lib/machine/src/fabric/snapshot/encode.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const admission = @import("../../admission/root.zig");
2 const fabric = @import("../root.zig");
3 const os = @import("os");
4 const schema = @import("schema.zig");
5 const std = @import("std");
6
7 const State = @FieldType(fabric.Fabric, "state");
8 const NodeState = @typeInfo(@FieldType(State, "nodes")).array.child;
9 const QueuedPacket = @typeInfo(@FieldType(State, "packets")).array.child;
10 const wire = os.abi.wire;
11
12 pub fn snapshot(
13 value: *const fabric.Fabric,
14 output: *[schema.stream_bytes]u8,
15 ) fabric.Error!void {
16 _ = try value.cut();
17 std.debug.assert(!value.turnPending());
18 var encoded: [schema.stream_bytes]u8 = @splat(0);
19 encodeEnvelope(&encoded);
20 encodeRoot(value.root(), &encoded);
21 encodeState(value.state, &encoded);
22 for (value.state.nodes[0..value.state.node_count], 0..) |node, index| {
23 encodeNode(node, index, &encoded);
24 }
25 for (value.state.packets[0..value.state.packet_count], 0..) |packet, index| {
26 encodePacket(packet, index, &encoded);
27 }
28 output.* = encoded;
29 }
30
31 fn encodeEnvelope(output: *[schema.stream_bytes]u8) void {
32 const layout = schema.Envelope;
33 @memcpy(output[layout.magic_offset..layout.version_offset], &schema.magic);
34 put16(output, layout.version_offset, schema.version);
35 put16(output, layout.stream_bytes_offset, schema.stream_bytes);
36 put16(output, layout.flags_offset, schema.flags);
37 put16(output, layout.format_offset, schema.format);
38 put16(output, layout.dialect_offset, @backingInt(fabric.Dialect.ordered_effect_fabric_v3));
39 put16(output, layout.node_capacity_offset, fabric.node_limit);
40 put16(output, layout.packet_capacity_offset, fabric.packet_limit);
41 put16(output, layout.node_bytes_offset, schema.node_bytes);
42 put16(output, layout.packet_bytes_offset, schema.packet_bytes);
43 put16(output, layout.packet_payload_bytes_offset, schema.packet_payload_bytes);
44 put16(output, layout.digest_bytes_offset, schema.digest_bytes);
45 put16(output, layout.root_bytes_offset, schema.root_bytes);
46 put16(output, layout.state_header_bytes_offset, schema.state_header_bytes);
47 }
48
49 fn encodeRoot(value: fabric.Root, output: *[schema.stream_bytes]u8) void {
50 const layout = schema.RootLayout;
51 putDigest(output, layout.digest_offset, value.digest);
52 putDigest(output, layout.contract_offset, value.machine_contract.digest);
53 put64(output, layout.entry_frontier_offset, value.entry_frontier);
54 put64(output, layout.admission_frontier_offset, value.admission_frontier);
55 put64(output, layout.fault_frontier_offset, value.fault_frontier);
56 put16(output, layout.dialect_offset, @backingInt(value.dialect));
57 }
58
59 fn encodeState(value: State, output: *[schema.stream_bytes]u8) void {
60 const layout = schema.StateLayout;
61 @memcpy(output[layout.world_offset..][0..16], &value.world);
62 output[layout.node_count_offset] = value.node_count;
63 output[layout.packet_count_offset] = value.packet_count;
64 output[layout.partition_bits_offset] = value.partition_bits;
65 output[layout.capacity_bits_offset] = value.capacity_bits;
66 put64(output, layout.virtual_time_offset, value.virtual_time_tick);
67 put64(output, layout.entropy_frontier_offset, value.entropy_frontier);
68 put64(output, layout.entropy_bytes_offset, value.entropy_bytes);
69 put64(output, layout.packet_next_id_offset, value.packet_next_id);
70 put64(output, layout.entry_frontier_offset, value.entry_frontier);
71 put64(output, layout.admission_frontier_offset, value.admission_frontier);
72 put64(output, layout.fault_frontier_offset, value.fault_frontier);
73 put32(output, layout.admission_limit_offset, value.admission_limit);
74 putDigest(output, layout.ledger_digest_offset, value.ledger_digest);
75 putDigest(output, layout.fault_digest_offset, value.fault_digest);
76 }
77
78 fn encodeNode(
79 value: NodeState,
80 index: usize,
81 output: *[schema.stream_bytes]u8,
82 ) void {
83 std.debug.assert(index < fabric.node_limit);
84 const layout = schema.NodeLayout;
85 const start = schema.nodes_offset + index * schema.node_bytes;
86 std.debug.assert(start + schema.node_bytes <= schema.packets_offset);
87 @memcpy(output[start + layout.id_offset ..][0..16], &value.id.bytes);
88 encodeBasis(value.basis, start, output);
89 output[start + layout.machine_kind_offset] = @backingInt(value.machine.kind);
90 output[start + layout.available_offset] = @intFromBool(value.available);
91 putDigest(output, start + layout.machine_digest_offset, value.machine.digest);
92 }
93
94 fn encodeBasis(
95 value: admission.Basis,
96 start: usize,
97 output: *[schema.stream_bytes]u8,
98 ) void {
99 std.debug.assert(start >= schema.nodes_offset);
100 std.debug.assert(start + schema.node_bytes <= schema.packets_offset);
101 const layout = schema.NodeLayout;
102 putDigest(output, start + layout.contract_offset, value.contract.digest);
103 putDigest(output, start + layout.source_root_offset, value.source_root);
104 put64(output, start + layout.input_frontier_offset, value.frontiers.input);
105 put64(output, start + layout.terminal_input_offset, value.frontiers.terminal_input_offset);
106 put64(output, start + layout.virtual_time_offset, value.frontiers.virtual_time_tick);
107 put64(output, start + layout.entropy_offset, value.frontiers.entropy_generation);
108 put64(output, start + layout.effect_offset, value.frontiers.effect);
109 if (value.outstanding_effect) |request| {
110 output[start + layout.request_present_offset] = 1;
111 putDigest(output, start + layout.request_receipt_offset, request.receipt.digest);
112 put64(output, start + layout.request_correlation_offset, request.correlation);
113 }
114 }
115
116 fn encodePacket(
117 value: QueuedPacket,
118 index: usize,
119 output: *[schema.stream_bytes]u8,
120 ) void {
121 std.debug.assert(index < fabric.packet_limit);
122 std.debug.assert(value.packet.length > 0);
123 std.debug.assert(value.packet.length <= fabric.packet_bytes_max);
124 const layout = schema.PacketLayout;
125 const start = schema.packets_offset + index * schema.packet_bytes;
126 std.debug.assert(start + schema.packet_bytes <= schema.material_limit);
127 put64(output, start + layout.id_offset, value.packet.id);
128 @memcpy(output[start + layout.source_offset ..][0..16], &value.packet.source.bytes);
129 @memcpy(output[start + layout.destination_offset ..][0..16], &value.packet.destination.bytes);
130 put16(output, start + layout.channel_offset, value.packet.channel);
131 put16(output, start + layout.length_offset, value.packet.length);
132 output[start + layout.ready_offset] = @intFromBool(value.ready);
133 putDigest(
134 output,
135 start + layout.request_receipt_offset,
136 value.packet.request.receipt.digest,
137 );
138 put64(output, start + layout.request_correlation_offset, value.packet.request.correlation);
139 put64(output, start + layout.ready_at_offset, value.ready_at_tick);
140 put64(output, start + layout.order_offset, value.order);
141 putDigest(output, start + layout.digest_offset, value.packet.digest);
142 @memcpy(output[start + layout.storage_offset ..][0..value.packet.length], value.packet.bytes());
143 }
144
145 fn putDigest(
146 output: *[schema.stream_bytes]u8,
147 offset: usize,
148 value: os.abi.Digest,
149 ) void {
150 std.debug.assert(offset + schema.digest_bytes <= output.len);
151 @memcpy(output[offset..][0..schema.digest_bytes], &value);
152 }
153
154 fn put16(output: *[schema.stream_bytes]u8, offset: usize, value: anytype) void {
155 std.debug.assert(offset + 2 <= output.len);
156 wire.write16(output[offset..][0..2], @intCast(value));
157 }
158
159 fn put32(output: *[schema.stream_bytes]u8, offset: usize, value: u32) void {
160 std.debug.assert(offset + 4 <= output.len);
161 wire.write32(output[offset..][0..4], value);
162 }
163
164 fn put64(output: *[schema.stream_bytes]u8, offset: usize, value: u64) void {
165 std.debug.assert(offset + 8 <= output.len);
166 wire.write64(output[offset..][0..8], value);
167 }