tiny.ui.AssetRegistry
Defined in tiny.ui.
API (32)
Actions
Public operations.
Types and contracts
Public types and contracts.
Fields and members
Public fields and members.
capacityepochfont_bytesfont_generationfont_occupiedfont_usedfontsimage_bytesimage_generationimage_occupiedimage_usedimageslimitsowned_bytesphasestoragestrings
Source
Source: lib/ui/src/asset/registry.zig:13
zig
pub const Registry = struct { phase: alloc_phase.capacity.Phase, limits: Limits, capacity: Capacity, storage: []align(8) u8, fonts: []FontDescriptor, font_bytes: []Bytes, font_generation: []u32, font_used: u32, images: []ImageDescriptor, image_bytes: []Bytes, image_generation: []u32, image_used: u32, strings: []u8, owned_bytes: []u8, font_occupied: []u64, image_occupied: []u64, epoch: u64, pub const Limits: type = capacity_mod.Limits; pub const Capacity: type = capacity_mod.Capacity; pub const Exhaustion: type = model.Error; pub const InitError: type = Allocator.Error || capacity_mod.Error; pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "ui.asset_table", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{.{ .id = "asset_table_and_owned_payload_pool", .lifetime = .steady, .detail = "font and image descriptors, byte views, generation and occupancy arrays, family strings, and the copied payload pool in one allocation", }}, .excluded = &.{ "borrowed font and image bytes kept alive by the caller", "embedded fallback face bytes held in startup static storage", }, }, .capacity = .{ .inputs = &.{ alloc_phase.capacity.bindInput(Limits, "fonts", "fonts"), alloc_phase.capacity.bindInput(Limits, "images", "images"), alloc_phase.capacity.bindInput(Limits, "owned_bytes", "owned_bytes"), }, .type_selectors = &.{ alloc_phase.capacity.bindType(FontDescriptor, "font_descriptor"), alloc_phase.capacity.bindType(ImageDescriptor, "image_descriptor"), alloc_phase.capacity.bindType(Bytes, "bytes"), alloc_phase.capacity.bindType(u32, "generation"), alloc_phase.capacity.bindType(u64, "occupancy_word"), }, .nodes = &.{ .{ .input = 0 }, .{ .input = 1 }, .{ .input = 2 }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 } } }, .{ .alignment = .{ .node = 3, .alignment = .{ .concrete_type = 2 } } }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 2 } } }, .{ .add = .{ .left = 4, .right = 5 } }, .{ .alignment = .{ .node = 6, .alignment = .{ .concrete_type = 3 } } }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 3 } } }, .{ .add = .{ .left = 7, .right = 8 } }, .{ .alignment = .{ .node = 9, .alignment = .{ .concrete_type = 4 } } }, .{ .constant = 64 }, .{ .ceiling_division = .{ .left = 0, .right = 11 } }, .{ .scale = .{ .node = 12, .coefficient = .{ .size_of_concrete_type = 4 } } }, .{ .add = .{ .left = 10, .right = 13 } }, .{ .alignment = .{ .node = 14, .alignment = .{ .concrete_type = 1 } } }, .{ .scale = .{ .node = 1, .coefficient = .{ .size_of_concrete_type = 1 } } }, .{ .add = .{ .left = 15, .right = 16 } }, .{ .alignment = .{ .node = 17, .alignment = .{ .concrete_type = 2 } } }, .{ .scale = .{ .node = 1, .coefficient = .{ .size_of_concrete_type = 2 } } }, .{ .add = .{ .left = 18, .right = 19 } }, .{ .alignment = .{ .node = 20, .alignment = .{ .concrete_type = 3 } } }, .{ .scale = .{ .node = 1, .coefficient = .{ .size_of_concrete_type = 3 } } }, .{ .add = .{ .left = 21, .right = 22 } }, .{ .alignment = .{ .node = 23, .alignment = .{ .concrete_type = 4 } } }, .{ .ceiling_division = .{ .left = 1, .right = 11 } }, .{ .scale = .{ .node = 25, .coefficient = .{ .size_of_concrete_type = 4 } } }, .{ .add = .{ .left = 24, .right = 26 } }, .{ .scale = .{ .node = 0, .coefficient = .{ .literal = capacity_mod.family_bytes_per_font } } }, .{ .add = .{ .left = 27, .right = 28 } }, .{ .add = .{ .left = 29, .right = 2 } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .exact, .expression = 30, }}, }, .overload = .{ .kind = .reject_before_mutation, .detail = "slot, family length, and owned payload quota checks run before changing table fields", }, .risks = .{ .transitive = .{ .status = .open, .detail = "owned bytes use one allocation at initialization; the bounded registration scan takes no allocator", }, .foreign = .{ .status = .excluded, .detail = "registration and lookup operate on caller and table bytes without an operating-system call", }, }, .obligations = &.{ .{ .key = "ui_asset_capacity", .role = .capacity_model }, .{ .key = "ui_asset_acquisition", .role = .acquisition }, .{ .key = "ui_asset_generation", .role = .integration }, .{ .key = "ui_asset_oom", .role = .overload }, .{ .key = "ui_asset_teardown", .role = .teardown }, }, }, .bindings = .{ .owner = @This(), .seal = .{ .family = alloc_phase.capacity.selector(@This().activate), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, .teardown = .{ .family = alloc_phase.capacity.selector(@This().deinit), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, }, }; pub fn init(allocator: Allocator, limits: Limits) InitError!Registry { const capacity = try Capacity.derive(limits); const storage = try allocator.alignedAlloc(u8, .fromByteUnits(8), capacity.total_bytes); var self = Registry{ .phase = .initialization, .limits = limits, .capacity = capacity, .storage = storage, .fonts = &.{}, .font_bytes = &.{}, .font_generation = &.{}, .font_used = 0, .images = &.{}, .image_bytes = &.{}, .image_generation = &.{}, .image_used = 0, .strings = &.{}, .owned_bytes = &.{}, .font_occupied = &.{}, .image_occupied = &.{}, .epoch = 0, }; self.place(); @memset(self.storage, 0); for (self.font_bytes) |*entry| entry.* = .{ .borrowed = &.{} }; for (self.image_bytes) |*entry| entry.* = .{ .borrowed = &.{} }; @memset(self.font_generation, 1); @memset(self.image_generation, 1); return self; } pub fn activate(self: *Registry) void { std.debug.assert(self.phase == .initialization); std.debug.assert(self.storage.len == self.capacity.total_bytes); self.phase = .steady; } pub fn deinit(self: *Registry, allocator: Allocator) void { std.debug.assert(self.phase != .teardown); allocator.free(self.storage); self.phase = .teardown; self.storage = &.{}; self.fonts = &.{}; self.font_bytes = &.{}; self.font_generation = &.{}; self.images = &.{}; self.image_bytes = &.{}; self.image_generation = &.{}; self.strings = &.{}; self.owned_bytes = &.{}; self.font_occupied = &.{}; self.image_occupied = &.{}; self.font_used = 0; self.image_used = 0; self.epoch = 0; } pub fn registerFont(self: *Registry, family: []const u8, input: FontDescriptor, bytes: Bytes) model.Error!AssetHandle { std.debug.assert(self.phase == .steady); if (family.len > capacity_mod.family_bytes_per_font) return error.FamilyTooLong; const index = firstFree(self.font_occupied, self.limits.fonts) orelse return error.FontCapacityExceeded; const source = bytes.slice(); const offset = switch (bytes) { .borrowed => null, .owned => self.findOwned(source.len) orelse return error.OwnedBytesExceeded, }; const family_offset = @as(usize, index) * capacity_mod.family_bytes_per_font; var descriptor = input; descriptor.family_offset = @intCast(family_offset); descriptor.family_len = @intCast(family.len); @memcpy(self.strings[family_offset..][0..family.len], family); self.fonts[index] = descriptor; self.font_bytes[index] = self.storeBytes(bytes, offset); setOccupied(self.font_occupied, index, true); self.font_used += 1; self.epoch +%= 1; return .{ .index = index, .generation = self.font_generation[index] }; } pub fn registerImage(self: *Registry, descriptor: ImageDescriptor, bytes: Bytes) model.Error!AssetHandle { std.debug.assert(self.phase == .steady); const index = firstFree(self.image_occupied, self.limits.images) orelse return error.ImageCapacityExceeded; const source = bytes.slice(); const offset = switch (bytes) { .borrowed => null, .owned => self.findOwned(source.len) orelse return error.OwnedBytesExceeded, }; self.images[index] = descriptor; self.image_bytes[index] = self.storeBytes(bytes, offset); setOccupied(self.image_occupied, index, true); self.image_used += 1; self.epoch +%= 1; return .{ .index = index, .generation = self.image_generation[index] }; } pub fn release(self: *Registry, kind: model.Kind, handle: AssetHandle) model.Error!void { std.debug.assert(self.phase == .steady); switch (kind) { .font => { if (!self.hasFont(handle)) return error.StaleAsset; if (handle.generation == std.math.maxInt(u32)) return error.GenerationExhausted; clearOwned(self.font_bytes[handle.index]); const start = @as(usize, handle.index) * capacity_mod.family_bytes_per_font; @memset(self.strings[start..][0..capacity_mod.family_bytes_per_font], 0); self.fonts[handle.index] = .{}; self.font_bytes[handle.index] = .{ .borrowed = &.{} }; self.font_generation[handle.index] += 1; setOccupied(self.font_occupied, handle.index, false); self.font_used -= 1; self.epoch +%= 1; }, .image => { if (!self.hasImage(handle)) return error.StaleAsset; if (handle.generation == std.math.maxInt(u32)) return error.GenerationExhausted; clearOwned(self.image_bytes[handle.index]); self.images[handle.index] = .{}; self.image_bytes[handle.index] = .{ .borrowed = &.{} }; self.image_generation[handle.index] += 1; setOccupied(self.image_occupied, handle.index, false); self.image_used -= 1; self.epoch +%= 1; }, } } pub fn hasFont(self: *const Registry, handle: AssetHandle) bool { return handle.index < self.limits.fonts and occupied(self.font_occupied, handle.index) and self.font_generation[handle.index] == handle.generation; } pub fn hasImage(self: *const Registry, handle: AssetHandle) bool { return handle.index < self.limits.images and occupied(self.image_occupied, handle.index) and self.image_generation[handle.index] == handle.generation; } pub fn font(self: *const Registry, handle: AssetHandle) model.Error!model.Font { if (!self.hasFont(handle)) return error.StaleAsset; const descriptor = self.fonts[handle.index]; return .{ .descriptor = descriptor, .family = self.strings[descriptor.family_offset..][0..descriptor.family_len], .bytes = self.font_bytes[handle.index].slice(), }; } pub fn image(self: *const Registry, handle: AssetHandle) model.Error!model.Image { if (!self.hasImage(handle)) return error.StaleAsset; return .{ .descriptor = self.images[handle.index], .bytes = self.image_bytes[handle.index].slice() }; } fn storeBytes(self: *Registry, bytes: Bytes, offset: ?usize) Bytes { return switch (bytes) { .borrowed => bytes, .owned => |source| blk: { const start = offset.?; @memcpy(self.owned_bytes[start..][0..source.len], source); break :blk .{ .owned = self.owned_bytes[start..][0..source.len] }; }, }; } fn findOwned(self: *const Registry, len: usize) ?usize { if (len > self.owned_bytes.len) return null; var candidate: usize = 0; while (candidate <= self.owned_bytes.len - len) { var conflict_end: usize = candidate; for (self.font_bytes, 0..) |entry, index| { if (!occupied(self.font_occupied, @intCast(index))) continue; overlapEnd(self.owned_bytes, entry, candidate, len, &conflict_end); } for (self.image_bytes, 0..) |entry, index| { if (!occupied(self.image_occupied, @intCast(index))) continue; overlapEnd(self.owned_bytes, entry, candidate, len, &conflict_end); } if (conflict_end == candidate) return candidate; candidate = conflict_end; } return null; } fn place(self: *Registry) void { var cursor: usize = 0; self.fonts = take(self.storage, &cursor, FontDescriptor, self.limits.fonts); self.font_bytes = take(self.storage, &cursor, Bytes, self.limits.fonts); self.font_generation = take(self.storage, &cursor, u32, self.limits.fonts); self.font_occupied = take(self.storage, &cursor, u64, std.math.divCeil(usize, self.limits.fonts, 64) catch unreachable); self.images = take(self.storage, &cursor, ImageDescriptor, self.limits.images); self.image_bytes = take(self.storage, &cursor, Bytes, self.limits.images); self.image_generation = take(self.storage, &cursor, u32, self.limits.images); self.image_occupied = take(self.storage, &cursor, u64, std.math.divCeil(usize, self.limits.images, 64) catch unreachable); self.strings = take(self.storage, &cursor, u8, self.capacity.string_bytes); self.owned_bytes = take(self.storage, &cursor, u8, self.limits.owned_bytes); std.debug.assert(cursor == self.capacity.total_bytes); }};Source: lib/ui/src/root.zig:34
zig
pub const AssetRegistry = asset.Registry;Also reachable as
Complete caller list for AssetRegistry.activate
10 direct callers.
tiny.ui.asset.Embedded.open[function] atlib/ui/src/asset/embedded.zig:134lib.ui.src.asset.registry.openAndClose[function] — private source atlib/ui/src/asset/registry.zig:396in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_capacity_accepts_each_maximum_and_rejects_maximum_plus_one[function] — test source atlib/ui/src/asset/registry.zig:443in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_capacity_default_slot_and_owned_byte_maxima[function] — test source atlib/ui/src/asset/registry.zig:458in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_generation_register_release_and_reuse[function] — test source atlib/ui/src/asset/registry.zig:409in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_oom_registration_rejects_before_mutation[function] — test source atlib/ui/src/asset/registry.zig:428in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_teardown_borrows_caller_bytes_and_returns_owned_table_once[function] — test source atlib/ui/src/asset/registry.zig:483in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.resolve.test_authored_font_families_decode_CSS_escapes_before_matching[function] — test source atlib/ui/src/asset/resolve.zig:303in nearest public ownerlib.ui.src.asset.resolvelib.ui.src.asset.resolve.test_font_resolution_follows_family_CSS_weight_and_synthetic_slant[function] — test source atlib/ui/src/asset/resolve.zig:284in nearest public ownerlib.ui.src.asset.resolvelib.ui.src.asset.resolve.test_font_resolution_prefers_monospace_and_orders_script_coverage_fallbacks[function] — test source atlib/ui/src/asset/resolve.zig:315in nearest public ownerlib.ui.src.asset.resolve
Complete caller list for AssetRegistry.init
7 direct callers.
tiny.ui.asset.Embedded.open[function] atlib/ui/src/asset/embedded.zig:134lib.ui.src.asset.registry.openAndClose[function] — private source atlib/ui/src/asset/registry.zig:396in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_capacity_accepts_each_maximum_and_rejects_maximum_plus_one[function] — test source atlib/ui/src/asset/registry.zig:443in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_capacity_default_slot_and_owned_byte_maxima[function] — test source atlib/ui/src/asset/registry.zig:458in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_generation_register_release_and_reuse[function] — test source atlib/ui/src/asset/registry.zig:409in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_oom_registration_rejects_before_mutation[function] — test source atlib/ui/src/asset/registry.zig:428in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_teardown_borrows_caller_bytes_and_returns_owned_table_once[function] — test source atlib/ui/src/asset/registry.zig:483in nearest public ownerlib.ui.src.asset.registry
Complete caller list for AssetRegistry.registerFont
8 direct callers.
lib.ui.src.asset.registry.test_ui_asset_capacity_accepts_each_maximum_and_rejects_maximum_plus_one[function] — test source atlib/ui/src/asset/registry.zig:443in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_capacity_default_slot_and_owned_byte_maxima[function] — test source atlib/ui/src/asset/registry.zig:458in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_generation_register_release_and_reuse[function] — test source atlib/ui/src/asset/registry.zig:409in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_oom_registration_rejects_before_mutation[function] — test source atlib/ui/src/asset/registry.zig:428in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.registry.test_ui_asset_teardown_borrows_caller_bytes_and_returns_owned_table_once[function] — test source atlib/ui/src/asset/registry.zig:483in nearest public ownerlib.ui.src.asset.registrylib.ui.src.asset.resolve.test_authored_font_families_decode_CSS_escapes_before_matching[function] — test source atlib/ui/src/asset/resolve.zig:303in nearest public ownerlib.ui.src.asset.resolvelib.ui.src.asset.resolve.test_font_resolution_follows_family_CSS_weight_and_synthetic_slant[function] — test source atlib/ui/src/asset/resolve.zig:284in nearest public ownerlib.ui.src.asset.resolvelib.ui.src.asset.resolve.test_font_resolution_prefers_monospace_and_orders_script_coverage_fallbacks[function] — test source atlib/ui/src/asset/resolve.zig:315in nearest public ownerlib.ui.src.asset.resolve
Audit
| Definitions | 16 |
|---|---|
| Public names | 32 |
| Members | 17 |
| Version | 26.7.0 |
| Revision | daab053ee433 |