tiny.preserves.predicates
Defined in tiny.preserves.
Predicates that test a value's shape.
API (11)
Actions
Public operations.
Value: Returns the tagged union of all values whose embedded values have typeD.isAtom: Returns true for a boolean, double, integer, string, byte string or symbol.isCompound: Returns true for a record, sequence, set or dictionary.isEmbedded: Returns true whenvalueis an embedded value.isNull: Returns true whenvalueis the symbolnull, the value the package uses for JSON's null.isObserve: Returns true whenvalueis an<Observe pattern observer>record: labeledObserve, with two fields.isPatternForm: Returns true for a discard, capture, bind or rest pattern.isRecord: Returns true whenvalueis a record.isSymbol: Returns true whenvalueis a symbol.recordAttributes: Returns the entries of a record's attribute dictionary.
Types and contracts
Public types and contracts.
NoEmbedded: A type of embedded values whose one value carries no data, for programs that embed nothing.
Source
Source: lib/preserves/src/predicates.zig
zig
//! Predicates that test a value's shape. None of them allocates.//!//! Code that dispatches on values needs one tested answer for each shape question, so every caller//! draws the line between atoms, compound values and patterns the same way.const std = @import("std");const value_mod = @import("value.zig");const domain_mod = @import("domain.zig");const symbols_mod = @import("symbols.zig");pub const Value = value_mod.Value;pub const NoEmbedded = domain_mod.NoEmbedded;/// Returns the entries of a record's attribute dictionary. The JSON encoder calls this function for/// the attributes of a record it writes as a `{"type": …}` object. A record with zero fields has an/// empty attribute list. A record whose one field is a dictionary with string keys has that/// dictionary's entries. The call returns null for any other value, including a record whose/// dictionary has a key other than a string. The entries point into `value`, and the call allocates/// nothing.pub fn recordAttributes(comptime D: type, value: Value(D)) ?[]const Value(D).DictionaryEntry { domain_mod.assertIsDomain(D); switch (value) { .record => |r| { if (r.fields.len == 0) return &.{}; if (r.fields.len != 1) return null; switch (r.fields[0]) { .dictionary => |d| { for (d) |entry| { switch (entry.key) { .string => {}, else => return null, } } return d; }, else => return null, } }, else => return null, }}/// Returns true when `value` is a record. When `label` is given, its label is the symbol `label`,/// and when `arity` is given, it has `arity` fields. The `Observe` field readers call this function/// for a label and field-count check, and so does `isObserve`. A record with a label other than a/// symbol matches only when `label` is null. The package root's version takes the label as a/// `Symbol`.pub fn isRecord(comptime D: type, value: Value(D), label: ?[]const u8, arity: ?usize) bool { domain_mod.assertIsDomain(D); switch (value) { .record => |r| { if (label) |l| { switch (r.label.*) { .symbol => |s| if (!std.mem.eql(u8, s, l)) return false, else => return false, } } if (arity) |a| { if (r.fields.len != a) return false; } return true; }, else => return false, }}/// Returns true when `value` is an `<Observe pattern observer>` record: labeled `Observe`, with two/// fields.pub fn isObserve(comptime D: type, value: Value(D)) bool { return isRecord(D, value, symbols_mod.SYM_OBSERVE.name, 2);}/// Returns true when `value` is an embedded value.pub fn isEmbedded(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return value == .embedded;}/// Returns true when `value` is a symbol.pub fn isSymbol(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return value == .symbol;}/// Returns true when `value` is the symbol `null`, the value the package uses for JSON's null.pub fn isNull(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return switch (value) { .symbol => |s| std.mem.eql(u8, s, symbols_mod.SYM_NULL.name), else => false, };}/// Returns true for a record, sequence, set or dictionary. The call returns false for patterns and/// embedded values, even a capture that holds a record.pub fn isCompound(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return switch (value) { .record, .sequence, .set, .dictionary => true, else => false, };}/// Returns true for a discard, capture, bind or rest pattern.pub fn isPatternForm(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return switch (value) { .discard, .capture, .bind, .rest_pattern => true, else => false, };}/// Returns true for a boolean, double, integer, string, byte string or symbol. The call returns/// false for an embedded value.pub fn isAtom(comptime D: type, value: Value(D)) bool { domain_mod.assertIsDomain(D); return switch (value) { .boolean, .double, .signed_integer, .string, .byte_string, .symbol => true, else => false, };}test "isRecord matches label and arity optionally" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const label = try V.initSymbol(a, "Foo"); const fields = try a.alloc(V, 2); fields[0] = V.initI128(1); fields[1] = V.initI128(2); const rec = try V.initRecord(a, label, fields); try std.testing.expect(isRecord(NoEmbedded, rec, "Foo", 2)); try std.testing.expect(isRecord(NoEmbedded, rec, null, 2)); try std.testing.expect(isRecord(NoEmbedded, rec, "Foo", null)); try std.testing.expect(isRecord(NoEmbedded, rec, null, null)); try std.testing.expect(!isRecord(NoEmbedded, rec, "Bar", 2)); try std.testing.expect(!isRecord(NoEmbedded, rec, "Foo", 3)); try std.testing.expect(!isRecord(NoEmbedded, V.initBoolean(true), null, null));}test "isObserve matches `<Observe _ _>` records" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const label = try V.initSymbol(a, "Observe"); const fields = try a.alloc(V, 2); fields[0] = V{ .discard = {} }; fields[1] = V.initBoolean(true); const rec = try V.initRecord(a, label, fields); try std.testing.expect(isObserve(NoEmbedded, rec)); const wrong_arity = try V.initRecord(a, try V.initSymbol(a, "Observe"), try a.alloc(V, 0)); try std.testing.expect(!isObserve(NoEmbedded, wrong_arity));}test "isNull, isSymbol, isEmbedded, isAtom, isCompound, isPatternForm" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const null_v = V{ .symbol = "null" }; try std.testing.expect(isNull(NoEmbedded, null_v)); try std.testing.expect(isSymbol(NoEmbedded, null_v)); try std.testing.expect(isAtom(NoEmbedded, null_v)); try std.testing.expect(!isCompound(NoEmbedded, null_v)); try std.testing.expect(!isPatternForm(NoEmbedded, null_v)); try std.testing.expect(!isEmbedded(NoEmbedded, null_v)); const not_null = V{ .symbol = "hello" }; try std.testing.expect(!isNull(NoEmbedded, not_null)); const seq = V.initSequence(try a.alloc(V, 0)); try std.testing.expect(isCompound(NoEmbedded, seq)); try std.testing.expect(!isAtom(NoEmbedded, seq)); const discard_v: V = .{ .discard = {} }; try std.testing.expect(isPatternForm(NoEmbedded, discard_v)); try std.testing.expect(!isAtom(NoEmbedded, discard_v)); try std.testing.expect(!isCompound(NoEmbedded, discard_v));}test "recordAttributes extracts dict entries only for single-dict-field records" { const V = Value(NoEmbedded); const allocator = std.testing.allocator; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const a = arena.allocator(); const empty_entries: V.Dictionary = try a.alloc(V.DictionaryEntry, 0); const d_empty = V.initDictionary(empty_entries); const fields_empty = try a.alloc(V, 1); fields_empty[0] = d_empty; const rec_empty = try V.initRecord(a, try V.initSymbol(a, "Label"), fields_empty); const got_empty = recordAttributes(NoEmbedded, rec_empty).?; try std.testing.expectEqual(@as(usize, 0), got_empty.len); const entries = try a.alloc(V.DictionaryEntry, 1); entries[0] = .{ .key = try V.initString(a, "k"), .value = V.initI128(1) }; const d_one = V.initDictionary(entries); const fields_one = try a.alloc(V, 1); fields_one[0] = d_one; const rec_one = try V.initRecord(a, try V.initSymbol(a, "Label"), fields_one); const got_one = recordAttributes(NoEmbedded, rec_one).?; try std.testing.expectEqual(@as(usize, 1), got_one.len); try std.testing.expect(recordAttributes(NoEmbedded, V.initI128(0)) == null); const bad_entries = try a.alloc(V.DictionaryEntry, 1); bad_entries[0] = .{ .key = V.initI128(7), .value = V.initI128(1) }; const d_bad = V.initDictionary(bad_entries); const fields_bad = try a.alloc(V, 1); fields_bad[0] = d_bad; const rec_bad = try V.initRecord(a, try V.initSymbol(a, "Label"), fields_bad); try std.testing.expect(recordAttributes(NoEmbedded, rec_bad) == null); const fields_two = try a.alloc(V, 2); fields_two[0] = V.initI128(1); fields_two[1] = V.initI128(2); const rec_two = try V.initRecord(a, try V.initSymbol(a, "Label"), fields_two); try std.testing.expect(recordAttributes(NoEmbedded, rec_two) == null);}Source: lib/preserves/src/root.zig:115
zig
pub const predicates = @import("predicates.zig");Audit
| Definitions | 10 |
|---|---|
| Public names | 10 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |