lib/zen/src/footnote/capacity.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const model = @import("model.zig");
 3 const plan_mod = @import("plan.zig");
 4 
 5 pub const storage_alignment: usize = @alignOf(model.Definition);
 6 
 7 pub const Limits = plan_mod.Limits;
 8 pub const DeriveError = error{CapacityOverflow};
 9 
10 pub const Capacity = struct {
11     limits: Limits,
12     definitions_offset: usize,
13     definition_bytes: usize,
14     joined_text_offset: usize,
15     storage_bytes: usize,
16 
17     pub fn derive(limits: Limits) DeriveError!Capacity {
18         const definition_bytes = std.math.mul(
19             usize,
20             limits.max_definitions,
21             @sizeOf(model.Definition),
22         ) catch return error.CapacityOverflow;
23         return .{
24             .limits = limits,
25             .definitions_offset = 0,
26             .definition_bytes = definition_bytes,
27             .joined_text_offset = definition_bytes,
28             .storage_bytes = try added(definition_bytes, limits.max_joined_text_bytes),
29         };
30     }
31 };
32 
33 fn added(left: usize, right: usize) DeriveError!usize {
34     return std.math.add(usize, left, right) catch error.CapacityOverflow;
35 }
36 
37 fn independent(limits: Limits) DeriveError!Capacity {
38     const definition_bytes = @as(u128, limits.max_definitions) * @sizeOf(model.Definition);
39     const storage_bytes = definition_bytes + limits.max_joined_text_bytes;
40     if (definition_bytes > std.math.maxInt(usize) or storage_bytes > std.math.maxInt(usize)) {
41         return error.CapacityOverflow;
42     }
43     return .{
44         .limits = limits,
45         .definitions_offset = 0,
46         .definition_bytes = @intCast(definition_bytes),
47         .joined_text_offset = @intCast(definition_bytes),
48         .storage_bytes = @intCast(storage_bytes),
49     };
50 }
51 
52 test "footnote capacity matches an independent byte model" {
53     comptime {
54         @stardustClaim(
55             @import("alloc_phase").capacity.witness(@import("./root.zig").Storage, "zen_footnote_capacity"),
56             null,
57             null,
58             null,
59             null,
60             null,
61             null,
62         );
63     }
64 
65     const limits = Limits{
66         .max_definitions = 3,
67         .max_joined_text_bytes = 42,
68     };
69     const capacity = try Capacity.derive(limits);
70     try std.testing.expectEqual(try independent(limits), capacity);
71     try std.testing.expectEqual(@as(usize, 210), capacity.storage_bytes);
72     try std.testing.expectEqual(
73         @as(usize, 94_208),
74         (try Capacity.derive(plan_mod.default_limits)).storage_bytes,
75     );
76 }
77 
78 test "footnote capacity handles zero and rejects overflow" {
79     try std.testing.expectEqual(@as(usize, 0), (try Capacity.derive(.{
80         .max_definitions = 0,
81         .max_joined_text_bytes = 0,
82     })).storage_bytes);
83     try std.testing.expectError(error.CapacityOverflow, Capacity.derive(.{
84         .max_definitions = std.math.maxInt(usize),
85         .max_joined_text_bytes = 0,
86     }));
87     try std.testing.expectError(error.CapacityOverflow, Capacity.derive(.{
88         .max_definitions = 1,
89         .max_joined_text_bytes = std.math.maxInt(usize),
90     }));
91 }