Skip to documentation
SLOP

tiny.choir.product.revision.record

Reference tiny.choir product revision record

Defined in product.revision.

API (34)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callsproduct.revisionrecord
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsprivate sourcelib.choir.src.product.revision.recordreadEntriesprivate sourcelib.choir.src.product.revision.recordreadEntryproduct.revision.recordEntries
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.choir.src.product.revision.recorddeclaresGateproduct.revision.record.InputViewrequireGateDeclarations
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.accy.src.preparation.publicationverifyPredecessorprivate sourcelib.accy.src.preparation.publicationverifyStagetest sourcelib.accy.src.preparation.testtest: Accy retained preparation owns ...private sourcelib.choir.src.product.revision.recordclosureFrametest sourcelib.choir.src.product.revision.recordtest: revision records expose exact a...+2 moreprivate sourcelib.choir.src.product.revision.recordreadFieldproduct.revision.recorddecodeAddress
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsprivate sourcelib.accy.src.preparation.publicationpredecessorPlanprivate sourcelib.accy.src.preparation.publicationverifyPredecessorprivate sourcelib.accy.src.preparation.testscreenStagetest sourcelib.accy.src.preparation.testtest: Accy retained preparation owns ...private sourcelib.accy.src.profiling.publication.suiteclosureOf+7 moreprivate sourcelib.choir.src.product.revision.recordreadFieldproduct.revision.recorddecodeExact
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsprivate sourcelib.accy.src.preparation.publicationverifyDialectsprivate sourcelib.accy.src.preparation.publicationverifyPredecessorprivate sourcelib.accy.src.profiling.publication.suiteclosureOfproduct.operationregisterKindprivate sourcelib.choir.src.product.revision.recordclosureFrame+6 moreprivate sourcelib.choir.src.product.revision.recordreadEntriesprivate sourcelib.choir.src.product.revision.recordreadFieldproduct.revision.recorddecodeInputs
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsprivate sourcelib.choir.src.composition.fixture.record.RecordsimportUnderprivate sourcelib.choir.src.product.incrementalfixtureRecordUndertest sourcelib.choir.src.product.revision.recordtest: revision records expose exact a...private sourcelib.choir.src.product.revision.store.DraftcopyRequestprivate sourcelib.choir.src.product.revision.recordsizeAddproduct.revision.recordencodeAddress
Static calls · unresolved targets: 5 · external targets: 1.
Called byCallsprivate sourcelib.choir.src.composition.fixture.record.RecordsimportUnderprivate sourcelib.choir.src.product.incrementalfixtureRecordUndertest sourcelib.choir.src.product.revision.recordtest: revision records encode into re...test sourcelib.choir.src.product.revision.recordtest: revision records expose exact a...test sourcelib.choir.src.product.revision.recordtest: revision records preserve negat...private sourcelib.choir.src.product.revision.recordwriteExactproduct.revision.recordencodeExact
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsprivate sourcelib.accy.src.profiling.publication.suitecopyRecordtest sourcelib.choir.src.product.revision.recordtest: revision records encode into re...private sourcelib.choir.src.product.revision.store.DraftprepareEntryproduct.revision.recordexactSizeprivate sourcelib.choir.src.product.revision.recordwriteExactproduct.revision.recordencodeExactInto
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsprivate sourcelib.choir.src.composition.fixture.record.RecordsimportUnderprivate sourcelib.choir.src.product.incrementalfixtureRecordUndertest sourcelib.choir.src.product.revision.recordtest: revision records expose exact a...test sourcelib.choir.src.product.revision.recordtest: revision records preserve negat...test sourcelib.choir.src.product.revision.recordtest: revision records sort map keys ...private sourcelib.choir.src.product.revision.store.DraftcopyRequestprivate sourcelib.choir.src.product.revision.recordfieldBlobprivate sourcelib.choir.src.product.revision.recordinputsSizeprivate sourcelib.choir.src.product.revision.recordsortedMapprivate sourcelib.choir.src.product.revision.recordwriteDependenciesprivate sourcelib.choir.src.product.revision.recordwriteFactsprivate sourcelib.choir.src.product.revision.recordwriteVersionsproduct.revision.recordencodeInputs
Static calls · unresolved targets: 4 · external targets: 2.
Called byCallsNo direct callsproduct.revision.recordencodeExactIntotest sourcelib.choir.src.product.revision.recordtest: revision records encode into re...private sourcelib.choir.src.product.revision.store.Draftpublishprivate sourcelib.choir.src.product.revision.storerecordSizeproduct.revision.recordexactSize
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.choir.src.product.recipeclassifyprivate sourcelib.choir.src.product.revision.recordwriteExactproduct.revision.recordrequireFields
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.choir.src.product.revision.store.StorageimportRecordprivate sourcelib.choir.src.product.revision.recordclosureFrameproduct.revision.recordvalidateClosure
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.choir.src.product.revision.recordtest: revision records refuse undecla...test sourcelib.choir.src.product.revision.recordtest: revision records sort map keys ...private sourcelib.choir.src.product.revision.store.Draftcaptureproduct.revision.recordvalidateObservations
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsproduct.operationregisterKindtest sourcelib.choir.src.product.revision.recordtest: revision records bound semantic...test sourcelib.choir.src.product.revision.recordtest: revision records reject cyclic ...test sourcelib.choir.src.product.revision.recordtest: revision records semantic proje...private sourcelib.choir.src.product.revision.recordwriteValueDepthproduct.revision.recordwriteValue
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/choir/src/product/revision/record.zig

zig
const std = @import("std");const simd = @import("simd");const binary = @import("../../serialization/binary/root.zig");const Bytes = simd.ScalableTag(u8);pub const schema_version: u32 = 2;/// Maximum number of nested values in a semantic projection.pub const maximum_projection_depth: u8 = 64;pub const ProjectionError = binary.WriteError || error{UnencodableProduct};pub const codec_limits = binary.Limits{    .serialized_bytes = std.math.maxInt(u32),    .string_bytes = std.math.maxInt(u32),    .blob_bytes = std.math.maxInt(u32),    .collection_entries = std.math.maxInt(u32),    .total_entries = std.math.maxInt(u32),};pub const Writer = binary.Writer(codec_limits);pub const Reader = binary.Reader(codec_limits);pub const Version = struct {    name: []const u8,    version: u32,    pub fn eql(self: Version, other: Version) bool {        return self.version == other.version and std.mem.eql(u8, self.name, other.name);    }};pub const Address = struct {    producer: []const u8,    source: []const u8,    stage: []const u8,    variant: []const u8,    pub fn eql(self: Address, other: Address) bool {        inline for (@typeInfo(Address).@"struct".field_names) |field| {            if (!std.mem.eql(u8, @field(self, field), @field(other, field))) return false;        }        return true;    }};/// A missing value records a negative observation, distinct from empty bytes.pub const Fact = struct {    key: []const u8,    value: ?[]const u8,    pub fn eql(self: Fact, other: Fact) bool {        if (!std.mem.eql(u8, self.key, other.key)) return false;        if (self.value) |value| {            return std.mem.eql(u8, value, other.value orelse return false);        }        return other.value == null;    }};/// Dependency records contain exact semantic bytes, excluding publication events.pub const Dependency = struct {    role: []const u8,    exact: []const u8,};/// The compiler manifest is admission input, not encoded content. An owner/// interns it and decides identity through the interned bytes, so `encodeInputs`/// reads every other field and leaves this one to the store.pub const Inputs = struct {    compiler_manifest: []const u8,    versions: []const Version,    pipeline: []const Version,    options: []const u8,    policy: []const u8,    facts: []const Fact = &.{},};/// Decoded input fields. A record does not carry its compiler manifest, so this/// view cannot answer which compiler produced it; ask the owner that holds it.pub const InputView = struct {    versions: Entries(Version),    pipeline: Entries(Version),    options: []const u8,    policy: []const u8,    facts: Entries(Fact),    dependencies: Entries(Dependency),    gate_manifest: []const u8,    /// Checks declared gate identities only. Transported bytes do not establish    /// that gates ran; callers obtain publication authority from a live Revision.    pub fn requireGateDeclarations(self: InputView, required: []const Version) !void {        for (required) |identity| {            if (!try declaresGate(self.gate_manifest, identity)) return error.MissingGateEvidence;        }    }};fn declaresGate(bytes: []const u8, required: Version) !bool {    var reader = try Reader.init(bytes);    if (try reader.readInt(u32) != schema_version) return error.UnknownSchema;    _ = try reader.readString();    _ = try reader.readInt(u32);    var found = (try readGateIdentity(&reader)).eql(required);    const count = try reader.readCount();    for (0..count) |_| {        const identity = try readGateIdentity(&reader);        found = identity.eql(required) or found;    }    if (!reader.atEnd()) return error.InvalidRecord;    return found;}fn readGateIdentity(reader: *Reader) !Version {    const identity = Version{        .name = try reader.readString(),        .version = try reader.readInt(u32),    };    _ = try reader.readBlob();    _ = try reader.readInt(u32);    return identity;}pub const ClosureBounds = struct {    bytes: u32,    records: u32,    depth: u8,};const ClosureFrame = struct {    dependencies: Entries(Dependency).Iterator,};/// Embedded dependencies strictly decrease in byte extent, so exact cycles cannot/// be represented. The iterative walk validates every closed record under bounds.pub fn validateClosure(bytes: []const u8, bounds: ClosureBounds) !void {    if (bytes.len > bounds.bytes) return error.RecordLimit;    if (bounds.records == 0 or bounds.depth == 0) return error.RecordClosureLimit;    var stack: [255]ClosureFrame = undefined;    stack[0] = try closureFrame(bytes);    var depth: usize = 1;    var count: u32 = 1;    while (depth != 0) {        const dependency = try stack[depth - 1].dependencies.next() orelse {            depth -= 1;            continue;        };        if (count == bounds.records or depth == bounds.depth) return error.RecordClosureLimit;        stack[depth] = try closureFrame(dependency.exact);        depth += 1;        count += 1;    }}fn closureFrame(bytes: []const u8) !ClosureFrame {    const exact = try decodeExact(bytes);    _ = try decodeAddress(exact.address);    const inputs = try decodeInputs(exact.inputs);    return .{ .dependencies = inputs.dependencies.iterator() };}pub fn Entries(comptime T: type) type {    return struct {        bytes: []const u8,        count: u32,        pub fn iterator(self: @This()) Iterator {            return .{                .reader = Reader.init(self.bytes) catch unreachable,                .remaining = self.count,            };        }        pub const Iterator = struct {            reader: Reader,            remaining: u32,            pub fn next(self: *Iterator) !?T {                if (self.remaining == 0) return null;                const result = try readEntry(T, &self.reader);                self.remaining -= 1;                return result;            }        };    };}pub fn decodeAddress(bytes: []const u8) !Address {    var reader = try Reader.init(bytes);    if (try reader.readInt(u32) != schema_version) return error.UnknownSchema;    var result: Address = undefined;    inline for (@typeInfo(Address).@"struct".field_names, 1..) |field, tag| {        @field(result, field) = try readField(&reader, tag);    }    if (result.producer.len == 0 or result.stage.len == 0) return error.InvalidAddress;    if (!reader.atEnd()) return error.InvalidRecord;    return result;}pub fn decodeInputs(bytes: []const u8) !InputView {    var reader = try Reader.init(bytes);    if (try reader.readInt(u32) != schema_version) return error.UnknownSchema;    const versions = try readEntries(Version, &reader, 2, "name");    const pipeline = try readEntries(Version, &reader, 3, null);    const options = try readField(&reader, 4);    const policy = try readField(&reader, 5);    const facts = try readEntries(Fact, &reader, 6, "key");    const dependencies = try readEntries(Dependency, &reader, 7, "role");    const gate_manifest = try readField(&reader, 8);    if (!reader.atEnd()) return error.InvalidRecord;    return .{        .versions = versions,        .pipeline = pipeline,        .options = options,        .policy = policy,        .facts = facts,        .dependencies = dependencies,        .gate_manifest = gate_manifest,    };}fn readEntries(    comptime T: type,    reader: *Reader,    tag: u8,    comptime ordered: ?[]const u8,) !Entries(T) {    if (try reader.readInt(u8) != tag) return error.UnknownRequiredField;    const count = try reader.readCount();    const start = reader.offset;    var previous: ?[]const u8 = null;    for (0..count) |_| {        const item = try readEntry(T, reader);        if (ordered) |field| try orderedKey(&previous, @field(item, field));    }    return .{ .bytes = reader.bytes[start..reader.offset], .count = @intCast(count) };}fn readEntry(comptime T: type, reader: *Reader) !T {    if (T == Version) {        const name = try reader.readString();        const version = try reader.readInt(u32);        if (version == 0 or name.len == 0) return error.InvalidVersion;        return .{ .name = name, .version = version };    } else if (T == Fact) {        return .{ .key = try reader.readString(), .value = try reader.readOptionalString() };    } else if (T == Dependency) {        const role = try reader.readString();        const exact = try reader.readBlob();        _ = try decodeExact(exact);        return .{ .role = role, .exact = exact };    } else @compileError("unknown canonical record collection");}pub const Namespace = enum(u8) { root, operation, region, block, value, attribute };pub const EntityCounts = [@typeInfo(Namespace).@"enum".field_names.len]u32;pub const Exact = struct {    address: []const u8,    inputs: []const u8,    image: []const u8,    pub fn eql(self: Exact, other: Exact) bool {        return simd.equal(Bytes, self.address, other.address) and            simd.equal(Bytes, self.inputs, other.inputs) and            simd.equal(Bytes, self.image, other.image);    }};const ValueTag = enum(u8) {    boolean = 1,    unsigned = 2,    signed = 3,    float_bits = 4,    enum_name = 5,    optional = 6,    sequence = 7,    structure = 8,    choice = 9,    bytes = 10,    unit = 11,};/// Keep each owner's projection exhaustive when its option or plan type changes.pub fn requireFields(comptime T: type, comptime names: []const []const u8) void {    const fields = @typeInfo(T).@"struct".field_names;    if (fields.len != names.len) {        @compileError("classify every field before publishing this record");    }    inline for (fields, names) |field, expected| {        if (!std.mem.eql(u8, field, expected)) {            @compileError("update the explicit semantic projection");        }    }}/// Encode an owner's explicit semantic projection, never compiler pointers.pub fn writeValue(writer: *Writer, value: anytype) ProjectionError!void {    try writeValueDepth(writer, value, 0);}fn writeValueDepth(writer: *Writer, value: anytype, depth: u8) ProjectionError!void {    if (depth >= maximum_projection_depth) return error.UnencodableProduct;    const T = @TypeOf(value);    switch (@typeInfo(T)) {        .void => try valueTag(writer, .unit),        .bool => {            try valueTag(writer, .boolean);            try writer.writeBool(value);        },        .int => |info| {            if (info.bits > 64) @compileError("declare a bounded wide-integer encoding");            try valueTag(writer, if (info.signedness == .signed) .signed else .unsigned);            if (info.signedness == .signed) try writer.writeInt(i64, value) else {                try writer.writeInt(u64, value);            }        },        .float => |info| {            try valueTag(writer, .float_bits);            try writer.writeInt(u16, info.bits);            const Bits = @Int(.unsigned, info.bits);            try writer.writeInt(Bits, @bitCast(value));        },        .@"enum" => {            try valueTag(writer, .enum_name);            try writer.writeString(@tagName(value));        },        .optional => {            try valueTag(writer, .optional);            try writer.writeBool(value != null);            if (value) |present| try writeValueDepth(writer, present, depth + 1);        },        .array, .pointer => try writeSequence(writer, value, depth),        .@"struct" => |info| {            try valueTag(writer, .structure);            try writer.writeCount(info.field_names.len);            inline for (info.field_names) |field| {                try writer.writeString(field);                try writeValueDepth(writer, @field(value, field), depth + 1);            }        },        .@"union" => {            try valueTag(writer, .choice);            try writer.writeString(@tagName(value));            switch (value) {                inline else => |payload| try writeValueDepth(writer, payload, depth + 1),            }        },        else => @compileError("classify this semantic field before publication"),    }}fn writeSequence(writer: *Writer, value: anytype, depth: u8) ProjectionError!void {    std.debug.assert(depth < maximum_projection_depth);    const info = @typeInfo(@TypeOf(value));    if (info == .pointer) {        if (info.pointer.size != .slice) {            @compileError("project references into exact revision ordinals");        }        if (info.pointer.child == u8) {            try valueTag(writer, .bytes);            try writer.writeBlob(value);            return;        }    }    try valueTag(writer, .sequence);    try writer.writeCount(value.len);    for (value) |item| try writeValueDepth(writer, item, depth + 1);}fn valueTag(writer: *Writer, value: ValueTag) !void {    try writer.writeTag(value);}pub fn encodeAddress(allocator: std.mem.Allocator, value: Address) ![]u8 {    if (value.producer.len == 0 or value.stage.len == 0) return error.InvalidAddress;    var writer = Writer.init(allocator);    defer writer.deinit();    var length: usize = 24;    inline for (@typeInfo(Address).@"struct".field_names) |field| {        length = try sizeAdd(length, @field(value, field).len);    }    try writer.bytes.ensureTotalCapacityPrecise(allocator, length);    try writer.writeInt(u32, schema_version);    inline for (@typeInfo(Address).@"struct".field_names, 1..) |field, tag| {        try writer.writeInt(u8, tag);        try writer.writeString(@field(value, field));    }    std.debug.assert(writer.bytes.items.len == length);    return writer.finish();}pub fn encodeInputs(    allocator: std.mem.Allocator,    inputs: Inputs,    dependencies: []const Dependency,    gate_manifest: []const u8,) ![]u8 {    comptime std.debug.assert(@typeInfo(Inputs).@"struct".field_names.len == 6);    const versions = try sortedMap(Version, allocator, inputs.versions, "name");    defer allocator.free(versions);    const facts = try sortedMap(Fact, allocator, inputs.facts, "key");    defer allocator.free(facts);    const ordered_dependencies = try sortedMap(Dependency, allocator, dependencies, "role");    defer allocator.free(ordered_dependencies);    var writer = Writer.init(allocator);    defer writer.deinit();    const length = try inputsSize(inputs, dependencies, gate_manifest);    try writer.bytes.ensureTotalCapacityPrecise(allocator, length);    try writer.writeInt(u32, schema_version);    try writer.writeInt(u8, 2);    try writeVersions(&writer, versions, true);    try writer.writeInt(u8, 3);    try writeVersions(&writer, inputs.pipeline, false);    try fieldBlob(&writer, 4, inputs.options);    try fieldBlob(&writer, 5, inputs.policy);    try writer.writeInt(u8, 6);    try writeFacts(&writer, facts);    try writer.writeInt(u8, 7);    try writeDependencies(&writer, ordered_dependencies);    try fieldBlob(&writer, 8, gate_manifest);    std.debug.assert(writer.bytes.items.len == length);    return writer.finish();}fn inputsSize(inputs: Inputs, dependencies: []const Dependency, gates: []const u8) !usize {    var size: usize = 39;    for ([_][]const u8{ inputs.options, inputs.policy, gates }) |bytes| {        size = try sizeAdd(size, bytes.len);    }    for ([_][]const Version{ inputs.versions, inputs.pipeline }) |versions| {        for (versions) |version| size = try sizeAdd(size, try sizeAdd(8, version.name.len));    }    for (inputs.facts) |fact| {        size = try sizeAdd(size, try sizeAdd(5, fact.key.len));        if (fact.value) |bytes| size = try sizeAdd(size, try sizeAdd(4, bytes.len));    }    for (dependencies) |dependency| {        size = try sizeAdd(size, try sizeAdd(8, dependency.role.len));        size = try sizeAdd(size, dependency.exact.len);    }    return size;}fn sizeAdd(first: usize, second: usize) !usize {    const size = std.math.add(usize, first, second) catch return error.RecordOverflow;    if (size > codec_limits.serialized_bytes) return error.RecordLimit;    return size;}fn sortedMap(    comptime T: type,    allocator: std.mem.Allocator,    source: []const T,    comptime key: []const u8,) ![]T {    const copy = try allocator.dupe(T, source);    errdefer allocator.free(copy);    std.mem.sort(T, copy, {}, struct {        fn less(_: void, first: T, second: T) bool {            return std.mem.lessThan(u8, @field(first, key), @field(second, key));        }    }.less);    var previous: ?[]const u8 = null;    for (copy) |item| try orderedKey(&previous, @field(item, key));    return copy;}fn fieldBlob(writer: anytype, tag: u8, bytes: []const u8) !void {    try writer.writeInt(u8, tag);    try writer.writeBlob(bytes);}fn writeVersions(writer: *Writer, versions: []const Version, sorted: bool) !void {    try writer.writeCount(versions.len);    var previous: ?[]const u8 = null;    for (versions) |version| {        if (version.version == 0 or version.name.len == 0) return error.InvalidVersion;        if (sorted) try orderedKey(&previous, version.name);        try writer.writeString(version.name);        try writer.writeInt(u32, version.version);    }}fn writeFacts(writer: *Writer, facts: []const Fact) !void {    try writer.writeCount(facts.len);    var previous: ?[]const u8 = null;    for (facts) |fact| {        try orderedKey(&previous, fact.key);        try writer.writeString(fact.key);        try writer.writeOptionalString(fact.value);    }}fn writeDependencies(writer: *Writer, dependencies: []const Dependency) !void {    try writer.writeCount(dependencies.len);    var previous: ?[]const u8 = null;    for (dependencies) |dependency| {        try orderedKey(&previous, dependency.role);        _ = try decodeExact(dependency.exact);        try writer.writeString(dependency.role);        try writer.writeBlob(dependency.exact);    }}fn orderedKey(previous: *?[]const u8, key: []const u8) !void {    if (key.len == 0) return error.InvalidKey;    if (previous.*) |prior| {        if (!std.mem.lessThan(u8, prior, key)) return error.NoncanonicalOrder;    }    previous.* = key;}pub fn encodeExact(allocator: std.mem.Allocator, exact: Exact) ![]u8 {    var writer = Writer.init(allocator);    defer writer.deinit();    try writeExact(&writer, exact);    return writer.finish();}/// The caller retains ownership of the output storage. Preflight refuses a short/// buffer before writing; the writer has no allocator capacity for growth.pub fn encodeExactInto(output: []u8, exact: Exact) ![]u8 {    const length = try exactSize(exact.address.len, exact.inputs.len, exact.image.len);    if (length > output.len) return error.RecordLimit;    var writer = binary.FixedWriter(codec_limits).init(output);    defer writer.deinit();    try writeExact(&writer, exact);    std.debug.assert(writer.bytes.items.len == length);    std.debug.assert(writer.bytes.items.ptr == output.ptr);    return writer.finish();}pub fn exactSize(address: usize, inputs: usize, image: usize) !usize {    const prefix = std.math.add(usize, address, inputs) catch return error.RecordOverflow;    const payload = std.math.add(usize, prefix, image) catch return error.RecordOverflow;    const length = std.math.add(usize, payload, 19) catch return error.RecordOverflow;    if (address > std.math.maxInt(u32) or inputs > std.math.maxInt(u32) or        image > std.math.maxInt(u32)) return error.RecordLimit;    return length;}fn writeExact(writer: anytype, exact: Exact) !void {    comptime requireFields(Exact, &.{ "address", "inputs", "image" });    try writer.writeInt(u32, schema_version);    try fieldBlob(writer, 1, exact.address);    try fieldBlob(writer, 2, exact.inputs);    try fieldBlob(writer, 3, exact.image);}pub fn decodeExact(bytes: []const u8) !Exact {    var reader = try Reader.init(bytes);    if (try reader.readInt(u32) != schema_version) return error.UnknownSchema;    const address = try readField(&reader, 1);    const inputs = try readField(&reader, 2);    const image = try readField(&reader, 3);    if (!reader.atEnd()) return error.InvalidRecord;    return .{ .address = address, .inputs = inputs, .image = image };}fn readField(reader: *Reader, tag: u8) ![]const u8 {    if (try reader.readInt(u8) != tag) return error.UnknownRequiredField;    return reader.readBlob();}pub fn validateObservations(declared: []const Fact, observed: []const Fact) !void {    if (declared.len != observed.len) return error.IncompleteObservations;    for (declared) |requested| {        for (observed) |actual| {            if (requested.eql(actual)) break;        } else return error.UndeclaredObservation;    }}test "revision records preserve negative reads, pipeline order and exact bytes" {    const allocator = std.testing.allocator;    const versions = [_]Version{.{ .name = "compiler", .version = 1 }};    const pipeline = [_]Version{        .{ .name = "b", .version = 2 },        .{ .name = "a", .version = 1 },    };    const inputs = Inputs{        .compiler_manifest = "owned build inputs",        .versions = &versions,        .pipeline = &pipeline,        .options = "expanded defaults",        .policy = "strict",        .facts = &.{.{ .key = "absent", .value = null }},    };    const first = try encodeInputs(allocator, inputs, &.{}, "gates");    defer allocator.free(first);    var changed = inputs;    changed.facts = &.{.{ .key = "absent", .value = "" }};    const second = try encodeInputs(allocator, changed, &.{}, "gates");    defer allocator.free(second);    try std.testing.expect(!std.mem.eql(u8, first, second));    changed = inputs;    const reversed = [_]Version{ pipeline[1], pipeline[0] };    changed.pipeline = &reversed;    const third = try encodeInputs(allocator, changed, &.{}, "gates");    defer allocator.free(third);    try std.testing.expect(!std.mem.eql(u8, first, third));    const exact = Exact{ .address = "address", .inputs = first, .image = "image" };    const bytes = try encodeExact(allocator, exact);    defer allocator.free(bytes);    try std.testing.expect(exact.eql(try decodeExact(bytes)));    bytes[4] = 99;    try std.testing.expectError(error.UnknownRequiredField, decodeExact(bytes));}test "revision records refuse undeclared observations and noncanonical maps" {    try std.testing.expectError(error.UndeclaredObservation, validateObservations(        &.{.{ .key = "capability", .value = null }},        &.{.{ .key = "capability", .value = "present" }},    ));    var writer = Writer.init(std.testing.allocator);    defer writer.deinit();    try std.testing.expectError(error.NoncanonicalOrder, writeFacts(&writer, &.{        .{ .key = "z", .value = null },        .{ .key = "a", .value = "value" },    }));}test "revision records sort map keys while observations retain negative values" {    const allocator = std.testing.allocator;    const facts = [_]Fact{        .{ .key = "z", .value = null },        .{ .key = "a", .value = "" },    };    const versions = [_]Version{        .{ .name = "z", .version = 2 },        .{ .name = "a", .version = 1 },    };    var inputs = Inputs{        .compiler_manifest = "compiled inputs",        .versions = &versions,        .pipeline = &.{},        .options = "defaults",        .policy = "strict",        .facts = &facts,    };    const first = try encodeInputs(allocator, inputs, &.{}, "gates");    defer allocator.free(first);    const reversed_facts = [_]Fact{ facts[1], facts[0] };    const reversed_versions = [_]Version{ versions[1], versions[0] };    inputs.facts = &reversed_facts;    inputs.versions = &reversed_versions;    const second = try encodeInputs(allocator, inputs, &.{}, "gates");    defer allocator.free(second);    try std.testing.expectEqualSlices(u8, first, second);    try validateObservations(&facts, &reversed_facts);    try std.testing.expectError(error.UndeclaredObservation, validateObservations(        &facts,        &.{ facts[0], facts[0] },    ));    inputs.facts = &.{ facts[0], facts[0] };    try std.testing.expectError(error.NoncanonicalOrder, encodeInputs(        allocator,        inputs,        &.{},        "gates",    ));}test "revision records semantic projections preserve float bits and tagged choices" {    const Choice = union(enum) { absent, threshold: u32 };    const Options = struct { value: f64, choice: Choice, sequence: [2]u16, note: ?[]const u8 };    var first = Writer.init(std.testing.allocator);    defer first.deinit();    var second = Writer.init(std.testing.allocator);    defer second.deinit();    var options = Options{        .value = @bitCast(@as(u64, 0x7ff8000000000042)),        .choice = .{ .threshold = 11 },        .sequence = .{ 2, 1 },        .note = null,    };    try writeValue(&first, options);    try writeValue(&second, options);    try std.testing.expectEqualSlices(u8, first.bytes.items, second.bytes.items);    second.bytes.clearRetainingCapacity();    options.value = @bitCast(@as(u64, 0x7ff8000000000043));    try writeValue(&second, options);    try std.testing.expect(!std.mem.eql(u8, first.bytes.items, second.bytes.items));    second.bytes.clearRetainingCapacity();    options.value = @bitCast(@as(u64, 0x7ff8000000000042));    options.choice = .absent;    try writeValue(&second, options);    try std.testing.expect(!std.mem.eql(u8, first.bytes.items, second.bytes.items));}test "revision records expose exact address and input closure without mutable owners" {    const allocator = std.testing.allocator;    const address = Address{        .producer = "compiler",        .source = "entry",        .stage = "ir",        .variant = "a",    };    const encoded_address = try encodeAddress(allocator, address);    defer allocator.free(encoded_address);    try std.testing.expect(address.eql(try decodeAddress(encoded_address)));    const dependency = try encodeExact(allocator, .{        .address = encoded_address,        .inputs = "input",        .image = "image",    });    defer allocator.free(dependency);    const inputs = try encodeInputs(allocator, .{        .compiler_manifest = "compiled inputs",        .versions = &.{},        .pipeline = &.{.{ .name = "pass", .version = 2 }},        .options = "defaults",        .policy = "strict",        .facts = &.{.{ .key = "absent", .value = null }},    }, &.{.{ .role = "source", .exact = dependency }}, "gates");    defer allocator.free(inputs);    const view = try decodeInputs(inputs);    var pipeline = view.pipeline.iterator();    try std.testing.expectEqualStrings("pass", (try pipeline.next()).?.name);    try std.testing.expectEqual(null, try pipeline.next());    var facts = view.facts.iterator();    try std.testing.expectEqual(null, (try facts.next()).?.value);    var dependencies = view.dependencies.iterator();    try std.testing.expectEqualSlices(u8, dependency, (try dependencies.next()).?.exact);    try std.testing.expectEqual(null, try dependencies.next());}test "revision records encode into reserved capacity without changing exact bytes" {    const exact = Exact{        .address = "address",        .inputs = "exact inputs",        .image = "canonical image",    };    const expected = try encodeExact(std.testing.allocator, exact);    defer std.testing.allocator.free(expected);    var storage: [256]u8 = undefined;    const actual = try encodeExactInto(storage[0..expected.len], exact);    try std.testing.expect(@intFromPtr(actual.ptr) == @intFromPtr(&storage));    try std.testing.expectEqualSlices(u8, expected, actual);    try std.testing.expectEqual(expected.len, try exactSize(        exact.address.len,        exact.inputs.len,        exact.image.len,    ));    @memset(&storage, 0xa5);    try std.testing.expectError(error.RecordLimit, encodeExactInto(        storage[0 .. expected.len - 1],        exact,    ));    for (storage) |byte| try std.testing.expectEqual(@as(u8, 0xa5), byte);    try std.testing.expectError(error.RecordOverflow, exactSize(std.math.maxInt(usize), 1, 0));}test "revision records bound semantic projection depth at the exact limit" {    const AtLimit = comptime blk: {        var T: type = u16;        for (1..maximum_projection_depth) |_| T = [1]T;        break :blk T;    };    var writer = Writer.init(std.testing.allocator);    defer writer.deinit();    try writeValue(&writer, std.mem.zeroes(AtLimit));    try std.testing.expect(writer.bytes.items.len > 0);    writer.bytes.clearRetainingCapacity();    try std.testing.expectError(error.UnencodableProduct, writeValue(        &writer,        std.mem.zeroes([1]AtLimit),    ));}test "revision records reject cyclic semantic projections within bounded depth" {    const Node = struct { children: []const @This() };    var nodes: [1]Node = undefined;    nodes[0] = .{ .children = &nodes };    var writer = Writer.init(std.testing.allocator);    defer writer.deinit();    try std.testing.expectError(error.UnencodableProduct, writeValue(&writer, nodes[0]));}

Source: lib/choir/src/product/revision/root.zig:1

zig
pub const record = @import("record.zig");

Complete caller list for product.revision.record.decodeAddress

7 direct callers.

Complete caller list for product.revision.record.decodeExact

12 direct callers.

Complete caller list for product.revision.record.decodeInputs

11 direct callers.

Audit

Definitions35
Public names35
Members35
Version26.7.0
Revisiondaab053ee433