lib/gui/src/surface/storage.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const alloc_phase = @import("alloc_phase");
   3 const capacity_mod = @import("capacity.zig");
   4 const command = @import("command.zig");
   5 const decode = @import("decode.zig");
   6 const gui = @import("../root.zig");
   7 const survey = @import("survey.zig");
   8 const types = @import("types.zig");
   9 
  10 const Surface = types.Surface;
  11 const UiImage = gui.model.UiImage;
  12 const UiImageSet = gui.model.UiImageSet;
  13 const UiNode = gui.model.UiNode;
  14 const UiSurfaceTree = gui.model.UiSurfaceTree;
  15 const UiText = gui.model.UiText;
  16 const UiTextRun = gui.model.UiTextRun;
  17 const UiTextStyle = gui.model.UiTextStyle;
  18 
  19 pub const Exhaustion = survey.Error || error{SurfaceCapacityExceeded};
  20 pub const CloneError = Exhaustion;
  21 
  22 pub const PlacementStatus = struct {
  23     capacity: capacity_mod.Capacity,
  24     facts: capacity_mod.Facts,
  25     has_surface: bool,
  26 };
  27 
  28 pub const Placement = struct {
  29     limits: capacity_mod.Limits,
  30     bytes: []align(capacity_mod.storage_alignment) u8,
  31     surface: ?Surface = null,
  32     facts: capacity_mod.Facts = .{},
  33 
  34     pub fn init(
  35         bytes: []align(capacity_mod.storage_alignment) u8,
  36         capacity: capacity_mod.Capacity,
  37     ) Placement {
  38         std.debug.assert(bytes.len == capacity.storage_bytes);
  39         return .{ .limits = capacity.toLimits(), .bytes = bytes };
  40     }
  41 
  42     pub inline fn cloneSurface(self: *Placement, src: Surface) CloneError!Surface {
  43         const facts = try survey.surface(src);
  44         if (!self.limits.admits(facts)) return error.SurfaceCapacityExceeded;
  45         return self.placeSurface(src, facts);
  46     }
  47 
  48     pub fn cloneCommandSurface(
  49         self: *Placement,
  50         src: *const command.CommandUiSurface,
  51     ) CloneError!Surface {
  52         const facts = try survey.commandSurface(src);
  53         if (!self.limits.admits(facts)) return error.SurfaceCapacityExceeded;
  54         return self.placeCommandSurface(src, facts);
  55     }
  56 
  57     pub fn reset(self: *Placement) void {
  58         self.surface = null;
  59         self.facts = .{};
  60     }
  61 
  62     pub fn current(self: *const Placement) ?Surface {
  63         return self.surface;
  64     }
  65 
  66     pub inline fn currentPtr(self: *const Placement) ?*const Surface {
  67         if (self.surface) |*value| return value;
  68         return null;
  69     }
  70 
  71     pub inline fn hasSurface(self: *const Placement) bool {
  72         return self.surface != null;
  73     }
  74 
  75     pub fn status(self: *const Placement) PlacementStatus {
  76         return .{
  77             .capacity = self.derivedCapacity(),
  78             .facts = self.facts,
  79             .has_surface = self.surface != null,
  80         };
  81     }
  82 
  83     fn derivedCapacity(self: *const Placement) capacity_mod.Capacity {
  84         return capacity_mod.Capacity.derive(self.limits) catch unreachable;
  85     }
  86 
  87     fn placeSurface(
  88         self: *Placement,
  89         src: Surface,
  90         facts: capacity_mod.Facts,
  91     ) Surface {
  92         var cursor = Cursor.init(self, self.derivedCapacity());
  93         const tree = cursor.surface();
  94         tree.* = .{
  95             .available_size = src.tree.available_size,
  96             .root = cursor.cloneNode(&src.tree.root),
  97         };
  98         const result = Surface{
  99             .tree = tree,
 100             .images = cursor.cloneImages(src.images),
 101         };
 102         cursor.finish(facts);
 103         self.surface = result;
 104         self.facts = facts;
 105         return result;
 106     }
 107 
 108     fn placeCommandSurface(
 109         self: *Placement,
 110         src: *const command.CommandUiSurface,
 111         facts: capacity_mod.Facts,
 112     ) Surface {
 113         var cursor = Cursor.init(self, self.derivedCapacity());
 114         const tree = cursor.surface();
 115         tree.* = .{
 116             .available_size = .{
 117                 .width = src.available_width,
 118                 .height = src.available_height,
 119             },
 120             .root = cursor.cloneCommandNode(src.root_ptr.?),
 121         };
 122         const result = Surface{
 123             .tree = tree,
 124             .images = cursor.cloneCommandImages(src),
 125         };
 126         cursor.finish(facts);
 127         self.surface = result;
 128         self.facts = facts;
 129         return result;
 130     }
 131 };
 132 
 133 const Cursor = struct {
 134     surface_offset: usize,
 135     bytes: []align(capacity_mod.storage_alignment) u8,
 136     nodes: []UiNode,
 137     nodes_used: usize = 0,
 138     runs: []UiTextRun,
 139     runs_used: usize = 0,
 140     styles: []UiTextStyle,
 141     styles_used: usize = 0,
 142     images: []UiImage,
 143     images_used: usize = 0,
 144     image_pixels: []u32,
 145     image_pixels_used: usize = 0,
 146     semantics: []u8,
 147     semantics_used: usize = 0,
 148 
 149     fn init(placement: *Placement, capacity: capacity_mod.Capacity) Cursor {
 150         return .{
 151             .surface_offset = capacity.surface_offset,
 152             .bytes = placement.bytes,
 153             .nodes = typedSlice(
 154                 UiNode,
 155                 placement.bytes,
 156                 capacity.node_offset,
 157                 capacity.node_slots,
 158             ),
 159             .runs = typedSlice(
 160                 UiTextRun,
 161                 placement.bytes,
 162                 capacity.run_offset,
 163                 capacity.run_slots,
 164             ),
 165             .styles = typedSlice(
 166                 UiTextStyle,
 167                 placement.bytes,
 168                 capacity.style_offset,
 169                 capacity.style_slots,
 170             ),
 171             .images = typedSlice(
 172                 UiImage,
 173                 placement.bytes,
 174                 capacity.image_offset,
 175                 capacity.image_slots,
 176             ),
 177             .image_pixels = typedSlice(
 178                 u32,
 179                 placement.bytes,
 180                 capacity.image_pixel_offset,
 181                 capacity.image_pixel_slots,
 182             ),
 183             .semantics = placement.bytes[capacity.semantic_offset..][0..capacity.semantic_bytes],
 184         };
 185     }
 186 
 187     fn surface(self: *Cursor) *UiSurfaceTree {
 188         return typedOne(UiSurfaceTree, self.bytes, self.surface_offset);
 189     }
 190 
 191     fn cloneNode(self: *Cursor, src: *const UiNode) UiNode {
 192         var node = UiNode{
 193             .widget_id = src.widget_id,
 194             .kind = src.kind,
 195             .style = src.style,
 196             .size = src.size,
 197             .paint = src.paint,
 198             .scroll = src.scroll,
 199             .focusable = src.focusable,
 200             .layer = src.layer,
 201             .text_selection = src.text_selection,
 202             .state_flags = src.state_flags,
 203         };
 204         if (src.text) |text| node.text = self.cloneText(text);
 205         node.action = self.cloneBytes(src.action);
 206         node.role = self.cloneBytes(src.role);
 207         if (src.children.len > 0) {
 208             const children = self.carveNodes(src.children.len);
 209             node.children = children;
 210             for (src.children, children) |*source, *destination| {
 211                 destination.* = self.cloneNode(source);
 212             }
 213         }
 214         return node;
 215     }
 216 
 217     fn cloneCommandNode(self: *Cursor, src: *const command.CommandUiNode) UiNode {
 218         var node = UiNode{
 219             .widget_id = src.widget_id,
 220             .kind = decode.widgetKind(src.kind) catch unreachable,
 221             .style = decode.commandStyle(src.style) catch unreachable,
 222             .size = .{
 223                 .width = decode.optionalF32(src.size.width),
 224                 .height = decode.optionalF32(src.size.height),
 225             },
 226             .paint = decode.commandPaint(src.paint),
 227             .scroll = decode.commandScroll(src.style) catch unreachable,
 228             .focusable = src.focusable != 0,
 229             .state_flags = src.state_flags,
 230         };
 231         if (src.text_ptr) |text| node.text = self.cloneCommandText(text);
 232         node.text_selection = decode.commandTextSelection(
 233             src.text_selection,
 234             if (node.text) |text| text.content.len else 0,
 235         ) catch unreachable;
 236         if (src.action_len > 0) node.action = self.cloneBytes(src.action_ptr.?[0..src.action_len]);
 237         if (src.role_len > 0) node.role = self.cloneBytes(src.role_ptr.?[0..src.role_len]);
 238         if (src.children_len > 0) {
 239             const source = src.children_ptr.?[0..src.children_len];
 240             const children = self.carveNodes(src.children_len);
 241             node.children = children;
 242             for (source, children) |*source_child, *destination| {
 243                 destination.* = self.cloneCommandNode(source_child);
 244             }
 245         }
 246         return node;
 247     }
 248 
 249     fn cloneCommandText(self: *Cursor, src: *const command.CommandUiText) UiText {
 250         return .{
 251             .content = if (src.content_len == 0) &.{} else self.cloneBytes(src.content_ptr.?[0..src.content_len]),
 252             .runs = self.cloneCommandRuns(src),
 253             .styles = self.cloneCommandStyles(src),
 254             .font_asset_id = src.font_asset_id,
 255             .font_weight = decode.normalizeFontWeight(src.font_weight),
 256             .point_size = src.point_size,
 257             .line_height = src.line_height,
 258             .wrap_width = src.wrap_width,
 259             .horizontal_align = decode.textAlign(src.horizontal_align) catch unreachable,
 260             .vertical_align = decode.textAlign(src.vertical_align) catch unreachable,
 261         };
 262     }
 263 
 264     fn cloneText(self: *Cursor, src: UiText) UiText {
 265         return .{
 266             .content = self.cloneBytes(src.content),
 267             .runs = self.cloneRuns(src.runs),
 268             .styles = self.cloneStyles(src.styles),
 269             .font_asset_id = src.font_asset_id,
 270             .font_weight = src.font_weight,
 271             .point_size = src.point_size,
 272             .line_height = src.line_height,
 273             .wrap_width = src.wrap_width,
 274             .horizontal_align = src.horizontal_align,
 275             .vertical_align = src.vertical_align,
 276         };
 277     }
 278 
 279     fn carveNodes(self: *Cursor, count: usize) []UiNode {
 280         std.debug.assert(self.nodes_used + count <= self.nodes.len);
 281         const result = self.nodes[self.nodes_used..][0..count];
 282         self.nodes_used += count;
 283         return result;
 284     }
 285 
 286     fn cloneRuns(self: *Cursor, source: []const UiTextRun) []const UiTextRun {
 287         if (source.len == 0) return &.{};
 288         const result = self.carveRuns(source.len);
 289         @memcpy(result, source);
 290         return result;
 291     }
 292 
 293     fn cloneCommandRuns(self: *Cursor, source: *const command.CommandUiText) []const UiTextRun {
 294         if (source.runs_len == 0) return &.{};
 295         const input = source.runs_ptr.?[0..source.runs_len];
 296         const result = self.carveRuns(input.len);
 297         for (input, result) |run, *destination| destination.* = decode.commandTextRun(run);
 298         return result;
 299     }
 300 
 301     fn carveRuns(self: *Cursor, count: usize) []UiTextRun {
 302         std.debug.assert(self.runs_used + count <= self.runs.len);
 303         const result = self.runs[self.runs_used..][0..count];
 304         self.runs_used += count;
 305         return result;
 306     }
 307 
 308     fn cloneStyles(self: *Cursor, source: []const UiTextStyle) []const UiTextStyle {
 309         if (source.len == 0) return &.{};
 310         const result = self.carveStyles(source.len);
 311         @memcpy(result, source);
 312         return result;
 313     }
 314 
 315     fn cloneCommandStyles(self: *Cursor, source: *const command.CommandUiText) []const UiTextStyle {
 316         if (source.styles_len == 0) return &.{};
 317         const input = source.styles_ptr.?[0..source.styles_len];
 318         const result = self.carveStyles(input.len);
 319         for (input, result) |style, *destination| destination.* = decode.commandTextStyle(style);
 320         return result;
 321     }
 322 
 323     fn cloneImages(self: *Cursor, source: UiImageSet) UiImageSet {
 324         if (source.images.len == 0) return .{};
 325         const result = self.carveImages(source.images.len);
 326         for (source.images, result) |image, *destination| {
 327             const count = image.pixelCount();
 328             destination.* = .{
 329                 .width = image.width,
 330                 .height = image.height,
 331                 .pixels = self.cloneImagePixels(image.pixels[0..count]),
 332             };
 333         }
 334         return .{ .images = result };
 335     }
 336 
 337     fn cloneCommandImages(
 338         self: *Cursor,
 339         source: *const command.CommandUiSurface,
 340     ) UiImageSet {
 341         if (source.images_len == 0) return .{};
 342         const input = source.images_ptr.?[0..source.images_len];
 343         const result = self.carveImages(input.len);
 344         for (input, result) |image, *destination| {
 345             const count = @as(usize, image.width) * @as(usize, image.height);
 346             destination.* = .{
 347                 .width = image.width,
 348                 .height = image.height,
 349                 .pixels = self.cloneImagePixels(image.pixels_ptr.?[0..count]),
 350             };
 351         }
 352         return .{ .images = result };
 353     }
 354 
 355     fn carveImages(self: *Cursor, count: usize) []UiImage {
 356         std.debug.assert(self.images_used + count <= self.images.len);
 357         const result = self.images[self.images_used..][0..count];
 358         self.images_used += count;
 359         return result;
 360     }
 361 
 362     fn cloneImagePixels(self: *Cursor, source: []const u32) []const u32 {
 363         std.debug.assert(self.image_pixels_used + source.len <= self.image_pixels.len);
 364         const result = self.image_pixels[self.image_pixels_used..][0..source.len];
 365         @memcpy(result, source);
 366         self.image_pixels_used += source.len;
 367         return result;
 368     }
 369 
 370     fn carveStyles(self: *Cursor, count: usize) []UiTextStyle {
 371         std.debug.assert(self.styles_used + count <= self.styles.len);
 372         const result = self.styles[self.styles_used..][0..count];
 373         self.styles_used += count;
 374         return result;
 375     }
 376 
 377     fn cloneBytes(self: *Cursor, source: []const u8) []const u8 {
 378         if (source.len == 0) return &.{};
 379         std.debug.assert(self.semantics_used + source.len <= self.semantics.len);
 380         const result = self.semantics[self.semantics_used..][0..source.len];
 381         @memcpy(result, source);
 382         self.semantics_used += source.len;
 383         return result;
 384     }
 385 
 386     fn finish(self: *const Cursor, facts: capacity_mod.Facts) void {
 387         std.debug.assert(self.nodes_used + 1 == facts.nodes);
 388         std.debug.assert(self.runs_used == facts.runs);
 389         std.debug.assert(self.styles_used == facts.styles);
 390         std.debug.assert(self.images_used == facts.images);
 391         std.debug.assert(self.image_pixels_used == facts.image_pixels);
 392         std.debug.assert(self.semantics_used == facts.semantic_bytes);
 393     }
 394 };
 395 
 396 pub const Storage = struct {
 397     phase: alloc_phase.capacity.Phase,
 398     capacity: capacity_mod.Capacity,
 399     bytes: []align(capacity_mod.storage_alignment) u8,
 400     placement: Placement,
 401 
 402     pub const Limits: type = capacity_mod.Limits;
 403     pub const Capacity: type = capacity_mod.Capacity;
 404     pub const Exhaustion: type = @import("storage.zig").Exhaustion;
 405     pub const InitError = std.mem.Allocator.Error || capacity_mod.DeriveError;
 406 
 407     pub const claim: alloc_phase.capacity.Declaration = .{
 408         .source = .{
 409             .id = "gui.surface_clone_storage",
 410             .kind = .phase_static,
 411             .limit_source = .caller,
 412             .storage = .{
 413                 .covered = &.{
 414                     .{
 415                         .id = "one_cloned_uisurfacetree_header_and_caller_sized_ty_33bebc07fe23",
 416                         .lifetime = .steady,
 417                         .detail = "one cloned UiSurfaceTree header and caller-sized typed node arena",
 418                     },
 419                     .{
 420                         .id = "caller_sized_cloned_uitextrun_arena",
 421                         .lifetime = .steady,
 422                         .detail = "caller-sized cloned UiTextRun arena",
 423                     },
 424                     .{
 425                         .id = "caller_sized_cloned_uitextstyle_arena",
 426                         .lifetime = .steady,
 427                         .detail = "caller-sized cloned UiTextStyle arena",
 428                     },
 429                     .{
 430                         .id = "caller_sized_cloned_ui_image_descriptor_arena",
 431                         .lifetime = .steady,
 432                         .detail = "caller-sized cloned UI image descriptor arena",
 433                     },
 434                     .{
 435                         .id = "caller_sized_cloned_packed_rgba8_image_pixels",
 436                         .lifetime = .steady,
 437                         .detail = "caller-sized cloned packed RGBA8 image pixels",
 438                     },
 439                     .{
 440                         .id = "caller_sized_cloned_text_action_and_role_bytes",
 441                         .lifetime = .steady,
 442                         .detail = "caller-sized cloned text action and role bytes",
 443                     },
 444                 },
 445                 .excluded = &.{
 446                     "caller-owned source trees and command pointer memory",
 447                     "sdfii retained root lookup and transactional replacement slots",
 448                     "frame layout render input and paint storage",
 449                 },
 450             },
 451             .capacity = .{
 452                 .inputs = &.{
 453                     alloc_phase.capacity.bindInput(Limits, "nodes", "nodes"),
 454                     alloc_phase.capacity.bindInput(Limits, "runs", "runs"),
 455                     alloc_phase.capacity.bindInput(Limits, "styles", "styles"),
 456                     alloc_phase.capacity.bindInput(Limits, "images", "images"),
 457                     alloc_phase.capacity.bindInput(Limits, "image_pixels", "image_pixels"),
 458                     alloc_phase.capacity.bindInput(Limits, "semantic_bytes", "semantic_bytes"),
 459                 },
 460                 .type_selectors = &.{
 461                     alloc_phase.capacity.bindType(UiSurfaceTree, "uisurfacetree"),
 462                     alloc_phase.capacity.bindType(UiNode, "uinode"),
 463                     alloc_phase.capacity.bindType(UiTextRun, "uitextrun"),
 464                     alloc_phase.capacity.bindType(UiTextStyle, "uitextstyle"),
 465                     alloc_phase.capacity.bindType(UiImage, "uiimage"),
 466                     alloc_phase.capacity.bindType(u32, "u32"),
 467                 },
 468                 .nodes = &.{
 469                     .{ .constant = 1 },
 470                     .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 } } },
 471                     .{ .alignment = .{ .node = 1, .alignment = .{ .literal = 16 } } },
 472                     .{ .input = 0 },
 473                     .{ .scale = .{ .node = 3, .coefficient = .{ .size_of_concrete_type = 1 } } },
 474                     .{ .alignment = .{ .node = 4, .alignment = .{ .literal = 16 } } },
 475                     .{ .input = 1 },
 476                     .{ .scale = .{ .node = 6, .coefficient = .{ .size_of_concrete_type = 2 } } },
 477                     .{ .alignment = .{ .node = 7, .alignment = .{ .literal = 16 } } },
 478                     .{ .input = 2 },
 479                     .{ .scale = .{ .node = 9, .coefficient = .{ .size_of_concrete_type = 3 } } },
 480                     .{ .alignment = .{ .node = 10, .alignment = .{ .literal = 16 } } },
 481                     .{ .input = 3 },
 482                     .{ .scale = .{ .node = 12, .coefficient = .{ .size_of_concrete_type = 4 } } },
 483                     .{ .alignment = .{ .node = 13, .alignment = .{ .literal = 16 } } },
 484                     .{ .input = 4 },
 485                     .{ .scale = .{ .node = 15, .coefficient = .{ .size_of_concrete_type = 5 } } },
 486                     .{ .alignment = .{ .node = 16, .alignment = .{ .literal = 16 } } },
 487                     .{ .input = 5 },
 488                     .{ .alignment = .{ .node = 18, .alignment = .{ .literal = 16 } } },
 489                     .{ .add = .{ .left = 2, .right = 5 } },
 490                     .{ .add = .{ .left = 20, .right = 8 } },
 491                     .{ .add = .{ .left = 21, .right = 11 } },
 492                     .{ .add = .{ .left = 22, .right = 14 } },
 493                     .{ .add = .{ .left = 23, .right = 17 } },
 494                     .{ .add = .{ .left = 24, .right = 19 } },
 495                 },
 496                 .assertions = &.{.{
 497                     .scope = .closure_total,
 498                     .measure = .retained,
 499                     .relation = .upper_bound,
 500                     .expression = 25,
 501                 }},
 502             },
 503             .overload = .{
 504                 .kind = .reject_before_mutation,
 505                 .detail = "depth invalid command facts and max-plus-one node run style image pixel or semantic demand reject during survey before placement state changes",
 506             },
 507             .risks = .{
 508                 .transitive = .{
 509                     .status = .witnessed,
 510                     .detail = "typed native and command placement traversals carry no allocator capability after storage activation",
 511                 },
 512                 .foreign = .{
 513                     .status = .open,
 514                     .detail = "command trees and image tables are foreign pointer graphs whose memory must remain immutable and valid through survey and placement",
 515                 },
 516             },
 517             .obligations = &.{
 518                 .{ .key = "gui_surface_clone_capacity", .role = .capacity_model },
 519                 .{ .key = "gui_surface_clone_survey", .role = .overload },
 520                 .{ .key = "gui_surface_clone_acquisition", .role = .custom },
 521                 .{ .key = "gui_surface_clone_boundary", .role = .overload },
 522                 .{ .key = "gui_surface_clone_command", .role = .foreign_risk },
 523                 .{ .key = "gui_surface_clone_images", .role = .overload },
 524                 .{ .key = "gui_surface_clone_command_images_overload", .role = .overload },
 525                 .{ .key = "gui_surface_clone_command_images_foreign_risk", .role = .foreign_risk },
 526                 .{ .key = "gui_surface_clone_sealed", .role = .transitive_risk },
 527             },
 528         },
 529         .bindings = .{
 530             .owner = @This(),
 531             .seal = .{
 532                 .family = alloc_phase.capacity.selector(@This().activate),
 533                 .premise = .{
 534                     .class = .checked_semantic_fact,
 535                     .authority = .checker,
 536                 },
 537             },
 538             .teardown = .{
 539                 .family = alloc_phase.capacity.selector(@This().deinit),
 540                 .premise = .{
 541                     .class = .checked_semantic_fact,
 542                     .authority = .checker,
 543                 },
 544             },
 545         },
 546     };
 547 
 548     pub fn init(allocator: std.mem.Allocator, limits: Limits) InitError!Storage {
 549         const capacity = try Capacity.derive(limits);
 550         const bytes = try allocator.alignedAlloc(
 551             u8,
 552             .fromByteUnits(capacity_mod.storage_alignment),
 553             capacity.storage_bytes,
 554         );
 555         return .{
 556             .phase = .initialization,
 557             .capacity = capacity,
 558             .bytes = bytes,
 559             .placement = Placement.init(bytes, capacity),
 560         };
 561     }
 562 
 563     pub fn activate(self: *Storage) void {
 564         std.debug.assert(self.phase == .initialization);
 565         self.assertStorage();
 566         self.phase = .steady;
 567     }
 568 
 569     pub fn cloneSurface(self: *Storage, src: Surface) CloneError!Surface {
 570         std.debug.assert(self.phase == .steady);
 571         self.assertStorage();
 572         return self.placement.cloneSurface(src);
 573     }
 574 
 575     pub fn cloneCommandSurface(
 576         self: *Storage,
 577         src: *const command.CommandUiSurface,
 578     ) CloneError!Surface {
 579         std.debug.assert(self.phase == .steady);
 580         self.assertStorage();
 581         return self.placement.cloneCommandSurface(src);
 582     }
 583 
 584     pub fn current(self: *const Storage) ?Surface {
 585         return self.placement.current();
 586     }
 587 
 588     pub fn status(self: *const Storage) PlacementStatus {
 589         self.assertStorage();
 590         return self.placement.status();
 591     }
 592 
 593     pub fn deinit(self: *Storage, allocator: std.mem.Allocator) void {
 594         std.debug.assert(self.phase != .teardown);
 595         self.assertStorage();
 596         self.phase = .teardown;
 597         allocator.free(self.bytes);
 598         self.bytes = &.{};
 599         self.placement.bytes = &.{};
 600         self.placement.reset();
 601     }
 602 
 603     fn assertStorage(self: *const Storage) void {
 604         std.debug.assert(self.bytes.len == self.capacity.storage_bytes);
 605         std.debug.assert(self.placement.bytes.ptr == self.bytes.ptr);
 606         std.debug.assert(self.placement.bytes.len == self.bytes.len);
 607         std.debug.assert(std.meta.eql(self.placement.limits, self.capacity.toLimits()));
 608     }
 609 };
 610 
 611 fn typedOne(
 612     comptime T: type,
 613     bytes: []align(capacity_mod.storage_alignment) u8,
 614     offset: usize,
 615 ) *T {
 616     const region: *align(@alignOf(T)) [@sizeOf(T)]u8 = @ptrCast(@alignCast(bytes[offset..][0..@sizeOf(T)]));
 617     return @ptrCast(region);
 618 }
 619 
 620 fn typedSlice(
 621     comptime T: type,
 622     bytes: []align(capacity_mod.storage_alignment) u8,
 623     offset: usize,
 624     count: usize,
 625 ) []T {
 626     const byte_count = count * @sizeOf(T);
 627     const region: []align(@alignOf(T)) u8 = @alignCast(bytes[offset..][0..byte_count]);
 628     return std.mem.bytesAsSlice(T, region);
 629 }
 630 
 631 fn checkInitFailures(allocator: std.mem.Allocator) !void {
 632     var storage = try Storage.init(allocator, .{ .nodes = 7, .semantic_bytes = 33 });
 633     storage.deinit(allocator);
 634 }
 635 
 636 test "surface clone storage acquires one exact aligned region" {
 637     comptime {
 638         @stardustClaim(
 639             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_acquisition"),
 640             null,
 641             null,
 642             null,
 643             null,
 644             null,
 645             null,
 646         );
 647     }
 648 
 649     var counting = std.testing.FailingAllocator.init(std.testing.allocator, .{});
 650     var storage = try Storage.init(counting.allocator(), .{ .nodes = 7, .semantic_bytes = 33 });
 651     defer storage.deinit(counting.allocator());
 652     try std.testing.expectEqual(@as(usize, 1), counting.alloc_index);
 653     try std.testing.expectEqual(storage.capacity.storage_bytes, counting.allocated_bytes);
 654 }
 655 
 656 test "surface clone storage retries after every allocation failure" {
 657     try std.testing.checkAllAllocationFailures(std.testing.allocator, checkInitFailures, .{});
 658 }
 659 
 660 test "surface clone storage owns nested surface slices" {
 661     const allocator = std.testing.allocator;
 662     var source_text = try allocator.dupe(u8, "Run");
 663     defer allocator.free(source_text);
 664     var source_runs = try allocator.dupe(UiTextRun, &.{.{
 665         .byte_start = 0,
 666         .byte_end = 3,
 667         .style_slot = 1,
 668         .foreground = .{ .r = 190, .g = 30, .b = 20 },
 669         .underline = true,
 670     }});
 671     defer allocator.free(source_runs);
 672     var source_styles = try allocator.dupe(UiTextStyle, &.{
 673         .{ .font_asset_id = 8, .point_size = 18 },
 674     });
 675     defer allocator.free(source_styles);
 676     var source_action = try allocator.dupe(u8, "chrome.quick-bar.command.run");
 677     defer allocator.free(source_action);
 678     var children = [_]UiNode{.{
 679         .widget_id = 2,
 680         .kind = .button,
 681         .layer = 7,
 682         .size = .{ .width = 40, .height = 20 },
 683         .text = .{ .content = source_text, .runs = source_runs, .styles = source_styles },
 684         .action = source_action,
 685     }};
 686     const surface = UiSurfaceTree{
 687         .available_size = .{ .width = 200, .height = 40 },
 688         .root = .{ .widget_id = 1, .children = &children },
 689     };
 690     const facts = try survey.surface(.{ .tree = &surface });
 691     var storage = try Storage.init(allocator, .{
 692         .nodes = facts.nodes,
 693         .runs = facts.runs,
 694         .styles = facts.styles,
 695         .semantic_bytes = facts.semantic_bytes,
 696     });
 697     defer storage.deinit(allocator);
 698     storage.activate();
 699     const cloned = try storage.cloneSurface(.{ .tree = &surface });
 700 
 701     source_text[0] = 'X';
 702     source_runs[0].foreground.?.r = 0;
 703     source_styles[0].point_size = 9;
 704     source_action[0] = 'x';
 705 
 706     try std.testing.expectEqual(@as(f32, 200), cloned.tree.available_size.width);
 707     try std.testing.expectEqual(@as(usize, 1), cloned.tree.root.children.len);
 708     try std.testing.expectEqual(@as(u8, 7), cloned.tree.root.children[0].layer);
 709     try std.testing.expectEqualStrings("Run", cloned.tree.root.children[0].text.?.content);
 710     try std.testing.expectEqual(@as(usize, 1), cloned.tree.root.children[0].text.?.runs.len);
 711     try std.testing.expectEqual(@as(u16, 1), cloned.tree.root.children[0].text.?.runs[0].style_slot);
 712     try std.testing.expectEqual(@as(f64, 18), cloned.tree.root.children[0].text.?.styles[0].point_size);
 713     try std.testing.expectEqual(@as(u8, 190), cloned.tree.root.children[0].text.?.runs[0].foreground.?.r);
 714     try std.testing.expect(cloned.tree.root.children[0].text.?.runs[0].underline);
 715     try std.testing.expectEqualStrings("chrome.quick-bar.command.run", cloned.tree.root.children[0].action);
 716 }
 717 
 718 test "surface clone storage rejects max plus one before replacing its current tree" {
 719     comptime {
 720         @stardustClaim(
 721             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_boundary"),
 722             null,
 723             null,
 724             null,
 725             null,
 726             null,
 727             null,
 728         );
 729     }
 730 
 731     const initial = UiSurfaceTree{
 732         .available_size = .{ .width = 10, .height = 10 },
 733         .root = .{ .widget_id = 7, .text = .{ .content = "1234" } },
 734     };
 735     const extra = [_]UiNode{.{ .widget_id = 9 }};
 736     const too_many = UiSurfaceTree{
 737         .available_size = .{ .width = 10, .height = 10 },
 738         .root = .{ .widget_id = 8, .text = .{ .content = "1234" }, .children = &extra },
 739     };
 740     const too_many_bytes = UiSurfaceTree{
 741         .available_size = .{ .width = 10, .height = 10 },
 742         .root = .{ .widget_id = 8, .text = .{ .content = "12345" } },
 743     };
 744     var storage = try Storage.init(std.testing.allocator, .{ .nodes = 1, .semantic_bytes = 4 });
 745     defer storage.deinit(std.testing.allocator);
 746     storage.activate();
 747     const cloned = try storage.cloneSurface(.{ .tree = &initial });
 748     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneSurface(.{ .tree = &too_many }));
 749     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneSurface(.{ .tree = &too_many_bytes }));
 750     try std.testing.expectEqual(@as(u64, 7), cloned.tree.root.widget_id);
 751     try std.testing.expectEqualStrings("1234", cloned.tree.root.text.?.content);
 752     try std.testing.expectEqual(@as(u64, 7), storage.current().?.tree.root.widget_id);
 753 }
 754 
 755 test "surface clone command survey rejects invalid input before replacement" {
 756     comptime {
 757         @stardustClaim(
 758             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_command"),
 759             null,
 760             null,
 761             null,
 762             null,
 763             null,
 764             null,
 765         );
 766     }
 767 
 768     const initial = UiSurfaceTree{
 769         .available_size = .{ .width = 10, .height = 10 },
 770         .root = .{ .widget_id = 7, .text = .{ .content = "1234" } },
 771     };
 772     var invalid_root = std.mem.zeroes(command.CommandUiNode);
 773     invalid_root.kind = 255;
 774     const invalid = command.CommandUiSurface{
 775         .available_width = 10,
 776         .available_height = 10,
 777         .root_ptr = &invalid_root,
 778         .images_ptr = null,
 779         .images_len = 0,
 780     };
 781     var storage = try Storage.init(std.testing.allocator, .{ .nodes = 1, .semantic_bytes = 4 });
 782     defer storage.deinit(std.testing.allocator);
 783     storage.activate();
 784     _ = try storage.cloneSurface(.{ .tree = &initial });
 785     try std.testing.expectError(error.InvalidCommand, storage.cloneCommandSurface(&invalid));
 786     try std.testing.expectEqual(@as(u64, 7), storage.current().?.tree.root.widget_id);
 787     try std.testing.expectEqualStrings("1234", storage.current().?.tree.root.text.?.content);
 788 }
 789 
 790 test "surface command decodes linear gradient paint" {
 791     var root = std.mem.zeroes(command.CommandUiNode);
 792     root.widget_id = 7;
 793     root.paint.linear_gradient = .{
 794         .is_set = 1,
 795         .start = .{ .x = std.math.nan(f32), .y = 0.25 },
 796         .end = .{ .x = 0.8, .y = std.math.inf(f32) },
 797         .start_color = .{ .r = 10, .g = 20, .b = 30, .a = 210 },
 798         .end_color = .{ .r = 90, .g = 120, .b = 180, .a = 160 },
 799     };
 800     const source = command.CommandUiSurface{
 801         .available_width = 20,
 802         .available_height = 12,
 803         .root_ptr = &root,
 804         .images_ptr = null,
 805         .images_len = 0,
 806     };
 807     const facts = try survey.commandSurface(&source);
 808     var storage = try Storage.init(std.testing.allocator, .{
 809         .nodes = facts.nodes,
 810         .runs = facts.runs,
 811         .styles = facts.styles,
 812         .semantic_bytes = facts.semantic_bytes,
 813     });
 814     defer storage.deinit(std.testing.allocator);
 815     storage.activate();
 816     const cloned = try storage.cloneCommandSurface(&source);
 817     const gradient = cloned.tree.root.paint.linear_gradient.?;
 818     try std.testing.expectEqual(@as(f32, 0), gradient.start.x);
 819     try std.testing.expectEqual(@as(f32, 0.25), gradient.start.y);
 820     try std.testing.expectEqual(@as(f32, 0.8), gradient.end.x);
 821     try std.testing.expectEqual(@as(f32, 0), gradient.end.y);
 822     try std.testing.expectEqual(@as(u8, 10), gradient.start_color.r);
 823     try std.testing.expectEqual(@as(u8, 160), gradient.end_color.a);
 824 }
 825 
 826 test "surface command owns and decodes validated text runs" {
 827     const content = "A\u{00e9}B";
 828     const styles = [_]command.CommandUiTextStyle{
 829         .{ .font_asset_id = 12, .point_size = 18 },
 830     };
 831     const runs = [_]command.CommandUiTextRun{
 832         .{
 833             .byte_start = 0,
 834             .byte_end = 1,
 835             .style_slot = 1,
 836             .foreground = .{
 837                 .is_set = 1,
 838                 .value = .{ .r = 10, .g = 20, .b = 30, .a = 220 },
 839             },
 840             .background = std.mem.zeroes(command.CommandUiOptionalColor),
 841             .underline = 1,
 842             .strikethrough = 0,
 843         },
 844         .{
 845             .byte_start = 1,
 846             .byte_end = 3,
 847             .style_slot = 0,
 848             .foreground = std.mem.zeroes(command.CommandUiOptionalColor),
 849             .background = .{
 850                 .is_set = 1,
 851                 .value = .{ .r = 40, .g = 50, .b = 60, .a = 180 },
 852             },
 853             .underline = 0,
 854             .strikethrough = 1,
 855         },
 856     };
 857     var text = std.mem.zeroes(command.CommandUiText);
 858     text.content_ptr = content.ptr;
 859     text.content_len = content.len;
 860     text.runs_ptr = &runs;
 861     text.runs_len = runs.len;
 862     text.styles_ptr = &styles;
 863     text.styles_len = styles.len;
 864     var root = std.mem.zeroes(command.CommandUiNode);
 865     root.widget_id = 9;
 866     root.kind = 1;
 867     root.text_ptr = &text;
 868     const source = command.CommandUiSurface{
 869         .available_width = 80,
 870         .available_height = 20,
 871         .root_ptr = &root,
 872         .images_ptr = null,
 873         .images_len = 0,
 874     };
 875     const facts = try survey.commandSurface(&source);
 876     try std.testing.expectEqual(@as(usize, 2), facts.runs);
 877     try std.testing.expectEqual(@as(usize, 1), facts.styles);
 878     var storage = try Storage.init(std.testing.allocator, .{
 879         .nodes = facts.nodes,
 880         .runs = facts.runs,
 881         .styles = facts.styles,
 882         .semantic_bytes = facts.semantic_bytes,
 883     });
 884     defer storage.deinit(std.testing.allocator);
 885     storage.activate();
 886     const cloned = try storage.cloneCommandSurface(&source);
 887     try std.testing.expectEqualStrings(content, cloned.tree.root.text.?.content);
 888     try std.testing.expectEqual(@as(usize, 2), cloned.tree.root.text.?.runs.len);
 889     try std.testing.expectEqual(@as(u64, 12), cloned.tree.root.text.?.styles[0].font_asset_id);
 890     try std.testing.expectEqual(@as(f64, 18), cloned.tree.root.text.?.styles[0].point_size);
 891     try std.testing.expectEqual(@as(u16, 1), cloned.tree.root.text.?.runs[0].style_slot);
 892     try std.testing.expectEqual(@as(u8, 10), cloned.tree.root.text.?.runs[0].foreground.?.r);
 893     try std.testing.expect(cloned.tree.root.text.?.runs[0].underline);
 894     try std.testing.expectEqual(@as(u8, 180), cloned.tree.root.text.?.runs[1].background.?.a);
 895     try std.testing.expect(cloned.tree.root.text.?.runs[1].strikethrough);
 896 
 897     var invalid_runs = runs;
 898     invalid_runs[1].byte_start = 2;
 899     text.runs_ptr = &invalid_runs;
 900     try std.testing.expectError(error.InvalidCommand, storage.cloneCommandSurface(&source));
 901     try std.testing.expectEqual(@as(u64, 9), storage.current().?.tree.root.widget_id);
 902     try std.testing.expectEqual(@as(u8, 10), storage.current().?.tree.root.text.?.runs[0].foreground.?.r);
 903 }
 904 
 905 test "surface clone owns image descriptors and pixels across failed replacement" {
 906     comptime {
 907         @stardustClaim(
 908             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_images"),
 909             null,
 910             null,
 911             null,
 912             null,
 913             null,
 914             null,
 915         );
 916     }
 917 
 918     var source_pixels = [_]u32{ 0xff00_00ff, 0xff00_ff00, 0xffff_0000, 0xffff_ffff };
 919     var source_images = [_]UiImage{.{
 920         .width = 2,
 921         .height = 2,
 922         .pixels = &source_pixels,
 923     }};
 924     const tree = UiSurfaceTree{
 925         .available_size = .{ .width = 12, .height = 12 },
 926         .root = .{
 927             .widget_id = 4,
 928             .paint = .{ .image = .{
 929                 .index = 0,
 930                 .source = .{ .x = 0.5, .y = 1, .width = 1, .height = 1 },
 931                 .opacity = 190,
 932             } },
 933         },
 934     };
 935     var storage = try Storage.init(std.testing.allocator, .{
 936         .nodes = 1,
 937         .images = 1,
 938         .image_pixels = 4,
 939         .semantic_bytes = 0,
 940     });
 941     defer storage.deinit(std.testing.allocator);
 942     storage.activate();
 943     const cloned = try storage.cloneSurface(.{
 944         .tree = &tree,
 945         .images = .{ .images = &source_images },
 946     });
 947     source_pixels[0] = 0;
 948     source_images[0].width = 1;
 949     try std.testing.expectEqual(@as(usize, 1), cloned.images.images.len);
 950     try std.testing.expectEqual(@as(u32, 2), cloned.images.images[0].width);
 951     try std.testing.expectEqual(@as(u32, 0xff00_00ff), cloned.images.images[0].pixels[0]);
 952     try std.testing.expectEqual(@as(u8, 190), cloned.tree.root.paint.image.?.opacity);
 953 
 954     const oversized_pixels = @as([5]u32, @splat(0));
 955     const oversized_images = [_]UiImage{.{
 956         .width = 5,
 957         .height = 1,
 958         .pixels = &oversized_pixels,
 959     }};
 960     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneSurface(.{
 961         .tree = &tree,
 962         .images = .{ .images = &oversized_images },
 963     }));
 964     try std.testing.expectEqual(@as(u32, 0xff00_00ff), storage.current().?.images.images[0].pixels[0]);
 965 
 966     const descriptor_pixels = [_]u32{ 1, 2 };
 967     const too_many_images = [_]UiImage{
 968         .{ .width = 1, .height = 1, .pixels = descriptor_pixels[0..1] },
 969         .{ .width = 1, .height = 1, .pixels = descriptor_pixels[1..2] },
 970     };
 971     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneSurface(.{
 972         .tree = &tree,
 973         .images = .{ .images = &too_many_images },
 974     }));
 975     try std.testing.expectEqual(@as(u32, 0xff00_00ff), storage.current().?.images.images[0].pixels[0]);
 976 }
 977 
 978 test "surface command owns image pixels and normalizes image paint" {
 979     comptime {
 980         @stardustClaim(
 981             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_command_images_overload"),
 982             null,
 983             null,
 984             null,
 985             null,
 986             null,
 987             null,
 988         );
 989     }
 990     comptime {
 991         @stardustClaim(
 992             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_command_images_foreign_risk"),
 993             null,
 994             null,
 995             null,
 996             null,
 997             null,
 998             null,
 999         );
1000     }
1001 
1002     var source_pixels = [_]u32{ 0xff10_2030, 0xff40_5060, 0xff70_8090, 0xffa0_b0c0 };
1003     var source_image = command.CommandUiImage{
1004         .width = 2,
1005         .height = 2,
1006         .pixels_ptr = &source_pixels,
1007         .pixels_len = source_pixels.len,
1008     };
1009     var root = std.mem.zeroes(command.CommandUiNode);
1010     root.widget_id = 8;
1011     root.paint.image = .{
1012         .is_set = 1,
1013         .index = 0,
1014         .source = .{
1015             .x = std.math.nan(f32),
1016             .y = 0.5,
1017             .width = std.math.inf(f32),
1018             .height = 1,
1019         },
1020         .tint = .{
1021             .is_set = 1,
1022             .value = .{ .r = 20, .g = 40, .b = 60, .a = 180 },
1023         },
1024         .opacity = 210,
1025     };
1026     var source = command.CommandUiSurface{
1027         .available_width = 12,
1028         .available_height = 12,
1029         .root_ptr = &root,
1030         .images_ptr = @ptrCast(&source_image),
1031         .images_len = 1,
1032     };
1033     const facts = try survey.commandSurface(&source);
1034     var storage = try Storage.init(std.testing.allocator, .{
1035         .nodes = facts.nodes,
1036         .images = facts.images,
1037         .image_pixels = facts.image_pixels,
1038         .semantic_bytes = facts.semantic_bytes,
1039     });
1040     defer storage.deinit(std.testing.allocator);
1041     storage.activate();
1042     const cloned = try storage.cloneCommandSurface(&source);
1043     source_pixels[0] = 0;
1044     source_image.width = 1;
1045     try std.testing.expectEqual(@as(u32, 2), cloned.images.images[0].width);
1046     try std.testing.expectEqual(@as(u32, 0xff10_2030), cloned.images.images[0].pixels[0]);
1047     const paint = cloned.tree.root.paint.image.?;
1048     try std.testing.expectEqual(@as(f32, 0), paint.source.x);
1049     try std.testing.expectEqual(@as(f32, 0), paint.source.width);
1050     try std.testing.expectEqual(@as(f32, 1), paint.source.height);
1051     try std.testing.expectEqual(@as(u8, 20), paint.tint.?.r);
1052     try std.testing.expectEqual(@as(u8, 210), paint.opacity);
1053 
1054     source_image.width = 2;
1055     const second_pixels = [_]u32{1};
1056     const too_many_images = [_]command.CommandUiImage{
1057         source_image,
1058         .{
1059             .width = 1,
1060             .height = 1,
1061             .pixels_ptr = &second_pixels,
1062             .pixels_len = second_pixels.len,
1063         },
1064     };
1065     source.images_ptr = &too_many_images;
1066     source.images_len = too_many_images.len;
1067     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneCommandSurface(&source));
1068     try std.testing.expectEqual(@as(u32, 0xff10_2030), storage.current().?.images.images[0].pixels[0]);
1069 
1070     const oversized_pixels = [_]u32{ 1, 2, 3, 4, 5 };
1071     const oversized_image = command.CommandUiImage{
1072         .width = 5,
1073         .height = 1,
1074         .pixels_ptr = &oversized_pixels,
1075         .pixels_len = oversized_pixels.len,
1076     };
1077     source.images_ptr = @ptrCast(&oversized_image);
1078     source.images_len = 1;
1079     try std.testing.expectError(error.SurfaceCapacityExceeded, storage.cloneCommandSurface(&source));
1080     try std.testing.expectEqual(@as(u32, 0xff10_2030), storage.current().?.images.images[0].pixels[0]);
1081 }
1082 
1083 test "surface clone maximum placement makes no backing allocation" {
1084     comptime {
1085         @stardustClaim(
1086             @import("alloc_phase").capacity.witness(Storage, "gui_surface_clone_sealed"),
1087             null,
1088             null,
1089             null,
1090             null,
1091             null,
1092             null,
1093         );
1094     }
1095 
1096     const children = [_]UiNode{
1097         .{ .widget_id = 2, .text = .{ .content = "abc" }, .action = "def" },
1098         .{ .widget_id = 3, .role = "ghi" },
1099     };
1100     const surface = UiSurfaceTree{
1101         .available_size = .{ .width = 10, .height = 10 },
1102         .root = .{
1103             .widget_id = 1,
1104             .paint = .{ .image = .{ .index = 0 } },
1105             .children = &children,
1106         },
1107     };
1108     const image_pixels = [_]u32{ 0xff00_00ff, 0xff00_ff00, 0xffff_0000, 0xffff_ffff };
1109     const images = [_]UiImage{.{
1110         .width = 2,
1111         .height = 2,
1112         .pixels = &image_pixels,
1113     }};
1114     const source = Surface{
1115         .tree = &surface,
1116         .images = .{ .images = &images },
1117     };
1118     const facts = try survey.surface(source);
1119     var counting = std.testing.FailingAllocator.init(std.testing.allocator, .{});
1120     var storage = try Storage.init(counting.allocator(), .{
1121         .nodes = facts.nodes,
1122         .runs = facts.runs,
1123         .styles = facts.styles,
1124         .images = facts.images,
1125         .image_pixels = facts.image_pixels,
1126         .semantic_bytes = facts.semantic_bytes,
1127     });
1128     defer storage.deinit(counting.allocator());
1129     storage.activate();
1130     const allocations = counting.alloc_index;
1131     const bytes = counting.allocated_bytes;
1132     _ = try storage.cloneSurface(source);
1133     _ = try storage.cloneSurface(source);
1134     try std.testing.expectEqual(allocations, counting.alloc_index);
1135     try std.testing.expectEqual(bytes, counting.allocated_bytes);
1136 }
1137 
1138 comptime {
1139     alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage);
1140 }