lib/acp/src/reader/capacity.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 /// A caller chooses the longest line the reader must accept, so the reader's buffer size follows.
 4 /// The structure holds one limit: the most bytes a line may hold before its newline. The package
 5 /// exports it as `acp.ReaderLimits`, `reader.Limits` and `Storage.Limits`. `reader.default_limits`
 6 /// sets 2 MiB.
 7 pub const Limits = struct {
 8     /// The most bytes a line may hold before its newline. Zero is allowed and accepts only empty
 9     /// lines.
10     message_bytes: usize,
11 };
12 
13 pub const DeriveError = error{CapacityOverflow};
14 
15 /// A caller learns the buffer size before any buffer exists, for example to set aside the reader's
16 /// share of one larger region of memory. The structure holds the line limit and the buffer size it
17 /// needs. `derive` builds it. Another program in the repository adds the buffer size into the size
18 /// of one region it allocates up front. The package exports it as `acp.ReaderCapacity`.
19 pub const Capacity = struct {
20     /// The line limit, copied from `Limits`.
21     message_bytes: usize,
22     /// The buffer size: the line limit plus one byte, for the newline after a longest line. The
23     /// value is always above the line limit and above zero.
24     storage_bytes: usize,
25 
26     /// A caller works out the buffer size for a line limit and learns early when the limit is too
27     /// large. The function returns the line limit with its buffer size. The call fails with
28     /// `error.CapacityOverflow` when the limit plus one does not fit in a `usize`. The call
29     /// allocates nothing.
30     pub fn derive(limits: Limits) DeriveError!Capacity {
31         const storage_bytes = std.math.add(usize, limits.message_bytes, 1) catch
32             return error.CapacityOverflow;
33         std.debug.assert(storage_bytes > limits.message_bytes);
34         std.debug.assert(storage_bytes != 0);
35         return .{
36             .message_bytes = limits.message_bytes,
37             .storage_bytes = storage_bytes,
38         };
39     }
40 };
41 
42 test "ACP reader capacity matches independent byte arithmetic" {
43     comptime {
44         @stardustClaim(
45             @import("alloc_phase").capacity.witness(@import("./root.zig").Storage, "acp_reader_capacity"),
46             null,
47             null,
48             null,
49             null,
50             null,
51             null,
52         );
53     }
54 
55     try std.testing.expectEqual(
56         Capacity{ .message_bytes = 0, .storage_bytes = 1 },
57         try Capacity.derive(.{ .message_bytes = 0 }),
58     );
59     try std.testing.expectEqual(
60         Capacity{ .message_bytes = 31, .storage_bytes = 32 },
61         try Capacity.derive(.{ .message_bytes = 31 }),
62     );
63     try std.testing.expectError(
64         error.CapacityOverflow,
65         Capacity.derive(.{ .message_bytes = std.math.maxInt(usize) }),
66     );
67 }