tiny.gui.paint.fallback
Defined in paint.
API (27)
Actions
Public operations.
Capacity.deriveEngine.deinitEngine.initEngine.segmentsEngine.statusStorage.activateStorage.deinitStorage.initStorage.lookupStorage.resetStorage.segmentListStorage.statusStorage.store
Types and contracts
Public types and contracts.
CapacityDeriveErrorEngineExhaustionFaceSegmentKeyLimitsStatusStorageStorage.CapacityStorage.ExhaustionStorage.InitErrorStorage.Limits
Values and defaults
Public values and defaults.
Source
Source: lib/gui/src/paint/fallback.zig
zig
const std = @import("std");const alloc_phase = @import("alloc_phase");const filigree = @import("filigree");const Allocator = std.mem.Allocator;pub const FaceSegment = struct { source: filigree.SourceRange, candidate_index: usize, missing_everywhere: bool,};pub const Key = struct { content: []const u8, primary_identity: usize, fallback_identity: usize,};const CacheEntry = struct { hash: u64, primary_identity: usize, fallback_identity: usize, content_offset: usize, content_len: usize, segment_offset: usize, segment_count: usize,};pub const Limits = struct { max_source_units: usize, cache_entries: usize, cache_payload_bytes: usize,};pub const DeriveError = error{CapacityOverflow};const storage_alignment: usize = @max( @max(@alignOf(filigree.FallbackSegment), @alignOf(u32)), @max(@alignOf(CacheEntry), @alignOf(FaceSegment)),);pub const Capacity = struct { limits: Limits, segment_offset: usize, segment_bytes: usize, index_slots: usize, index_offset: usize, index_bytes: usize, entry_offset: usize, entry_bytes: usize, payload_offset: usize, payload_bytes: usize, storage_bytes: usize, pub fn derive(limits: Limits) DeriveError!Capacity { const segments = try placed(filigree.FallbackSegment, 0, limits.max_source_units); const slots = try indexSlotCount(limits.cache_entries); const index = try placed(u32, segments.end, slots); const entries = try placed(CacheEntry, index.end, limits.cache_entries); const payload = try placed(u8, try alignOffset(entries.end, @alignOf(FaceSegment)), limits.cache_payload_bytes); return .{ .limits = limits, .segment_offset = segments.start, .segment_bytes = segments.bytes, .index_slots = slots, .index_offset = index.start, .index_bytes = index.bytes, .entry_offset = entries.start, .entry_bytes = entries.bytes, .payload_offset = payload.start, .payload_bytes = payload.bytes, .storage_bytes = payload.end, }; }};pub const Exhaustion = error{ SourceUnitCapacityExceeded, SegmentCapacityExceeded, CacheEntryCapacityExceeded, CachePayloadCapacityExceeded,};pub const Status = struct { phase: alloc_phase.capacity.Phase, capacity: StorageCapacity, storage_bytes: usize, entries: usize, payload_bytes: usize, high_water_entries: usize, high_water_payload_bytes: usize, source_rejections: u64, segment_rejections: u64, cache_entry_rejections: u64, cache_payload_rejections: u64, rollovers: u64,};const StorageLimits = Limits;const StorageCapacity = Capacity;const StorageExhaustion = Exhaustion;pub const Storage = struct { phase: alloc_phase.capacity.Phase, capacity: StorageCapacity, bytes: []align(storage_alignment) u8, segment_scratch: []filigree.FallbackSegment, index: []u32, entries: []CacheEntry, payload: []u8, entry_count: usize = 0, payload_used: usize = 0, high_water_entries: usize = 0, high_water_payload_bytes: usize = 0, source_rejections: u64 = 0, segment_rejections: u64 = 0, cache_entry_rejections: u64 = 0, cache_payload_rejections: u64 = 0, rollovers: u64 = 0, pub const Limits: type = StorageLimits; pub const Capacity: type = StorageCapacity; pub const Exhaustion: type = StorageExhaustion; pub const InitError = Allocator.Error || DeriveError; pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "gui.text_fallback_segment_storage", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{ .{ .id = "fallback_reported_segment_scratch", .lifetime = .steady, .detail = "reported Filigree fallback face segments", }, .{ .id = "fallback_segment_cache_index_and_entries", .lifetime = .steady, .detail = "fixed fallback segment cache index and dense entries", }, .{ .id = "fallback_segment_cache_payload", .lifetime = .steady, .detail = "source keys and aligned face segment payloads", }, }, .excluded = &.{ "caller-owned UTF-8 content and font atlases", "Filigree fallback context and temporary shaped output", "per-atlas shape caches and composite layout workspace", }, }, .capacity = .{ .inputs = &.{ alloc_phase.capacity.bindInput(StorageLimits, "max_source_units", "max_source_units"), alloc_phase.capacity.bindInput(StorageLimits, "cache_entries", "cache_entries"), alloc_phase.capacity.bindInput(StorageLimits, "cache_payload_bytes", "cache_payload_bytes"), }, .type_selectors = &.{ alloc_phase.capacity.bindType(filigree.FallbackSegment, "fallbacksegment"), alloc_phase.capacity.bindType(u32, "u32"), alloc_phase.capacity.bindType(CacheEntry, "cacheentry"), alloc_phase.capacity.bindType(FaceSegment, "facesegment"), }, .nodes = &.{ .{ .input = 0 }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 } } }, .{ .alignment = .{ .node = 1, .alignment = .{ .concrete_type = 1 } } }, .{ .input = 1 }, .{ .scale = .{ .node = 3, .coefficient = .{ .literal = 2 } } }, .{ .next_power_of_two = 4 }, .{ .scale = .{ .node = 5, .coefficient = .{ .size_of_concrete_type = 1 } } }, .{ .add = .{ .left = 2, .right = 6 } }, .{ .alignment = .{ .node = 7, .alignment = .{ .concrete_type = 2 } } }, .{ .scale = .{ .node = 3, .coefficient = .{ .size_of_concrete_type = 2 } } }, .{ .add = .{ .left = 8, .right = 9 } }, .{ .alignment = .{ .node = 10, .alignment = .{ .concrete_type = 3 } } }, .{ .input = 2 }, .{ .add = .{ .left = 11, .right = 12 } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .exact, .expression = 13, }}, }, .overload = .{ .kind = .reject_before_mutation, .detail = "source, segment, entry, and payload max-plus-one requests reject before cached records or returned pointers change", }, .risks = .{ .transitive = .{ .status = .witnessed, .detail = "activated lookup, insertion, and explicit rollover use only the acquired typed regions", }, .foreign = .{ .status = .excluded, .detail = "cache operations cross no operating-system or foreign callback boundary", }, }, .obligations = &.{ .{ .key = "gui_text_fallback_capacity", .role = .capacity_model }, .{ .key = "gui_text_fallback_acquisition", .role = .custom }, .{ .key = "gui_text_fallback_oom", .role = .custom }, .{ .key = "gui_text_fallback_boundaries", .role = .overload }, .{ .key = "gui_text_fallback_reuse", .role = .overload }, .{ .key = "gui_text_fallback_sealed_transitive_risk", .role = .transitive_risk }, .{ .key = "gui_text_fallback_sealed_foreign_risk", .role = .foreign_risk }, .{ .key = "gui_text_fallback_root", .role = .custom }, }, }, .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: StorageLimits) InitError!Storage { const capacity = try StorageCapacity.derive(limits); const bytes = try allocator.alignedAlloc(u8, .fromByteUnits(storage_alignment), capacity.storage_bytes); return .{ .phase = .initialization, .capacity = capacity, .bytes = bytes, .segment_scratch = typedSlice(filigree.FallbackSegment, bytes, capacity.segment_offset, limits.max_source_units), .index = typedSlice(u32, bytes, capacity.index_offset, capacity.index_slots), .entries = typedSlice(CacheEntry, bytes, capacity.entry_offset, limits.cache_entries), .payload = bytes[capacity.payload_offset..][0..capacity.payload_bytes], }; } pub fn activate(self: *Storage) void { std.debug.assert(self.phase == .initialization); self.assertStorage(); @memset(self.index, 0); self.phase = .steady; } pub fn deinit(self: *Storage, allocator: Allocator) void { std.debug.assert(self.phase != .teardown); self.assertStorage(); self.phase = .teardown; allocator.free(self.bytes); self.bytes = &.{}; self.segment_scratch = &.{}; self.index = &.{}; self.entries = &.{}; self.payload = &.{}; } pub fn segmentList(self: *Storage, source_units: usize) StorageExhaustion!std.ArrayListUnmanaged(filigree.FallbackSegment) { std.debug.assert(self.phase == .steady); if (source_units > self.capacity.limits.max_source_units) { self.source_rejections +|= 1; return error.SourceUnitCapacityExceeded; } return .{ .items = self.segment_scratch[0..0], .capacity = self.segment_scratch.len }; } pub fn lookup(self: *const Storage, key: Key) ?[]const FaceSegment { std.debug.assert(self.phase == .steady); if (self.index.len == 0) return null; const hash = hashKey(key); var slot = @as(usize, @truncate(hash)) & (self.index.len - 1); var probes: usize = 0; while (probes < self.index.len) : (probes += 1) { const stored = self.index[slot]; if (stored == 0) return null; const entry = self.entries[stored - 1]; if (self.entryMatches(entry, hash, key)) return self.entrySegments(entry); slot = (slot + 1) & (self.index.len - 1); } return null; } pub fn store(self: *Storage, key: Key, reported: []const filigree.FallbackSegment) StorageExhaustion![]const FaceSegment { std.debug.assert(self.phase == .steady); if (reported.len > self.segment_scratch.len) { self.segment_rejections +|= 1; return error.SegmentCapacityExceeded; } if (self.entry_count >= self.entries.len) { self.cache_entry_rejections +|= 1; return error.CacheEntryCapacityExceeded; } const placement = payloadPlacement(self.payload_used, key.content.len, reported.len) catch { self.cache_payload_rejections +|= 1; return error.CachePayloadCapacityExceeded; }; if (placement.end > self.payload.len) { self.cache_payload_rejections +|= 1; return error.CachePayloadCapacityExceeded; } const hash = hashKey(key); const slot = self.emptySlot(hash) orelse { self.cache_entry_rejections +|= 1; return error.CacheEntryCapacityExceeded; }; return self.commitStore(key, reported, hash, slot, placement); } pub fn reset(self: *Storage) void { std.debug.assert(self.phase == .steady); @memset(self.index, 0); self.entry_count = 0; self.payload_used = 0; self.rollovers +|= 1; } pub fn status(self: *const Storage) Status { return .{ .phase = self.phase, .capacity = self.capacity, .storage_bytes = self.capacity.storage_bytes, .entries = self.entry_count, .payload_bytes = self.payload_used, .high_water_entries = self.high_water_entries, .high_water_payload_bytes = self.high_water_payload_bytes, .source_rejections = self.source_rejections, .segment_rejections = self.segment_rejections, .cache_entry_rejections = self.cache_entry_rejections, .cache_payload_rejections = self.cache_payload_rejections, .rollovers = self.rollovers, }; } fn commitStore(self: *Storage, key: Key, reported: []const filigree.FallbackSegment, hash: u64, slot: usize, placement: PayloadPlacement) []const FaceSegment { const content = self.payload[placement.content_offset..placement.content_end]; @memcpy(content, key.content); const segments = payloadSegments(self.payload, placement.segment_offset, reported.len); for (reported, segments) |source, *target| { target.* = .{ .source = source.source, .candidate_index = source.candidate_index, .missing_everywhere = source.missing_everywhere, }; } self.entries[self.entry_count] = .{ .hash = hash, .primary_identity = key.primary_identity, .fallback_identity = key.fallback_identity, .content_offset = placement.content_offset, .content_len = key.content.len, .segment_offset = placement.segment_offset, .segment_count = reported.len, }; self.index[slot] = @intCast(self.entry_count + 1); self.entry_count += 1; self.payload_used = placement.end; self.high_water_entries = @max(self.high_water_entries, self.entry_count); self.high_water_payload_bytes = @max(self.high_water_payload_bytes, self.payload_used); return segments; } fn emptySlot(self: *const Storage, hash: u64) ?usize { if (self.index.len == 0) return null; var slot = @as(usize, @truncate(hash)) & (self.index.len - 1); var probes: usize = 0; while (probes < self.index.len) : (probes += 1) { if (self.index[slot] == 0) return slot; slot = (slot + 1) & (self.index.len - 1); } return null; } fn entryMatches(self: *const Storage, entry: CacheEntry, hash: u64, key: Key) bool { if (entry.hash != hash or entry.primary_identity != key.primary_identity or entry.fallback_identity != key.fallback_identity) return false; if (entry.content_len != key.content.len) return false; return std.mem.eql(u8, self.payload[entry.content_offset..][0..entry.content_len], key.content); } fn entrySegments(self: *const Storage, entry: CacheEntry) []const FaceSegment { return payloadSegments(self.payload, entry.segment_offset, entry.segment_count); } fn assertStorage(self: *const Storage) void { std.debug.assert(self.bytes.len == self.capacity.storage_bytes); std.debug.assert(self.segment_scratch.len == self.capacity.limits.max_source_units); std.debug.assert(self.index.len == self.capacity.index_slots); std.debug.assert(self.entries.len == self.capacity.limits.cache_entries); std.debug.assert(self.payload.len == self.capacity.payload_bytes); std.debug.assert(self.entry_count <= self.entries.len); std.debug.assert(self.payload_used <= self.payload.len); }};comptime { alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage);}pub const Engine = struct { allocator: Allocator, context: filigree.FallbackContext, output: filigree.Output, storage: Storage, pub fn init(allocator: Allocator, limits: Limits, output_limits: filigree.Output.Limits) !Engine { var storage = try Storage.init(allocator, limits); errdefer storage.deinit(allocator); storage.activate(); var context = try filigree.FallbackContext.init(allocator, .{ .script_runs = .{ .max_source_units = limits.max_source_units }, .output = output_limits, }); errdefer context.deinit(); return .{ .allocator = allocator, .context = context, .output = try filigree.Output.init(allocator, output_limits), .storage = storage, }; } pub fn deinit(self: *Engine) void { self.storage.deinit(self.allocator); self.output.deinit(self.allocator); self.context.deinit(); self.* = undefined; } pub fn segments(self: *Engine, primary: *const filigree.Font, fallback: *const filigree.Font, content: []const u8) ![]const FaceSegment { const key = Key{ .content = content, .primary_identity = @intFromPtr(primary), .fallback_identity = @intFromPtr(fallback), }; if (self.storage.lookup(key)) |cached| return cached; var reported = try self.storage.segmentList(content.len); const candidates = [_]filigree.FallbackCandidate{.{ .font = fallback }}; try self.context.shapeRunSegmented(.{ .base = .{ .font = primary, .text = .{ .utf8 = content } }, .candidates = &candidates, }, &self.output, self.allocator, &reported); return try self.storage.store(key, reported.items); } pub fn status(self: *const Engine) Status { return self.storage.status(); }};const Region = struct { start: usize, bytes: usize, end: usize,};const PayloadPlacement = struct { content_offset: usize, content_end: usize, segment_offset: usize, end: usize,};fn placed(comptime T: type, offset: usize, count: usize) DeriveError!Region { const start = try alignOffset(offset, @alignOf(T)); const bytes = std.math.mul(usize, count, @sizeOf(T)) catch return error.CapacityOverflow; return .{ .start = start, .bytes = bytes, .end = std.math.add(usize, start, bytes) catch return error.CapacityOverflow };}fn alignOffset(offset: usize, alignment: usize) DeriveError!usize { const padded = std.math.add(usize, offset, alignment - 1) catch return error.CapacityOverflow; return padded & ~(alignment - 1);}fn indexSlotCount(entries: usize) DeriveError!usize { if (entries == 0) return 0; const doubled = std.math.mul(usize, entries, 2) catch return error.CapacityOverflow; return std.math.ceilPowerOfTwo(usize, doubled) catch return error.CapacityOverflow;}fn payloadPlacement(offset: usize, content_len: usize, segment_count: usize) DeriveError!PayloadPlacement { const content_end = std.math.add(usize, offset, content_len) catch return error.CapacityOverflow; const segment_offset = try alignOffset(content_end, @alignOf(FaceSegment)); const segment_bytes = std.math.mul(usize, segment_count, @sizeOf(FaceSegment)) catch return error.CapacityOverflow; return .{ .content_offset = offset, .content_end = content_end, .segment_offset = segment_offset, .end = std.math.add(usize, segment_offset, segment_bytes) catch return error.CapacityOverflow, };}fn typedSlice(comptime T: type, bytes: []align(storage_alignment) u8, offset: usize, count: usize) []T { const byte_count = count * @sizeOf(T); const region: []align(@alignOf(T)) u8 = @alignCast(bytes[offset..][0..byte_count]); return std.mem.bytesAsSlice(T, region);}fn payloadSegments(payload: []u8, offset: usize, count: usize) []FaceSegment { const byte_count = count * @sizeOf(FaceSegment); const region: []align(@alignOf(FaceSegment)) u8 = @alignCast(payload[offset..][0..byte_count]); return std.mem.bytesAsSlice(FaceSegment, region);}fn hashKey(key: Key) u64 { var hash = std.hash.Wyhash.init(0x17d6_43c1_a948_5ef2); hash.update(std.mem.asBytes(&key.primary_identity)); hash.update(std.mem.asBytes(&key.fallback_identity)); hash.update(key.content); return hash.final();}fn modelCapacity(limits: Limits) DeriveError!Capacity { const segment_bytes = @as(u128, limits.max_source_units) * @sizeOf(filigree.FallbackSegment); const index_slots = if (limits.cache_entries == 0) 0 else std.math.ceilPowerOfTwo(u128, @as(u128, limits.cache_entries) * 2) catch return error.CapacityOverflow; const index_offset = modelAlign(segment_bytes, @alignOf(u32)); const index_bytes = index_slots * @sizeOf(u32); const entry_offset = modelAlign(index_offset + index_bytes, @alignOf(CacheEntry)); const entry_bytes = @as(u128, limits.cache_entries) * @sizeOf(CacheEntry); const payload_offset = modelAlign(entry_offset + entry_bytes, @alignOf(FaceSegment)); const storage_bytes = payload_offset + limits.cache_payload_bytes; const values = [_]u128{ segment_bytes, index_slots, index_offset, index_bytes, entry_offset, entry_bytes, payload_offset, storage_bytes }; for (values) |value| if (value > std.math.maxInt(usize)) return error.CapacityOverflow; return .{ .limits = limits, .segment_offset = 0, .segment_bytes = @intCast(segment_bytes), .index_slots = @intCast(index_slots), .index_offset = @intCast(index_offset), .index_bytes = @intCast(index_bytes), .entry_offset = @intCast(entry_offset), .entry_bytes = @intCast(entry_bytes), .payload_offset = @intCast(payload_offset), .payload_bytes = limits.cache_payload_bytes, .storage_bytes = @intCast(storage_bytes), };}fn modelAlign(offset: u128, alignment: u128) u128 { return ((offset + alignment - 1) / alignment) * alignment;}fn activatedStorage(allocator: Allocator, limits: Limits) !Storage { var storage = try Storage.init(allocator, limits); storage.activate(); return storage;}fn checkInitFailures(allocator: Allocator) !void { var storage = try Storage.init(allocator, .{ .max_source_units = 16, .cache_entries = 4, .cache_payload_bytes = 256 }); storage.deinit(allocator);}test "fallback segment capacity matches an independent aligned byte model" { comptime { @stardustClaim(alloc_phase.capacity.witness(Storage, "gui_text_fallback_capacity"), null, null, null, null, null, null); } const limits = Limits{ .max_source_units = 13, .cache_entries = 7, .cache_payload_bytes = 513 }; try std.testing.expectEqual(try modelCapacity(limits), try Capacity.derive(limits));}test "fallback segment storage acquires one exact region and retries OOM" { comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_acquisition"), null, null, null, null, null, null, ); } comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_oom"), null, null, null, null, null, null, ); } const limits = Limits{ .max_source_units = 13, .cache_entries = 7, .cache_payload_bytes = 513 }; const capacity = try Capacity.derive(limits); var counting = std.testing.FailingAllocator.init(std.testing.allocator, .{}); var storage = try Storage.init(counting.allocator(), limits); defer storage.deinit(counting.allocator()); try std.testing.expectEqual(@as(usize, 1), counting.alloc_index); try std.testing.expectEqual(capacity.storage_bytes, counting.allocated_bytes); storage.activate(); try std.testing.checkAllAllocationFailures(std.testing.allocator, checkInitFailures, .{});}test "fallback segment storage accepts exact maxima and rejects max plus one transactionally" { comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_boundaries"), null, null, null, null, null, null, ); } comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_reuse"), null, null, null, null, null, null, ); } comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_sealed_transitive_risk"), null, null, null, null, null, null, ); } comptime { @stardustClaim( alloc_phase.capacity.witness(Storage, "gui_text_fallback_sealed_foreign_risk"), null, null, null, null, null, null, ); } const segment = filigree.FallbackSegment{ .source = .{ .start = 0, .end = 1 }, .glyphs = .{ .start = 0, .end = 1 }, .candidate_index = 1, .missing_everywhere = false, }; const placement = try payloadPlacement(0, 1, 1); var storage = try activatedStorage(std.testing.allocator, .{ .max_source_units = 1, .cache_entries = 1, .cache_payload_bytes = placement.end }); defer storage.deinit(std.testing.allocator); const key = Key{ .content = "x", .primary_identity = 11, .fallback_identity = 22 }; const stored = try storage.store(key, &.{segment}); const stored_pointer = stored.ptr; const prior = stored[0]; const prior_status = storage.status(); try std.testing.expectError(error.SourceUnitCapacityExceeded, storage.segmentList(2)); try std.testing.expectError(error.SegmentCapacityExceeded, storage.store(key, &.{ segment, segment })); try std.testing.expectError(error.CacheEntryCapacityExceeded, storage.store(.{ .content = "y", .primary_identity = 11, .fallback_identity = 22 }, &.{segment})); try std.testing.expectEqual(prior, storage.lookup(key).?[0]); try std.testing.expectEqual(stored_pointer, storage.lookup(key).?.ptr); try std.testing.expectEqual(prior_status.entries, storage.status().entries); try std.testing.expectEqual(prior_status.payload_bytes, storage.status().payload_bytes); storage.reset(); try std.testing.expectEqual(@as(usize, 0), storage.status().entries); try std.testing.expectEqual(@as(u64, 1), storage.status().rollovers); _ = try storage.store(key, &.{segment});}test "fallback segment payload max plus one rejects without cache mutation" { const segment = filigree.FallbackSegment{ .source = .{ .start = 0, .end = 1 }, .glyphs = .{ .start = 0, .end = 1 }, .candidate_index = 1, .missing_everywhere = false, }; const placement = try payloadPlacement(0, 1, 1); var storage = try activatedStorage(std.testing.allocator, .{ .max_source_units = 2, .cache_entries = 2, .cache_payload_bytes = placement.end }); defer storage.deinit(std.testing.allocator); const key = Key{ .content = "x", .primary_identity = 11, .fallback_identity = 22 }; const prior = try storage.store(key, &.{segment}); const pointer = prior.ptr; try std.testing.expectError( error.CachePayloadCapacityExceeded, storage.store(.{ .content = "yy", .primary_identity = 11, .fallback_identity = 22 }, &.{segment}), ); try std.testing.expectEqual(pointer, storage.lookup(key).?.ptr); try std.testing.expectEqual(@as(usize, 1), storage.status().entries); try std.testing.expectEqual(placement.end, storage.status().payload_bytes);}test "fallback segment storage is exported through paint root" { comptime { @stardustClaim(alloc_phase.capacity.witness(Storage, "gui_text_fallback_root"), null, null, null, null, null, null); } try std.testing.expect(@import("root.zig").TextFallbackStorage == Storage);}Source: lib/gui/src/paint/root.zig:6
zig
pub const fallback = @import("fallback.zig");Audit
| Definitions | 28 |
|---|---|
| Public names | 52 |
| Members | 57 |
| Version | 26.7.0 |
| Revision | daab053ee433 |