tiny.preserves.records_mod
Defined in tiny.preserves.
Builders for ten kinds of record, each with a fixed label and a fixed number of fields.
API (6)
Actions
Public operations.
Records: Returns a namespace of protocol record builders forValue(D).Value: Returns the tagged union of all values whose embedded values have typeD.
Types and contracts
Public types and contracts.
AnyEmbedded: An embedded value that points to a payload of the host program, with optional functions to compare, hash, free and copy it.NoEmbedded: A type of embedded values whose one value carries no data, for programs that embed nothing.
Values and defaults
Public values and defaults.
any_records: The protocol record builders for values whose embedded values hold any pointer (AnyEmbedded).records: The protocol record builders forValue(NoEmbedded).
Source
Source: lib/preserves/src/records.zig
zig
//! Builders for ten kinds of record, each with a fixed label and a fixed number of fields. A caller//! building one of these records needs the label spelled the one way readers match it, and needs to//! know what the record takes from its arguments.const std = @import("std");const Allocator = std.mem.Allocator;const value_mod = @import("value.zig");const domain_mod = @import("domain.zig");const symbols_mod = @import("symbols.zig");const embedded_mod = @import("embedded.zig");const constructors_mod = @import("constructors.zig");pub const Value = value_mod.Value;pub const NoEmbedded = domain_mod.NoEmbedded;pub const AnyEmbedded = embedded_mod.AnyEmbedded;/// Returns a namespace of protocol record builders for `Value(D)`. Code whose values hold embedded/// values of one type calls it once at compile time, for every protocol record builder over those/// values. `D` has to provide `eql`, `order`, `deinit` and `clone`, or the call is a compile error./// Every builder allocates a copy of the label, one label cell and a copy of the field slice, all/// with `alloc`. The record takes the field values the caller passes, and `deinit` on the record/// frees the label, the fields and the record's own storage. On failure a builder frees its label/// and leaves the fields with the caller.pub fn Records(comptime D: type) type { domain_mod.assertIsDomain(D); const V = Value(D); const H = constructors_mod.Constructors(D); return struct { fn recordWithSymbol(alloc: Allocator, symbol_name: []const u8, fields: []const V) !V { var label = try V.initSymbol(alloc, symbol_name); errdefer label.deinit(alloc); return try H.record(alloc, label, fields); } /// Returns `<Observe pattern observer>`, for code that asks to observe a pattern. For /// `AnyEmbedded` values, an observer other than an embedded value is moved into a new cell /// and wrapped as an embedded value that owns it. The wrapped observer compares, hashes, /// copies and frees through the value it holds. An observer that is already an embedded /// value goes in as it is. When the embedded values have a type other than `AnyEmbedded`, /// every observer goes in as it is. On failure the call frees the wrapper cell and leaves /// `pattern` and `observer` with the caller. pub fn observeRecord(alloc: Allocator, pattern: V, observer: V) !V { var wrapped_ptr: ?*V = null; const obs: V = observer_wrap: { if (D == AnyEmbedded) { switch (observer) { .embedded => break :observer_wrap observer, else => { const val_ptr = try alloc.create(V); val_ptr.* = observer; wrapped_ptr = val_ptr; break :observer_wrap V{ .embedded = AnyEmbedded{ .value = @ptrCast(val_ptr), .semantic_ops = embedded_mod.parsedEmbeddedOps(V), .deinit_fn = embedded_mod.parsedEmbeddedDeinit(V), .clone_fn = embedded_mod.parsedEmbeddedClone(V), } }; }, } } break :observer_wrap observer; }; errdefer if (wrapped_ptr) |ptr| alloc.destroy(ptr); return recordWithSymbol(alloc, symbols_mod.SYM_OBSERVE.name, &.{ pattern, obs }); } /// Returns `<Synced>`, a record with zero fields. pub fn syncedRecord(alloc: Allocator) !V { return recordWithSymbol(alloc, symbols_mod.SYM_SYNCED.name, &.{}); } /// Returns `<RequireService name>`. pub fn requireServiceRecord(alloc: Allocator, name: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_REQUIRE_SERVICE.name, &.{name}); } /// Returns `<RunService name>`. pub fn runServiceRecord(alloc: Allocator, name: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_RUN_SERVICE.name, &.{name}); } /// Returns `<ServiceState name state>`. pub fn serviceStateRecord(alloc: Allocator, name: V, state: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_SERVICE_STATE.name, &.{ name, state }); } /// Returns `<ServiceObject name obj>`. pub fn serviceObjectRecord(alloc: Allocator, name: V, obj: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_SERVICE_OBJECT.name, &.{ name, obj }); } /// Returns `<ReactorError stage facet reactor err>`, a record with four fields. pub fn reactorErrorRecord(alloc: Allocator, stage: V, facet: V, reactor: V, err: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_REACTOR_ERROR.name, &.{ stage, facet, reactor, err }); } /// Returns `<EntityRuntime kind observe during>`. pub fn entityRuntimeRecord(alloc: Allocator, kind: V, observe: V, during: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_ENTITY_RUNTIME.name, &.{ kind, observe, during }); } /// Returns `<ServiceDependency depender dependee>`. pub fn serviceDependencyRecord(alloc: Allocator, depender: V, dependee: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_SERVICE_DEPENDENCY.name, &.{ depender, dependee }); } /// Returns `<RestartService name>`. pub fn restartServiceRecord(alloc: Allocator, name: V) !V { return recordWithSymbol(alloc, symbols_mod.SYM_RESTART_SERVICE.name, &.{name}); } };}/// The protocol record builders for `Value(NoEmbedded)`. Code whose values are `Value(NoEmbedded)`/// calls these builders, for a namespace fixed to that type.pub const records = Records(NoEmbedded);/// The protocol record builders for values whose embedded values hold any pointer (`AnyEmbedded`)./// The package root re-exports each builder under the same name, so a caller of/// `preserves.observeRecord` calls this instance.pub const any_records = Records(AnyEmbedded);test "syncedRecord builds <Synced>" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const r = try records.syncedRecord(a); try std.testing.expect(r == .record); try std.testing.expect(std.mem.eql(u8, r.record.label.*.symbol, "Synced")); try std.testing.expectEqual(@as(usize, 0), r.record.fields.len); _ = V;}test "requireServiceRecord and runServiceRecord take a single name" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const name = try V.initString(a, "svc-a"); const req = try records.requireServiceRecord(a, name); try std.testing.expect(std.mem.eql(u8, req.record.label.*.symbol, "RequireService")); try std.testing.expectEqual(@as(usize, 1), req.record.fields.len); const run = try records.runServiceRecord(a, name); try std.testing.expect(std.mem.eql(u8, run.record.label.*.symbol, "RunService"));}test "observeRecord (NoEmbedded) keeps observer unchanged" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const pattern: V = .{ .discard = {} }; const observer = V.initBoolean(true); const rec = try records.observeRecord(a, pattern, observer); try std.testing.expect(std.mem.eql(u8, rec.record.label.*.symbol, "Observe")); try std.testing.expectEqual(@as(usize, 2), rec.record.fields.len); try std.testing.expect(rec.record.fields[1] == .boolean);}test "observeRecord (AnyEmbedded) auto-wraps non-embedded observers" { const V = Value(AnyEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const pattern: V = .{ .discard = {} }; const observer = V.initBoolean(true); const rec = try any_records.observeRecord(a, pattern, observer); try std.testing.expect(std.mem.eql(u8, rec.record.label.*.symbol, "Observe")); try std.testing.expect(rec.record.fields[1] == .embedded); try std.testing.expect( rec.record.fields[1].embedded.semantic_ops == embedded_mod.parsedEmbeddedOps(V), ); var probe: u32 = 7; const pre_embedded = V{ .embedded = AnyEmbedded{ .value = &probe } }; const rec2 = try any_records.observeRecord(a, pattern, pre_embedded); try std.testing.expect(rec2.record.fields[1].embedded.semantic_ops == null);}test "protocol record labels are owned by returned values" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var name = try V.initString(allocator, "svc-a"); var name_moved = false; errdefer if (!name_moved) name.deinit(allocator); var observed = try records.observeRecord(allocator, .{ .discard = {} }, V.initBoolean(true)); defer observed.deinit(allocator); var required = try records.requireServiceRecord(allocator, name); name_moved = true; defer required.deinit(allocator);}test "observeRecord owns auto-wrapped embedded observer payload" { const V = Value(AnyEmbedded); const allocator = std.testing.allocator; var observed = try any_records.observeRecord(allocator, .{ .discard = {} }, V.initBoolean(true)); defer observed.deinit(allocator);}fn checkObserveRecordAllocationFailures(allocator: Allocator) !void { const V = Value(AnyEmbedded); var observer = try V.initString(allocator, "observer"); var observer_owned = true; defer if (observer_owned) observer.deinit(allocator); var observed = try any_records.observeRecord( allocator, .{ .discard = {} }, observer, ); observer_owned = false; defer observed.deinit(allocator); try std.testing.expect(observed.record.fields[1] == .embedded); try std.testing.expect(observed.record.fields[1].embedded.deinit_fn != null); try std.testing.expect(observed.record.fields[1].embedded.clone_fn != null);}test "observeRecord preserves caller ownership on every allocation failure" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkObserveRecordAllocationFailures, .{}, );}test "protocol record builders deinit under owning allocator" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var synced = try records.syncedRecord(allocator); defer synced.deinit(allocator); var require_service = try records.requireServiceRecord(allocator, V.initI128(1)); defer require_service.deinit(allocator); var run_service = try records.runServiceRecord(allocator, V.initI128(2)); defer run_service.deinit(allocator); var service_state = try records.serviceStateRecord(allocator, V.initI128(3), V.initI128(4)); defer service_state.deinit(allocator); var service_object = try records.serviceObjectRecord(allocator, V.initI128(5), V.initI128(6)); defer service_object.deinit(allocator); var reactor_error = try records.reactorErrorRecord( allocator, V.initI128(7), V.initI128(8), V.initI128(9), V.initI128(10), ); defer reactor_error.deinit(allocator); var entity_runtime = try records.entityRuntimeRecord(allocator, V.initI128(11), V.initI128(12), V.initI128(13)); defer entity_runtime.deinit(allocator); var service_dependency = try records.serviceDependencyRecord(allocator, V.initI128(14), V.initI128(15)); defer service_dependency.deinit(allocator); var restart_service = try records.restartServiceRecord(allocator, V.initI128(16)); defer restart_service.deinit(allocator);}test "reactorErrorRecord has correct arity" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const re = try records.reactorErrorRecord( a, V.initI128(1), V.initI128(2), V.initI128(3), V.initI128(4), ); try std.testing.expect(std.mem.eql(u8, re.record.label.*.symbol, "ReactorError")); try std.testing.expectEqual(@as(usize, 4), re.record.fields.len);}test "entityRuntime, serviceDependency, restartService, serviceState, serviceObject" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const er = try records.entityRuntimeRecord(a, V.initI128(1), V.initI128(2), V.initI128(3)); try std.testing.expect(std.mem.eql(u8, er.record.label.*.symbol, "EntityRuntime")); const sd = try records.serviceDependencyRecord(a, V.initI128(1), V.initI128(2)); try std.testing.expect(std.mem.eql(u8, sd.record.label.*.symbol, "ServiceDependency")); const rs = try records.restartServiceRecord(a, V.initI128(1)); try std.testing.expect(std.mem.eql(u8, rs.record.label.*.symbol, "RestartService")); const ss = try records.serviceStateRecord(a, V.initI128(1), V.initI128(2)); try std.testing.expect(std.mem.eql(u8, ss.record.label.*.symbol, "ServiceState")); const so = try records.serviceObjectRecord(a, V.initI128(1), V.initI128(2)); try std.testing.expect(std.mem.eql(u8, so.record.label.*.symbol, "ServiceObject"));}Source: lib/preserves/src/root.zig:116
zig
pub const records_mod = @import("records.zig");Audit
| Definitions | 1 |
|---|---|
| Public names | 1 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |