lib/filigree/src/fallback/workspace.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const alloc_phase = @import("alloc_phase");
  3 const capacity_mod = @import("capacity.zig");
  4 const model = @import("model.zig");
  5 
  6 pub const Status = struct {
  7     phase: alloc_phase.capacity.Phase,
  8     storage_bytes: usize,
  9     max_source_units: usize,
 10     scalar_count: usize,
 11     cluster_count: usize,
 12     range_count: usize,
 13 };
 14 
 15 pub const Workspace = struct {
 16     phase: alloc_phase.capacity.Phase,
 17     capacity: capacity_mod.Capacity,
 18     bytes: []align(capacity_mod.storage_alignment) u8,
 19     scalars: std.ArrayList(model.Scalar),
 20     clusters: std.ArrayList(model.SourceCluster),
 21     ranges: std.ArrayList(model.SegmentRange),
 22 
 23     pub const Limits: type = capacity_mod.Limits;
 24     pub const Capacity: type = capacity_mod.Capacity;
 25     pub const Exhaustion: type = model.Exhaustion;
 26     pub const InitError = std.mem.Allocator.Error || capacity_mod.DeriveError;
 27 
 28     pub const claim: alloc_phase.capacity.Declaration = .{
 29         .source = .{
 30             .id = "filigree.fallback_workspace",
 31             .kind = .phase_static,
 32             .limit_source = .caller,
 33             .storage = .{
 34                 .covered = &.{
 35                     .{
 36                         .id = "decoded_fallback_scalars",
 37                         .lifetime = .steady,
 38                         .detail = "decoded scalar descriptors used for face coverage",
 39                     },
 40                     .{
 41                         .id = "grapheme_safe_fallback_clusters",
 42                         .lifetime = .steady,
 43                         .detail = "grapheme and joining-cluster descriptors",
 44                     },
 45                     .{
 46                         .id = "fallback_face_segment_ranges",
 47                         .lifetime = .steady,
 48                         .detail = "script and selected-face segment descriptors",
 49                     },
 50                 },
 51                 .excluded = &.{
 52                     "caller-owned source units and fallback candidates",
 53                     "shape engine, shape output, and script-run storage",
 54                     "caller-owned reported face segments",
 55                 },
 56             },
 57             .capacity = .{
 58                 .inputs = &.{
 59                     alloc_phase.capacity.bindInput(Limits, "max_source_units", "max_source_units"),
 60                 },
 61                 .type_selectors = &.{
 62                     alloc_phase.capacity.bindType(model.Scalar, "scalar"),
 63                     alloc_phase.capacity.bindType(model.SourceCluster, "sourcecluster"),
 64                     alloc_phase.capacity.bindType(model.SegmentRange, "segmentrange"),
 65                 },
 66                 .nodes = &.{
 67                     .{ .input = 0 },
 68                     .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 } } },
 69                     .{ .alignment = .{ .node = 1, .alignment = .{ .concrete_type = 1 } } },
 70                     .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 1 } } },
 71                     .{ .add = .{ .left = 2, .right = 3 } },
 72                     .{ .alignment = .{ .node = 4, .alignment = .{ .concrete_type = 2 } } },
 73                     .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 2 } } },
 74                     .{ .add = .{ .left = 5, .right = 6 } },
 75                 },
 76                 .assertions = &.{.{
 77                     .scope = .closure_total,
 78                     .measure = .retained,
 79                     .relation = .exact,
 80                     .expression = 7,
 81                 }},
 82             },
 83             .overload = .{
 84                 .kind = .reject_before_mutation,
 85                 .detail = "a max-plus-one source rejects before prior scalar, cluster, or face-range state changes",
 86             },
 87             .risks = .{
 88                 .transitive = .{
 89                     .status = .witnessed,
 90                     .detail = "fallback collection and segmentation use only activated typed regions",
 91                 },
 92                 .foreign = .{
 93                     .status = .excluded,
 94                     .detail = "workspace collection and segmentation cross no operating-system or foreign callback boundary",
 95                 },
 96             },
 97             .obligations = &.{
 98                 .{ .key = "filigree_fallback_workspace_capacity", .role = .capacity_model },
 99                 .{ .key = "filigree_fallback_workspace_acquisition", .role = .custom },
100                 .{ .key = "filigree_fallback_workspace_oom", .role = .custom },
101                 .{ .key = "filigree_fallback_workspace_boundaries", .role = .overload },
102                 .{ .key = "filigree_fallback_workspace_reuse", .role = .overload },
103                 .{ .key = "filigree_fallback_workspace_sealed_transitive_risk", .role = .transitive_risk },
104                 .{ .key = "filigree_fallback_workspace_sealed_foreign_risk", .role = .foreign_risk },
105                 .{ .key = "filigree_fallback_workspace_root", .role = .custom },
106             },
107         },
108         .bindings = .{
109             .owner = @This(),
110             .seal = .{
111                 .family = alloc_phase.capacity.selector(@This().activate),
112                 .premise = .{
113                     .class = .checked_semantic_fact,
114                     .authority = .checker,
115                 },
116             },
117             .teardown = .{
118                 .family = alloc_phase.capacity.selector(@This().deinit),
119                 .premise = .{
120                     .class = .checked_semantic_fact,
121                     .authority = .checker,
122                 },
123             },
124         },
125     };
126 
127     pub fn init(allocator: std.mem.Allocator, limits: Limits) InitError!Workspace {
128         const capacity = try Capacity.derive(limits);
129         const bytes = try allocator.alignedAlloc(
130             u8,
131             .fromByteUnits(capacity_mod.storage_alignment),
132             capacity.storage_bytes,
133         );
134         return .{
135             .phase = .initialization,
136             .capacity = capacity,
137             .bytes = bytes,
138             .scalars = .initBuffer(typedSlice(model.Scalar, bytes, capacity.scalar_offset, limits.max_source_units)),
139             .clusters = .initBuffer(typedSlice(model.SourceCluster, bytes, capacity.cluster_offset, limits.max_source_units)),
140             .ranges = .initBuffer(typedSlice(model.SegmentRange, bytes, capacity.range_offset, limits.max_source_units)),
141         };
142     }
143 
144     pub fn activate(self: *Workspace) void {
145         std.debug.assert(self.phase == .initialization);
146         self.assertStorage();
147         self.phase = .steady;
148     }
149 
150     pub fn deinit(self: *Workspace, allocator: std.mem.Allocator) void {
151         std.debug.assert(self.phase != .teardown);
152         self.assertStorage();
153         self.phase = .teardown;
154         allocator.free(self.bytes);
155         self.bytes = &.{};
156         self.scalars = .empty;
157         self.clusters = .empty;
158         self.ranges = .empty;
159     }
160 
161     pub fn begin(self: *Workspace, source_units: usize) Exhaustion!void {
162         std.debug.assert(self.phase == .steady);
163         if (source_units > self.capacity.limits.max_source_units) {
164             return error.SourceUnitCapacityExceeded;
165         }
166         self.reset();
167     }
168 
169     pub fn reset(self: *Workspace) void {
170         std.debug.assert(self.phase == .steady);
171         self.scalars.clearRetainingCapacity();
172         self.clusters.clearRetainingCapacity();
173         self.ranges.clearRetainingCapacity();
174     }
175 
176     pub fn status(self: *const Workspace) Status {
177         return .{
178             .phase = self.phase,
179             .storage_bytes = self.capacity.storage_bytes,
180             .max_source_units = self.capacity.limits.max_source_units,
181             .scalar_count = self.scalars.items.len,
182             .cluster_count = self.clusters.items.len,
183             .range_count = self.ranges.items.len,
184         };
185     }
186 
187     fn assertStorage(self: *const Workspace) void {
188         std.debug.assert(self.bytes.len == self.capacity.storage_bytes);
189         std.debug.assert(self.scalars.capacity == self.capacity.limits.max_source_units);
190         std.debug.assert(self.clusters.capacity == self.capacity.limits.max_source_units);
191         std.debug.assert(self.ranges.capacity == self.capacity.limits.max_source_units);
192         std.debug.assert(self.scalars.items.len <= self.scalars.capacity);
193         std.debug.assert(self.clusters.items.len <= self.clusters.capacity);
194         std.debug.assert(self.ranges.items.len <= self.ranges.capacity);
195     }
196 };
197 
198 comptime {
199     alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Workspace);
200 }
201 
202 fn typedSlice(
203     comptime T: type,
204     bytes: []align(capacity_mod.storage_alignment) u8,
205     offset: usize,
206     count: usize,
207 ) []T {
208     const byte_count = count * @sizeOf(T);
209     const region: []align(@alignOf(T)) u8 = @alignCast(bytes[offset..][0..byte_count]);
210     return std.mem.bytesAsSlice(T, region);
211 }
212 
213 fn activatedWorkspace(allocator: std.mem.Allocator, max_source_units: usize) !Workspace {
214     var workspace = try Workspace.init(allocator, .{ .max_source_units = max_source_units });
215     workspace.activate();
216     return workspace;
217 }
218 
219 fn checkInitFailures(allocator: std.mem.Allocator) !void {
220     var workspace = try Workspace.init(allocator, .{ .max_source_units = 13 });
221     workspace.deinit(allocator);
222 }
223 
224 test "fallback workspace acquires one exact region" {
225     comptime {
226         alloc_phase.capacity.record(
227             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_acquisition"),
228         );
229     }
230 
231     var counting = std.testing.FailingAllocator.init(std.testing.allocator, .{});
232     const limits = capacity_mod.Limits{ .max_source_units = 13 };
233     const capacity = try capacity_mod.Capacity.derive(limits);
234     var workspace = try Workspace.init(counting.allocator(), limits);
235     defer workspace.deinit(counting.allocator());
236 
237     try std.testing.expectEqual(@as(usize, 1), counting.alloc_index);
238     try std.testing.expectEqual(capacity.storage_bytes, counting.allocated_bytes);
239     workspace.activate();
240     const base = @intFromPtr(workspace.bytes.ptr);
241     try std.testing.expectEqual(base + capacity.scalar_offset, @intFromPtr(workspace.scalars.allocatedSlice().ptr));
242     try std.testing.expectEqual(base + capacity.cluster_offset, @intFromPtr(workspace.clusters.allocatedSlice().ptr));
243     try std.testing.expectEqual(base + capacity.range_offset, @intFromPtr(workspace.ranges.allocatedSlice().ptr));
244 }
245 
246 test "fallback workspace retries after its only allocation failure" {
247     comptime {
248         alloc_phase.capacity.record(
249             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_oom"),
250         );
251     }
252     try std.testing.checkAllAllocationFailures(std.testing.allocator, checkInitFailures, .{});
253 }
254 
255 test "fallback workspace rejects max plus one transactionally and reuses storage" {
256     comptime {
257         alloc_phase.capacity.record(
258             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_boundaries"),
259         );
260     }
261     comptime {
262         alloc_phase.capacity.record(
263             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_reuse"),
264         );
265     }
266     comptime {
267         alloc_phase.capacity.record(
268             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_sealed_transitive_risk"),
269         );
270     }
271     comptime {
272         alloc_phase.capacity.record(
273             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_sealed_foreign_risk"),
274         );
275     }
276 
277     var workspace = try activatedWorkspace(std.testing.allocator, 3);
278     defer workspace.deinit(std.testing.allocator);
279     try workspace.begin(3);
280     workspace.scalars.appendAssumeCapacity(.{ .codepoint = 'A', .start = 0, .end = 1 });
281     const prior = workspace.scalars.items[0];
282     const pointer = workspace.scalars.allocatedSlice().ptr;
283     const status = workspace.status();
284 
285     try std.testing.expectError(error.SourceUnitCapacityExceeded, workspace.begin(4));
286     try std.testing.expectEqual(prior, workspace.scalars.items[0]);
287     try std.testing.expectEqual(status, workspace.status());
288     try std.testing.expectEqual(pointer, workspace.scalars.allocatedSlice().ptr);
289 
290     try workspace.begin(3);
291     try std.testing.expectEqual(@as(usize, 0), workspace.status().scalar_count);
292     try std.testing.expectEqual(pointer, workspace.scalars.allocatedSlice().ptr);
293 }
294 
295 test "fallback workspace is exported through its namespace root" {
296     comptime {
297         alloc_phase.capacity.record(
298             alloc_phase.capacity.witness(Workspace, "filigree_fallback_workspace_root"),
299         );
300     }
301     try std.testing.expect(@import("root.zig").Workspace == Workspace);
302 }