lib/machine/src/world/manifest/codec.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const decode = @import("decode.zig");
2 const encode = @import("encode.zig");
3 const manifest_types = @import("types.zig");
4 const schema = @import("schema.zig");
5 const std = @import("std");
6 const world = @import("../root.zig");
7
8 pub const Error = manifest_types.Error;
9 pub const stream_bytes = schema.stream_bytes;
10
11 pub fn encodeDisjoint(value: *const world.Cut, writer: *std.Io.Writer) Error!void {
12 try validateSink(value, writer);
13 var bytes: [stream_bytes]u8 = undefined;
14 try encode.manifest(value, &bytes);
15 try writer.writeAll(&bytes);
16 }
17
18 pub fn decodeDisjoint(
19 reader: *std.Io.Reader,
20 expected_root: world.Root,
21 ) Error!world.Cut {
22 var bytes: [stream_bytes]u8 = undefined;
23 try readExact(reader, &bytes);
24 var trailing: [1]u8 = undefined;
25 if (try reader.readSliceShort(&trailing) != 0) return error.TrailingData;
26 return decode.manifest(&bytes, expected_root);
27 }
28
29 fn readExact(reader: *std.Io.Reader, output: []u8) Error!void {
30 std.debug.assert(output.len == stream_bytes);
31 reader.readSliceAll(output) catch |failure| switch (failure) {
32 error.EndOfStream => return error.TruncatedStream,
33 error.ReadFailed => return error.ReadFailed,
34 };
35 }
36
37 fn validateSink(value: *const world.Cut, writer: *std.Io.Writer) Error!void {
38 const source = std.mem.asBytes(value);
39 if (buffersOverlap(std.mem.asBytes(writer), source) or
40 buffersOverlap(writer.buffer, source))
41 {
42 return error.SinkAliasesCut;
43 }
44 }
45
46 fn buffersOverlap(left: []const u8, right: []const u8) bool {
47 if (left.len == 0 or right.len == 0) return false;
48 const left_start = @intFromPtr(left.ptr);
49 const right_start = @intFromPtr(right.ptr);
50 const left_end = std.math.add(usize, left_start, left.len) catch return true;
51 const right_end = std.math.add(usize, right_start, right.len) catch return true;
52 return left_start < right_end and right_start < left_end;
53 }