lib/preserves/src/any.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 const value = @import("value.zig");
4 const symbols = @import("symbols.zig");
5 const embedded_mod = @import("embedded.zig");
6 const constructors_mod = @import("constructors.zig");
7 const ownership = @import("ownership.zig");
8 const predicates = @import("predicates.zig");
9 const patterns_mod = @import("patterns.zig");
10 const containers = @import("containers.zig");
11
12 const Symbol = symbols.Symbol;
13 const any_constructors = constructors_mod.any_constructors;
14 const any_conversions = patterns_mod.any_conversions;
15
16 pub const AnyValue = value.Value(embedded_mod.AnyEmbedded);
17
18 /// One key and value pair of a dictionary, for values that use `AnyEmbedded` as the type of the
19 /// embedded values, its domain. Code that builds a dictionary for the root's `dictionary`
20 /// constructor names its entries with this type. A dictionary holds its entries in a slice of
21 /// these, in any storage order, with each key once.
22 pub const DictEntry = AnyValue.DictionaryEntry;
23 /// The parts of a record: a pointer to its label value and a slice of its field values. Code that
24 /// reads a record parsed from text or JSON names its parts with this type. The label sits behind a
25 /// pointer so a record can hold a value of its own type as its label.
26 pub const Record = AnyValue.Record;
27 /// A slice of key and value entries, the storage of a dictionary value. Code that walks a
28 /// dictionary from the root functions names its storage with this type. Equality, order and hash
29 /// read the entries in ascending order of their keys under `compare`, whatever the order of the
30 /// slice. A dictionary built with `Value.initDictionary` keeps the caller's slice unchecked, so two
31 /// equal keys in it go undetected. The `dictionary` constructor rejects them.
32 pub const Dictionary = AnyValue.Dictionary;
33 pub const Embedded = embedded_mod.AnyEmbedded;
34 /// A pointer to the inner pattern of a capture. Beside its data, `Value` holds four value kinds
35 /// that describe a match, the pattern forms, and a capture is one of them. Code that reads a
36 /// capture from the root functions names its inner pattern with this type. `toText` prints a
37 /// capture as the record `<bind p>` over its inner pattern `p`.
38 pub const Capture = *AnyValue;
39 /// The parts of a bind: a name and a pointer to the inner pattern it names. Code that reads a bind
40 /// from the root functions names its parts with this type. The name is a byte slice that the
41 /// `bindVal` constructor borrows and `Value.deinit` frees.
42 pub const Bind = AnyValue.Bind;
43 /// The parts of a rest pattern: a slice of patterns for the first items of a sequence and a pointer
44 /// to one pattern for the items after them. Code that reads a rest pattern from the root functions
45 /// names its parts with this type. `toText` prints it as `[p1 p2 . rest]`.
46 pub const RestPattern = AnyValue.RestPattern;
47
48 /// A hash-map context whose hash calls `Value.hash` and whose equality calls `Value.eql`. Code that
49 /// keys a standard-library hash map by values passes this context. Two equal values land in the
50 /// same slot, so a set or dictionary finds its entry whatever its storage order.
51 pub const ValueContext = containers.ValueContext(embedded_mod.AnyEmbedded);
52 /// A standard-library unmanaged hash map from values to values, keyed through `ValueContext`, with
53 /// a maximum load of 80 percent. Code that maps values to values by equality uses this map, so a
54 /// set key matches whatever its storage order. Each call that grows the map takes the allocator.
55 /// The map stores each key and value as a copy of its outer struct, and it never copies or frees
56 /// the storage they point to, so that storage has to outlive the map.
57 pub const ValueHashMap = containers.ValueHashMap(embedded_mod.AnyEmbedded);
58 /// A standard-library unmanaged hash map from values to nothing, keyed through `ValueContext`, with
59 /// a maximum load of 80 percent. Code that collects distinct values uses this set, so two equal
60 /// values count once. The set stores each value as a copy of its outer struct, and it never copies
61 /// or frees the storage the value points to, so that storage has to outlive the set.
62 pub const ValueSet = containers.ValueSet(embedded_mod.AnyEmbedded);
63
64 /// Returns whether `a` and `b` are equal, the same answer as `a.eql(b)`. Code that needs value
65 /// equality as a plain function passes this. Sets and dictionaries are equal when they hold the
66 /// same elements or entries, whatever their storage order. Two embedded values are equal only when
67 /// they share one table of equality, hash and order functions and that table's equality holds, or
68 /// when both lack a table and point to the same payload. The call allocates nothing. Its cost on
69 /// two sets grows with the square of their size.
70 pub fn valueEqual(a: AnyValue, b: AnyValue) bool {
71 return a.eql(b);
72 }
73
74 /// Returns the value's 64-bit hash, the same answer as `v.hash()`. Code that needs the hash as a
75 /// plain function passes this. The hash is Wyhash with seed 0 over the value's kind and contents.
76 /// Sets and dictionaries feed their elements in ascending order under `compare`, so equal values
77 /// hash equally whatever their storage order. An embedded value hashes through its table of
78 /// functions, or by the address of its payload when it has no table. The call allocates nothing.
79 /// Its cost on a set grows with the square of the set's size.
80 pub fn valueHash(v: AnyValue) u64 {
81 return v.hash();
82 }
83
84 /// Returns the order of `a` against `b`, the same answer as `a.compare(b)`. Code that sorts values
85 /// passes this as the comparison, for the package's one total order. Values of different kinds
86 /// order by kind: booleans, doubles, integers, strings, byte strings, symbols, records, sequences,
87 /// sets, dictionaries, embedded values, then the four pattern forms. Doubles order by a total order
88 /// over their bits, so every double, `NaN` included, has one place. Sets and dictionaries compare
89 /// their elements in ascending order under `compare`, whatever their storage order. The call
90 /// allocates nothing. Its cost on two sets grows with the square of their size.
91 pub fn valueCompare(a: AnyValue, b: AnyValue) std.math.Order {
92 return a.compare(b);
93 }
94
95 /// Frees the outer storage of one compound value and nothing below it. Code that built a value with
96 /// the root constructors calls it at the end, as the README's example does. The outer storage is a
97 /// record's label cell and field slice, the slice of a sequence, set or dictionary, the inner cell
98 /// of a capture or bind, and a rest pattern's prefix slice and rest cell. The call matches the root
99 /// constructors, which allocate that outer storage and borrow everything below it. The call frees
100 /// no child value, no atom bytes and no embedded payload, and it does nothing to an atom or an
101 /// embedded value.
102 pub fn freeValue(alloc: std.mem.Allocator, v: AnyValue) void {
103 ownership.freeValue(embedded_mod.AnyEmbedded, alloc, v);
104 }
105
106 /// Frees a value's compound storage all the way down: records, sequences, sets, dictionaries and
107 /// the cells of the four pattern forms. Code that owns a tree's structure and borrows its text
108 /// calls it, as the pattern conversions and `toText` do. The call also frees the digits of every
109 /// integer too large for 128 bits. The call leaves the bytes of strings, byte strings and symbols,
110 /// the names of binds, and embedded payloads. `Value.deinit` frees all of those too, so it fits a
111 /// tree that owns every byte.
112 pub fn freeValueDeep(alloc: std.mem.Allocator, v: AnyValue) void {
113 ownership.freeValueDeep(embedded_mod.AnyEmbedded, alloc, v);
114 }
115
116 /// Copies `v` all the way down into storage from `alloc`: atom bytes, integer digits, bind names
117 /// and compound storage. Code that keeps a value past the life of its source calls it for a copy
118 /// that owns every byte. A set or dictionary copy keeps the original's storage order. Each embedded
119 /// payload is copied by its copy function. A payload with no copy function and no free function
120 /// stays shared with the original. The call panics on a payload that has a free function and no
121 /// copy function. `Value.deinit` with the same allocator frees the copy. On `error.OutOfMemory` the
122 /// call frees every partial copy and leaves `v` unchanged.
123 pub fn cloneValueDeep(alloc: std.mem.Allocator, v: AnyValue) std.mem.Allocator.Error!AnyValue {
124 return ownership.cloneValueDeep(embedded_mod.AnyEmbedded, alloc, v);
125 }
126
127 /// Makes a boolean value from `v`. Code that builds values by hand calls it for a boolean. The call
128 /// allocates nothing, so no free call applies.
129 pub const boolean = any_constructors.boolean;
130 /// Makes an integer value from the signed 64-bit `v`. Code that builds values by hand calls it for
131 /// an integer from an `i64`. The value holds `v` in 128 bits and allocates nothing.
132 pub const integer = any_constructors.integer;
133 /// Makes a double value from `v`. Code that builds values by hand calls it for a double. The call
134 /// allocates nothing.
135 pub const float = any_constructors.float;
136 /// Makes a string value that points at the caller's bytes `s`. Code that builds values by hand from
137 /// bytes it keeps alive calls it. The call copies nothing, so `s` has to outlive the value.
138 /// `Value.deinit` frees string bytes, so a value over bytes the allocator does not own goes to
139 /// `freeValue` or `freeValueDeep`. `Value.initString` makes a string value that owns a copy.
140 pub const string = any_constructors.string;
141 /// Makes a symbol value that points at the caller's bytes `name`. Code that builds values by hand
142 /// from a name it keeps alive calls it. The call copies nothing, so `name` has to outlive the
143 /// value. `Value.deinit` frees symbol bytes, so a value over bytes the allocator does not own goes
144 /// to `freeValue` or `freeValueDeep`. `Value.initSymbol` makes a symbol value that owns a copy.
145 pub const symbol = any_constructors.symbol;
146 /// Makes the discard pattern, written `<_>` in text. Code that writes a pattern by hand calls it
147 /// for the part that accepts any value. The call allocates nothing.
148 pub const discard = any_constructors.discard;
149 /// Makes the symbol `null`, which the JSON codec reads and writes as JSON `null`. Code that builds
150 /// values for that codec calls it. The symbol's bytes are a constant of the package. `Value.deinit`
151 /// would free those constant bytes, so the value goes to `freeValue` or `freeValueDeep`.
152 pub const null_val = any_constructors.null_val;
153 /// Makes a record with label `label` and fields `fields`. Code that builds a record by hand calls
154 /// it, as the README's example does. The call allocates one cell for the label and a copy of the
155 /// field slice, and it copies each value's outer struct. The record shares all storage below the
156 /// label and fields with the caller, and `freeValue` frees exactly the two allocations the call
157 /// made. On `error.OutOfMemory` the call frees what it allocated.
158 pub const record = any_constructors.record;
159 /// Makes a sequence holding a copy of the slice `items`. Code that builds a sequence by hand from
160 /// values it already holds calls it. The copy is one level deep: the sequence shares everything the
161 /// items point to, and `freeValue` frees exactly the slice.
162 pub const sequence = any_constructors.sequence;
163 /// Makes a set holding a copy of the slice `items`, sorted in ascending order under `compare`. Code
164 /// that builds a set by hand calls it, so duplicates are refused and the storage comes out sorted.
165 /// The duplicate check compares each item with every item before it, so its cost grows with the
166 /// square of the set's size. The copy is one level deep: the set shares everything the items point
167 /// to, and `freeValue` frees exactly the slice. The call returns `error.DuplicateSetElement` before
168 /// it allocates when two items are equal.
169 pub const set = any_constructors.set;
170 /// Makes a dictionary holding a copy of the slice `entries`, sorted in ascending order of their
171 /// keys under `compare`. Code that builds a dictionary by hand calls it, so repeated keys are
172 /// refused and the storage comes out sorted by key. The duplicate check compares each key with
173 /// every key before it, so its cost grows with the square of the entry count. The copy is one level
174 /// deep: the dictionary shares everything the keys and values point to, and `freeValue` frees
175 /// exactly the slice. The call returns `error.DuplicateDictionaryKey` before it allocates when two
176 /// keys are equal.
177 pub const dictionary = any_constructors.dictionary;
178 /// Makes a capture of the pattern `inner`. Code that writes a pattern by hand calls it to wrap an
179 /// inner pattern in a capture. The call allocates one cell and copies the outer struct of `inner`
180 /// into it. The capture shares everything below `inner`, and `freeValue` frees exactly the cell.
181 pub const capture = any_constructors.capture;
182 /// Makes a bind that gives the pattern `inner` the name `name`. Code that writes a pattern by hand
183 /// calls it to give part of the pattern a name. The call allocates one cell and copies the outer
184 /// struct of `inner` into it. The call copies nothing of `name`, so `name` has to outlive the bind.
185 /// `Value.deinit` frees a bind's name, so a bind over a name the allocator does not own goes to
186 /// `freeValue` or `freeValueDeep`. On `error.OutOfMemory` the call frees what it allocated.
187 pub const bindVal = any_constructors.bindVal;
188 /// Makes a rest pattern from the patterns `prefix` for the first items and the pattern `rest` for
189 /// the items after them. Code that writes a pattern by hand calls it for a sequence whose tail has
190 /// any length. The call copies the slice `prefix` and allocates one cell for `rest`, copying outer
191 /// structs only. `freeValue` frees exactly the prefix copy and the cell. On `error.OutOfMemory` the
192 /// call frees what it allocated.
193 pub const restPattern = any_constructors.restPattern;
194 /// Makes an embedded value that points to the payload `ptr`. Code that places a host object inside
195 /// a value calls it, so the value points to the object and never frees it. The value carries no
196 /// table of functions, no free function and no copy function. The value compares and hashes by the
197 /// address of `ptr`, and nothing in the package frees the payload. A copy of the value by
198 /// `cloneValueDeep` points to the same payload.
199 pub const embedded = any_constructors.embedded;
200
201 /// Returns the attribute entries of a record whose fields are named. The JSON writer uses the call
202 /// to write such a record as a JSON object. A record with no fields has an empty list of
203 /// attributes. A record with one field that is a dictionary whose keys are all strings has that
204 /// dictionary's entries as attributes. The call returns `null` for any other value. The returned
205 /// slice is the dictionary's own storage, so the call allocates nothing.
206 pub fn recordAttributes(v: AnyValue) ?[]const AnyValue.DictionaryEntry {
207 return predicates.recordAttributes(embedded_mod.AnyEmbedded, v);
208 }
209
210 /// Returns whether `v` is a record whose label is the symbol `label` and whose field count is
211 /// `arity`. Code that dispatches on record labels calls it, as the Observe accessors do. A `null`
212 /// label or arity skips that check. A record whose label holds a value other than a symbol fails
213 /// every label check.
214 pub fn isRecord(v: AnyValue, label: ?Symbol, arity: ?usize) bool {
215 const name: ?[]const u8 = if (label) |l| l.name else null;
216 return predicates.isRecord(embedded_mod.AnyEmbedded, v, name, arity);
217 }
218
219 /// Returns whether `v` is a record labeled with the symbol `Observe` that has exactly two fields.
220 /// Code that handles subscriptions calls it to recognize an `<Observe pattern observer>` record.
221 pub fn isObserve(v: AnyValue) bool {
222 return predicates.isObserve(embedded_mod.AnyEmbedded, v);
223 }
224
225 /// Returns whether `v` is an embedded value. Code that treats host objects apart from data calls it
226 /// before reading the payload.
227 pub fn isEmbedded(v: AnyValue) bool {
228 return predicates.isEmbedded(embedded_mod.AnyEmbedded, v);
229 }
230
231 /// Returns whether `v` is a symbol. Code that dispatches on a value's kind calls it before reading
232 /// symbol bytes.
233 pub fn isSymbol(v: AnyValue) bool {
234 return predicates.isSymbol(embedded_mod.AnyEmbedded, v);
235 }
236
237 /// Returns whether `v` is the symbol `null`, compared byte for byte. Code that reads JSON-shaped
238 /// data calls it to recognize JSON `null`.
239 pub fn isNull(v: AnyValue) bool {
240 return predicates.isNull(embedded_mod.AnyEmbedded, v);
241 }
242
243 /// Returns whether `v` is a record, sequence, set or dictionary. Code that walks a tree calls it to
244 /// decide whether to descend.
245 pub fn isCompound(v: AnyValue) bool {
246 return predicates.isCompound(embedded_mod.AnyEmbedded, v);
247 }
248
249 /// Returns whether `v` is a discard, capture, bind or rest pattern. Code that mixes data and
250 /// patterns calls it to tell them apart.
251 pub fn isPatternForm(v: AnyValue) bool {
252 return predicates.isPatternForm(embedded_mod.AnyEmbedded, v);
253 }
254
255 /// Returns whether `v` is a boolean, double, integer, string, byte string or symbol. Code that
256 /// walks a tree calls it to find the leaves.
257 pub fn isAtom(v: AnyValue) bool {
258 return predicates.isAtom(embedded_mod.AnyEmbedded, v);
259 }
260
261 /// Returns whether the bytes `sym_bytes` equal the name of the symbol constant `s`, byte for byte.
262 /// Code that dispatches on symbol bytes calls it against the package's symbol constants, so each
263 /// name is spelled once.
264 pub fn symbolEql(sym_bytes: []const u8, s: Symbol) bool {
265 return std.mem.eql(u8, sym_bytes, s.name);
266 }
267
268 /// Returns `v` unchanged. Code that passes a value through the pattern conversions calls it for the
269 /// same signature as the others. The call ignores `alloc` and allocates nothing. The call never
270 /// fails, and the error union in its type exists for the root's signature alone.
271 pub fn preserve(alloc: std.mem.Allocator, v: AnyValue) !AnyValue {
272 return any_conversions.preserve(alloc, v);
273 }
274
275 /// Reads a pattern written as records and returns it as pattern values. Code that holds a pattern
276 /// parsed as records calls it for the pattern values of `Value`. The symbol `_` and the record
277 /// `<_>` become a discard. `<bind P>` becomes a capture of `P`. `<lit V>` becomes `V` itself.
278 /// `<group <rec L> {0: P0 1: P1}>` becomes a record labeled `L` with its fields in key order.
279 /// `<group <arr> {...}>` becomes a sequence the same way, and `<group <dict> {K: P}>` becomes a
280 /// dictionary. Other records, sequences and dictionaries are converted item by item, and every
281 /// other value comes back unchanged. The result shares atoms, `<lit>` values, labels and dictionary
282 /// keys with `pattern`. On a failed allocation the call returns the unconverted input in its place
283 /// and reports nothing, and cells allocated before the failure are never freed.
284 /// `preservesToPattern` does the same conversion and reports allocation failure.
285 pub fn preservePattern(alloc: std.mem.Allocator, pattern: AnyValue) AnyValue {
286 return any_conversions.preservePattern(alloc, pattern);
287 }
288
289 /// Writes the pattern values of `pattern` as records, the reverse of `preservesToPattern`. `toText`
290 /// calls it to print captures and binds, and code that sends a pattern as data calls it for the
291 /// record form. A discard becomes `<_>`, and captures and binds both become `<bind P>`. A bind's
292 /// name is dropped, so a bind comes back from the record form as a capture. Atoms and sets become
293 /// `<lit V>`, and embedded values stay as they are. A record becomes `<group <rec L> {0: P0 ...}>`,
294 /// a sequence `<group <arr> {...}>`, and a dictionary `<group <dict> {K: P}>`. A rest pattern
295 /// becomes the sequence of its prefix, the symbol `.`, and its rest pattern, written the same way.
296 /// The result holds `pattern`'s own atoms, sets, labels and dictionary keys, and its new labels
297 /// point to constant bytes of the package. So `Value.deinit` would free constant bytes, and
298 /// `freeValueDeep` frees storage that `pattern` still holds. On `error.OutOfMemory` the storage
299 /// built before the failure is never freed.
300 pub fn patternToPreserves(alloc: std.mem.Allocator, pattern: AnyValue) !AnyValue {
301 return any_conversions.patternToPreserves(alloc, pattern);
302 }
303
304 /// Reads a pattern written as records and returns it as pattern values, with the same mapping as
305 /// `preservePattern`. Code that receives a pattern in record form calls it for pattern values, with
306 /// allocation failure reported. `<lit V>`, the labels of plain records and dictionary keys come
307 /// back as new copies of their compound storage and integer digits. `freeValueDeep` frees the
308 /// result. Sets, integers, other atoms, embedded values and the labels and keys of `<group>`
309 /// records come back as the input's own values, so `freeValueDeep` on the result also frees the
310 /// input's sets and large-integer digits. On `error.OutOfMemory` most paths free what they built.
311 /// The `<group>` paths and the `<bind P>` path leak it.
312 pub fn preservesToPattern(alloc: std.mem.Allocator, v: AnyValue) !AnyValue {
313 return any_conversions.preservesToPattern(alloc, v);
314 }
315
316 /// Returns the second field of an `<Observe pattern observer>` record with exactly two fields, and
317 /// `null` for any other value. Code that handles a subscription calls it for the observer of an
318 /// `<Observe pattern observer>` record. The returned value shares its storage with `v`.
319 pub fn observeObserver(v: AnyValue) ?AnyValue {
320 return any_conversions.observeObserver(v);
321 }
322
323 /// Returns the first field of an `<Observe pattern observer>` record with exactly two fields, and
324 /// `null` for any other value. Code that handles a subscription calls it for the pattern of an
325 /// `<Observe pattern observer>` record. The returned value shares its storage with `v`.
326 pub fn observePattern(v: AnyValue) ?AnyValue {
327 return any_conversions.observePattern(v);
328 }
329
330 /// Calls `callback(context, e)` once for each embedded value `e` inside `v`, in storage order. Code
331 /// that tracks host objects inside a value calls it to visit each one. The walk visits a record's
332 /// label before its fields, a dictionary entry's key before its value, and the inner patterns of
333 /// captures, binds and rest patterns. The call allocates nothing.
334 pub fn foreachEmbedded(
335 v: AnyValue,
336 context: anytype,
337 callback: anytype,
338 ) void {
339 any_conversions.foreachEmbedded(v, context, callback);
340 }
341
342 /// Returns a copy of `v` in which each embedded value `e` is replaced by the value
343 /// `map_fn(context, alloc, e)` returns. Code that swaps host objects inside a value for data calls
344 /// it for a new tree with each one replaced. The copy has new compound storage from `alloc` and
345 /// shares every atom with `v`. A set in the copy keeps the input's storage order and skips checking
346 /// again for duplicates. On an error from `map_fn` or from `alloc`, the storage built before the
347 /// failure is never freed.
348 pub fn mapEmbedded(
349 alloc: std.mem.Allocator,
350 v: AnyValue,
351 context: anytype,
352 map_fn: anytype,
353 ) !AnyValue {
354 return any_conversions.mapEmbedded(alloc, v, context, map_fn);
355 }