cove_runtime/value.rs
1//! Runtime values.
2//!
3//! Assignment and ordinary argument passing use one rule: field-wise shallow
4//! copy. That rule is encoded directly in [`Clone`]: cloning a struct or enum
5//! copies its fields, cloning an `Array` shares immutable storage, and cloning
6//! a `Vector` copies only the handle so aliases observe the same elements and
7//! length. Cove never performs an implicit deep copy.
8//!
9//! # What an embedding host should write
10//!
11//! A host builds a value through a constructor — [`Value::unit`],
12//! [`Value::bool`], [`Value::int`], [`Value::float`], [`Value::duration`],
13//! [`Value::string`], [`Value::range_of`], [`Value::array`], [`Value::set`],
14//! [`Value::map`], [`Value::structure`], [`Value::enumeration`],
15//! [`Value::from_resource`], [`Value::host_fn`], [`Value::host_module`],
16//! [`Value::type_value`], [`Value::ok`], [`Value::err`], [`Value::some`],
17//! [`Value::none`], [`Value::error`] — and reads one through a reader:
18//! [`Value::field`],
19//! [`Value::fields`], [`Value::case`], [`Value::payload`], [`Value::items`],
20//! [`Value::elements`], [`Value::entries`], [`Value::declared_type`],
21//! [`Value::range`], [`Value::resource`], [`Value::host_op`],
22//! [`Value::arity`], and the scalar `as_*` family. Between them they cover
23//! every shape that crosses the Host API boundary, and none of them says how
24//! the runtime holds one.
25//!
26//! A host that wants to be told *what kind* of value it has calls
27//! [`Value::view`] and matches [`ValueView`], which is exhaustive on purpose.
28//!
29//! **There is no variant to match, and that is the point.** [`Value`]'s
30//! variants were `pub` until ADR 0028, and every change to what a value *is*
31//! was therefore a source break for the hosts that matched one: issue #104
32//! moved a struct from a `Box` to an `Rc`, issue #109 put a bound host
33//! operation's two names behind one pointer to take every value in the
34//! program from forty bytes to twenty-four, issue #121 replaced a closure's
35//! parameter list with an arity, and issue #183 replaced an enum payload's
36//! `Vec<Value>` with [`Payload`]. Each was invisible through the constructors
37//! and visible through a `match`, and each was rescued individually — twice
38//! by luck and once by a hand-written `Deref` shim. Issue #196 asked whether
39//! that should keep being paid for; ADR 0028 decision 6 answers no, for every
40//! variant and not a chosen subset, because a partial seal leaves the API a
41//! mixture and makes "which half may I match on" a question every embedder
42//! has to hold in their head.
43//!
44//! What a host loses is the compile error that said *the language changed*,
45//! and [`ValueView`] gives exactly that back: after this a representation
46//! change is invisible and a new kind of Cove value is a compile error at
47//! every `match`, which is the right way round.
48//!
49//! The readers are issue #186's answer to the same question on the way out;
50//! what they promise, what borrowing them forecloses, and what they do with a
51//! wrong shape are stated once, on the `impl Value` block that holds them.
52
53use std::cell::RefCell;
54use std::collections::{BTreeMap, BTreeSet};
55use std::fmt;
56use std::rc::Rc;
57use std::sync::Arc;
58
59use cove_schema::builtins::{
60 BuiltinSchema, CaseSchema, ERROR, ERR_CASE, MESSAGE_FIELD, NONE_CASE, OK_CASE, OPTION, RESULT,
61 SOME_CASE,
62};
63use cove_syntax::ast::{FnDecl, Param};
64
65use crate::host::ResourceHandle;
66use crate::shared::SharedCell;
67use crate::task::{Task, TaskScope};
68
69/// A Cove value.
70///
71/// **An abstract type.** What it holds is private to this crate: a host
72/// builds one through a constructor, reads one through a reader, and
73/// classifies one through [`Value::view`]. ADR 0028 decision 6 is where that
74/// was decided and issue #196 is where it was asked. Every change to what a
75/// value *is* had been a source break for the hosts that matched on it, and
76/// the record is not that `pub` variants are survivable but that each change
77/// was individually rescued — twice by luck and once by a hand-written
78/// compatibility shim.
79///
80/// The one thing sealing takes away is the compile error a host got when a
81/// new variant arrived, and [`ValueView`] gives that back deliberately and
82/// exhaustively. What it does *not* give back is a compile error when the
83/// runtime moves a value from a `Box` to an `Rc`, which is the whole point:
84/// those two were the same error before, and they are unrelated events.
85#[derive(Clone)]
86pub struct Value(pub(crate) Repr);
87
88/// `Value` prints as the value it is, and not as a wrapper around one.
89///
90/// Forwarded rather than derived so that the newtype the seal is made of
91/// leaves no trace in a rendering: a `Debug` of an `Int` is `Int(3)`, exactly
92/// as it was when `Value` was the enum itself. Tests, traces and diagnostics
93/// all read this, and none of them should have to know.
94impl fmt::Debug for Value {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 fmt::Debug::fmt(&self.0, f)
97 }
98}
99
100/// How this crate holds a value. Private, and it is the seal.
101///
102/// The variants are exactly what `Value`'s were, and this crate matches them
103/// exactly as it did — a pattern reads `Value(Repr::Int(n))` where it read
104/// `Value::Int(n)`, and that is the whole of the difference on this side of
105/// the boundary. Nothing outside the crate can name any of it, which is what
106/// ADR 0028 decision 0 means by representations that cannot fail to differ.
107#[derive(Clone, Debug)]
108pub(crate) enum Repr {
109 Unit,
110 Bool(bool),
111 Int(i64),
112 Float(f64),
113 /// A duration in nanoseconds.
114 Duration(i64),
115 Str(Rc<str>),
116 /// Fixed-length immutable sequence; sharing its storage is unobservable.
117 Array(Rc<[Value]>),
118 /// Growable mutable sequence backed by stable shared storage. Copying the
119 /// handle is O(1) and aliases observe the same elements and length.
120 Vector(Rc<VectorStorage>),
121 /// Immutable in the MVP. Iterates in ascending key order, since that is
122 /// the natural order of its `BTreeMap` storage.
123 Map(Rc<BTreeMap<MapKey, Value>>),
124 /// Immutable in the MVP. Backed by the same key-ordered storage as `Map`,
125 /// so membership is O(log n) and iteration order is defined the same
126 /// way: ascending order. An element must satisfy the [`MapKey`]
127 /// restriction, exactly like a map key.
128 Set(Rc<BTreeSet<MapKey>>),
129 /// A struct value.
130 ///
131 /// The storage is shared and copied on write. Cloning a struct value is
132 /// the field-wise shallow copy the Language Card describes, and sharing
133 /// the fields until one of them is written is unobservable: a write goes
134 /// through a place, [`crate::interp`]'s `Place::with_mut` is the only way
135 /// to reach one, and it takes a private copy first when the storage has
136 /// another holder. Nothing else can tell the two apart, because `is` is
137 /// defined only for `Vector`.
138 ///
139 /// It is shared because it was copied on every non-mutating method call:
140 /// `self` is passed by value, and a copy was a `Box` and a `Vec` and a
141 /// clone of every field. That made a method call twice the cost of the
142 /// same code with the fields read directly, which issue #99 measured and
143 /// issue #104 set out to remove.
144 ///
145 /// This was a `Box<StructValue>` until issue #104. Nothing a Cove program
146 /// can write sees the difference, but an embedder building a struct value
147 /// writes `Rc::new` where it wrote `Box::new`, and one matching on the
148 /// variant binds an `&Rc<StructValue>` where it bound an
149 /// `&Box<StructValue>` — both deref to `StructValue`, so a body that only
150 /// reads fields needs no change. Mutating through one needs
151 /// [`Rc::make_mut`], which is what keeps the copy private.
152 Struct(Rc<StructValue>),
153 /// An enum value, including `Option` and `Result`.
154 ///
155 /// One allocation, not two: the box is the whole of it, because
156 /// [`Payload`] holds the arities an ordinary program builds inside the
157 /// [`EnumValue`] rather than in a vector beside it. Issue #183 is why,
158 /// and `benches/arrayget` is where it shows.
159 Enum(Box<EnumValue>),
160 /// A callback is an ordinary handle value.
161 Closure(Rc<Closure>),
162 /// A `dyn Trait` value: a concrete value together with the trait it was
163 /// used at.
164 ///
165 /// This is the one place where a Cove value's runtime representation
166 /// depends on its static type. A concrete value is wrapped here at the
167 /// point it is used where a `dyn Trait` is expected, and the wrapper
168 /// carries what a concrete value does not: the trait, so a diagnostic can
169 /// name it, and the value itself, whose own type is what dispatch finds
170 /// the implementation from.
171 Dyn(Rc<DynValue>),
172 /// A bound host module such as `console`.
173 HostModule(Rc<str>),
174 /// A handle to a resource the host owns, such as a database connection.
175 ///
176 /// The handle is a name, never the thing itself: what a
177 /// `database.Connection` really is stays on the host's side of the
178 /// boundary, and this value carries only the identity that addresses it.
179 /// That is what lets a handle be copied like any other value, crossed
180 /// into a task when its schema allows it, written into a trace, and
181 /// handed back by a replay — see ADR 0013 and
182 /// [`crate::host::ResourceHandle`].
183 Resource(Arc<ResourceHandle>),
184 /// A bound host operation such as `console.println`.
185 ///
186 /// The two names live behind one pointer, exactly as [`Value::Struct`]
187 /// and [`Value::Dyn`] hold their contents, and for the same kind of
188 /// reason: a variant is as wide as its widest member, and this one held
189 /// two fat pointers where every other variant holds at most one. Thirty-
190 /// two bytes for the pair set the width of every `Value` in the program,
191 /// including the `Int`s the two backends spend most of their time moving.
192 ///
193 /// The trade is an allocation for a value that is built when a host
194 /// operation is *used* as a value — `console.println` bound to a name or
195 /// passed as an argument — rather than called in place, which is rare,
196 /// against sixteen bytes off every value everywhere.
197 ///
198 /// An embedder constructing one writes `Value::HostFn(Rc::new(
199 /// HostFnValue { module, op }))` where it wrote `Value::HostFn { module,
200 /// op }`, and one matching on the variant binds an `&Rc<HostFnValue>`
201 /// whose fields have the names and the types they had.
202 HostFn(Rc<HostFnValue>),
203 /// A type used as a value, such as `Vector` in `Vector.of(1, 2)`.
204 Type(Rc<str>),
205 /// An integer range. `..` includes `end` and `..<` excludes it.
206 ///
207 /// A range is an ordinary value: it can be bound, passed, compared, and
208 /// iterated. An empty or reversed range such as `3..<0` yields nothing.
209 Range {
210 start: i64,
211 end: i64,
212 inclusive_end: bool,
213 },
214 /// The task scope `scope tasks { ... }` binds. Concurrent work belongs to
215 /// a task scope, and the scope owns the tasks spawned into it.
216 TaskScope(Rc<TaskScope>),
217 /// A handle to a spawned task. The task's value is reachable only through
218 /// `await` or through the scope settling it on exit.
219 Task(Rc<Task>),
220 /// `Shared(value)`: mutable state more than one task may reach.
221 ///
222 /// This is the one value whose storage is an [`Arc`] rather than an
223 /// [`Rc`]: a `Shared` crosses a task boundary by sharing its cell, so two
224 /// task threads address the same one. Its contents are reachable only
225 /// through `lock`; see [`crate::shared`].
226 Shared(Arc<SharedCell>),
227}
228
229// A `Value` is twenty-four bytes, and nothing else in this file says so.
230//
231// It was forty until issue #109's audit, because exactly one variant was wide:
232// `HostFn` inlined two fat pointers, so the variant that names
233// `console.println` set the width of every `Int` both backends move. Boxing it
234// was worth `field` −4.9% and `method` −6.3% on the predecessor VM and `arith`
235// −8.2% on the interpreter — the first change since that backend landed to
236// make both backends faster. Width was then measured directly, by widening
237// `Value` with a padding
238// variant nothing constructs and running the suite at 24, 32 and 40: about a
239// percent per eight bytes. See `docs/VM_ARCHITECTURE.md`, "The value
240// representation, audited".
241//
242// So this is the one number a new variant can undo silently. A second variant
243// holding two pointers takes every `Value` in the program back to 32 and costs
244// what the audit bought, and nothing about writing it would say so. This
245// refuses to compile instead.
246//
247// Twenty-four is the floor for the variants that exist — `Range` is two `i128`
248// halves reduced to `(i64, i64, bool)` whose `bool` niche holds the
249// discriminant — and sixteen is the floor for the *language*, since `Int` is a
250// full sixty-four bits with overflow a broken invariant, which is why NaN
251// boxing and pointer tagging are rejected rather than deferred. Neither number
252// is a target to shrink to: 24 → 16 was measured and not taken.
253//
254// Guarded on the pointer width because every non-scalar variant is one
255// pointer, so this says nothing on a 32-bit target.
256#[cfg(target_pointer_width = "64")]
257const _: () = assert!(
258 std::mem::size_of::<Value>() == 24,
259 "a Value is 24 bytes; a variant wider than one pointer takes every value \
260 in the program back to 32 — see docs/VM_ARCHITECTURE.md, \"The value \
261 representation, audited\""
262);
263
264/// The half-open bounds of a `Range` value, widened to `i128` so that an
265/// inclusive `i64::MAX` end cannot overflow.
266#[derive(Clone, Copy, Debug)]
267pub struct RangeBounds {
268 /// The first value the range can yield.
269 pub start: i128,
270 /// The first value past the end.
271 pub end: i128,
272}
273
274impl RangeBounds {
275 /// Normalises the AST form, where `inclusive_end` selects `..` over `..<`.
276 pub fn of(start: i64, end: i64, inclusive_end: bool) -> RangeBounds {
277 RangeBounds {
278 start: i128::from(start),
279 end: i128::from(end) + i128::from(inclusive_end),
280 }
281 }
282
283 /// The number of values the range yields. A reversed range yields none.
284 pub fn len(self) -> i64 {
285 (self.end - self.start).max(0) as i64
286 }
287
288 /// Whether the range yields no values at all.
289 pub fn is_empty(self) -> bool {
290 self.end <= self.start
291 }
292
293 /// Whether `value` is one of the values the range yields.
294 pub fn contains(self, value: i64) -> bool {
295 let value = i128::from(value);
296 self.start <= value && value < self.end
297 }
298
299 /// The values the range yields, in order.
300 pub fn items(self) -> Vec<Value> {
301 (self.start..self.end)
302 .map(|n| Value(Repr::Int(n as i64)))
303 .collect()
304 }
305}
306
307/// Growable vector storage. Length, capacity, and elements all belong to the
308/// shared storage, so growth stays visible through every alias.
309#[derive(Debug, Default)]
310pub struct VectorStorage {
311 pub elements: RefCell<Vec<Value>>,
312 /// Set by `freeze()`, which consumes uniquely owned storage.
313 pub frozen: RefCell<bool>,
314}
315
316impl VectorStorage {
317 pub fn new(elements: Vec<Value>) -> Rc<VectorStorage> {
318 Rc::new(VectorStorage {
319 elements: RefCell::new(elements),
320 frozen: RefCell::new(false),
321 })
322 }
323
324 pub fn len(&self) -> usize {
325 self.elements.borrow().len()
326 }
327
328 pub fn is_empty(&self) -> bool {
329 self.len() == 0
330 }
331}
332
333#[derive(Clone, Debug)]
334pub struct StructValue {
335 /// Fully qualified type name, such as `values.BookingDraft`.
336 pub type_name: Rc<str>,
337 /// Fields in declaration order.
338 pub fields: Vec<(Rc<str>, Value)>,
339 /// Whether the type was declared `export opaque struct`, in which case
340 /// the value renders as its name alone (ADR 0014).
341 ///
342 /// The flag rides on the value because rendering is context-free: a
343 /// `Display` has no idea which module is watching, and a value formatted
344 /// in the module that declares it can be handed to one that may not name
345 /// its fields. So the representation is hidden from every reader,
346 /// including the declaring module, which publishes a readable form by
347 /// exporting a method that builds one.
348 pub opaque: bool,
349}
350
351impl StructValue {
352 pub fn get(&self, name: &str) -> Option<&Value> {
353 self.fields
354 .iter()
355 .find(|(n, _)| &**n == name)
356 .map(|(_, v)| v)
357 }
358
359 pub fn get_mut(&mut self, name: &str) -> Option<&mut Value> {
360 self.fields
361 .iter_mut()
362 .find(|(n, _)| &**n == name)
363 .map(|(_, v)| v)
364 }
365}
366
367#[derive(Clone, Debug)]
368pub struct EnumValue {
369 /// Fully qualified type name, or `Option` / `Result` for the builtins.
370 pub type_name: Rc<str>,
371 pub case: Rc<str>,
372 pub payload: Payload,
373}
374
375/// What an enum case carries, held inline for the arities that occur.
376///
377/// This was a `Vec<Value>` until [issue
378/// #183](https://github.com/myuon/cove/issues/183). A `Value::Enum` is a
379/// `Box<EnumValue>`, so a `Some(x)` cost *two* allocations: the box for the
380/// struct, and a vector for a payload of one. Almost every enum case an
381/// ordinary program builds carries zero or one value — `Option` and `Result`
382/// are the two the language builds constantly, and `benches/arrayget`'s
383/// comment says why: an `Option` is how every indexed read answers. Holding
384/// the common arities in the box that already exists makes `Some(x)` one
385/// allocation instead of two.
386///
387/// It is an enum rather than a `Box<[Value]>` because a boxed slice still
388/// allocates for one element, and rather than a general small-vector because
389/// there are exactly two shapes worth naming: no payload, and one. Two or
390/// more is a `Box<[Value]>` rather than a `Vec` because a payload is never
391/// grown after the case is built — the length is the case declaration's, and
392/// nothing in this workspace pushes onto one.
393///
394/// **This reads as a slice.** [`std::ops::Deref`] and [`std::ops::DerefMut`]
395/// to `[Value]`, and `IntoIterator` on `&Payload` and `&mut Payload`, so
396/// `payload.len()`, `payload[0]`, `payload.first()`, `for item in &payload`
397/// and matching `&*payload` against `[inner]` all mean what they meant. [`fmt::Debug`] is
398/// written by hand to print as the list it reads as, so a `Debug` rendering
399/// of an enum value is the one it always was.
400///
401/// An embedder that built one by naming the field writes `payload:
402/// Payload::One(value)` or `payload: values.into()` where it wrote `payload:
403/// vec![value]`; one that goes through [`Value::enumeration`],
404/// [`Value::some`] or [`Value::ok`] writes nothing new, because those take
405/// what they took.
406#[derive(Clone, Default)]
407pub enum Payload {
408 /// A case with no payload, such as `None`.
409 #[default]
410 Empty,
411 /// A case carrying exactly one value, such as `Some(x)` or `Err(e)`.
412 One(Value),
413 /// A case carrying two or more.
414 Many(Box<[Value]>),
415}
416
417impl Payload {
418 /// The payload as a slice, which is what every reader wants of one.
419 pub fn as_slice(&self) -> &[Value] {
420 match self {
421 Payload::Empty => &[],
422 Payload::One(value) => std::slice::from_ref(value),
423 Payload::Many(values) => values,
424 }
425 }
426
427 /// The payload as a mutable slice.
428 pub fn as_mut_slice(&mut self) -> &mut [Value] {
429 match self {
430 Payload::Empty => &mut [],
431 Payload::One(value) => std::slice::from_mut(value),
432 Payload::Many(values) => values,
433 }
434 }
435
436 /// The payload as an owned vector, for a caller that needs one.
437 ///
438 /// This allocates, which is the thing the type exists to avoid, so it is
439 /// here for the callers that genuinely take ownership rather than as the
440 /// way to read one.
441 pub fn into_vec(self) -> Vec<Value> {
442 match self {
443 Payload::Empty => Vec::new(),
444 Payload::One(value) => vec![value],
445 Payload::Many(values) => values.into_vec(),
446 }
447 }
448}
449
450impl std::ops::Deref for Payload {
451 type Target = [Value];
452
453 fn deref(&self) -> &[Value] {
454 self.as_slice()
455 }
456}
457
458impl std::ops::DerefMut for Payload {
459 fn deref_mut(&mut self) -> &mut [Value] {
460 self.as_mut_slice()
461 }
462}
463
464impl<'a> IntoIterator for &'a Payload {
465 type Item = &'a Value;
466 type IntoIter = std::slice::Iter<'a, Value>;
467
468 fn into_iter(self) -> Self::IntoIter {
469 self.as_slice().iter()
470 }
471}
472
473impl<'a> IntoIterator for &'a mut Payload {
474 type Item = &'a mut Value;
475 type IntoIter = std::slice::IterMut<'a, Value>;
476
477 fn into_iter(self) -> Self::IntoIter {
478 self.as_mut_slice().iter_mut()
479 }
480}
481
482/// Prints as the list a payload reads as, rather than as the variant that
483/// happens to be holding it.
484///
485/// Deliberate: the arity a payload is stored at is an implementation detail
486/// of this type, and a `Debug` rendering that named it would make the same
487/// enum value print two ways depending on how many values it carries.
488impl fmt::Debug for Payload {
489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490 f.debug_list().entries(self.as_slice()).finish()
491 }
492}
493
494impl FromIterator<Value> for Payload {
495 fn from_iter<I: IntoIterator<Item = Value>>(values: I) -> Payload {
496 let mut values = values.into_iter();
497 let Some(first) = values.next() else {
498 return Payload::Empty;
499 };
500 let Some(second) = values.next() else {
501 return Payload::One(first);
502 };
503 let mut rest = Vec::with_capacity(2 + values.size_hint().0);
504 rest.push(first);
505 rest.push(second);
506 rest.extend(values);
507 Payload::Many(rest.into_boxed_slice())
508 }
509}
510
511impl From<Vec<Value>> for Payload {
512 fn from(mut values: Vec<Value>) -> Payload {
513 match values.len() {
514 0 => Payload::Empty,
515 1 => Payload::One(
516 values
517 .pop()
518 .expect("a vector of length one has a last element"),
519 ),
520 _ => Payload::Many(values.into_boxed_slice()),
521 }
522 }
523}
524
525/// The contents of a `dyn Trait` value, which [`Value::dyn_trait`] names
526/// and no other reader admits.
527#[derive(Clone, Debug)]
528pub struct DynValue {
529 /// Fully qualified trait name, such as `render.Display`.
530 pub trait_name: Rc<str>,
531 /// The concrete value. Its own type is what dynamic dispatch resolves a
532 /// method against, which is exactly what makes this dispatch dynamic.
533 pub value: Value,
534}
535
536/// The two names a bound host operation is: the host module the operation
537/// belongs to, and the operation itself.
538///
539/// Neither is the operation's implementation. A bound host operation is a
540/// name the same way a bound host module is, and what it names is looked up
541/// through the registry at the call.
542#[derive(Clone, Debug)]
543pub struct HostFnValue {
544 /// The host module, such as `console`.
545 pub module: Rc<str>,
546 /// The operation's own name, such as `println`.
547 pub op: Rc<str>,
548}
549
550/// A closure captures its environment by value at creation time.
551#[derive(Debug)]
552pub struct Closure {
553 pub is_async: bool,
554 /// How many parameters this closure declares.
555 ///
556 /// The whole of its signature that anything outside the backend that
557 /// built it asks for, and the reason it is a number rather than the
558 /// parameter list it used to be. Every reader wanted a count:
559 /// [`crate::builtins::Callable::arity`] answers out of this,
560 /// `Result.mapError` reads it to decide whether to hand its callback the
561 /// error it is replacing, and `builtins::expect_callback` refuses a
562 /// callback of the wrong shape in one place rather than at every call
563 /// site that needs the check. None of them wanted a name, a default, a
564 /// type or a span, and issue #121 is where each was asked and answered.
565 ///
566 /// It counts parameters, not arguments a call must supply: a defaulted
567 /// or a variadic parameter is one of these like any other, which is what
568 /// `params.len()` answered when this was a `Vec<Param>`.
569 pub arity: usize,
570 pub body: ClosureBody,
571 /// The module a closure body resolves names in.
572 pub module: Rc<str>,
573 pub captures: Vec<(Rc<str>, Value)>,
574}
575
576/// Where a closure's body is, which is the one thing about a closure the two
577/// backends do not agree on.
578///
579/// Everything else a closure is — what it captured, how many parameters it
580/// declares, which module it resolves names in, whether it is `async` — is
581/// the same fact whichever backend made it, and a host that receives one
582/// reads those the same way either way. The body is not: the interpreter
583/// walks a tree and the linear-memory backend runs a lowered function, and
584/// neither can run the other's.
585///
586/// **The declaration is part of the body, not part of the closure.** The
587/// parameters an interpreted call binds against and the return type it
588/// coerces to are syntax, and syntax is one backend's form of a body: a
589/// lowered function has neither, because `cove_ir::lower` spent both when it
590/// chose the slots and emitted the conversions. Keeping them beside the
591/// `Arc<Block>` they came from is what lets every field of a [`Closure`]
592/// outside this enum be a fact both backends state the same way, so that
593/// reaching syntax means reaching past the one variant that has any — which
594/// is the direction issue #109 asks for.
595///
596/// So this is an enum rather than a second `Value` variant. Issue #109 asks
597/// that the internal representation become *less* exposed to an embedder,
598/// not more, and a `Value::LoweredClosure` beside `Value::Closure` would make
599/// every host that already handles a callback handle two — while the
600/// difference between them is one field that no host reads. A host calls a
601/// closure back through [`crate::host::Reentry`], which hands it to the
602/// backend that made it, and that backend is the only party that has to know
603/// which of these it is.
604#[derive(Clone, Debug)]
605pub enum ClosureBody {
606 /// The syntax [`crate::interp::Interpreter`] walks, and the declaration
607 /// it walks it under.
608 Tree {
609 /// The parameters as source wrote them.
610 ///
611 /// `Interpreter::bind_params` reads every field of one: the name to
612 /// match a labelled argument against, `variadic` to know which
613 /// arguments to gather, `default` to evaluate in the callee's
614 /// environment when an argument was left out, and `is_var` to bind
615 /// the caller's place rather than a copy — which is also what
616 /// `Interpreter::call_shared_method` reads off the first parameter
617 /// of a `lock` closure. The lowering answers that last question when
618 /// it chooses the slots, and has no use for the other three.
619 params: Vec<Param>,
620 /// The block to evaluate.
621 block: Arc<cove_syntax::ast::Block>,
622 /// The declaration this closure came from, and `None` for a lambda,
623 /// which has none of its own.
624 ///
625 /// Read for the written return type: a `dyn Trait` in it is what
626 /// tells the interpreter to wrap what the body produced. The lowered
627 /// form needs no equivalent, because `cove_ir::lower` boxes what a
628 /// function declared as erased returns, so the answer that leaves a
629 /// lowered body is already wrapped.
630 decl: Option<Arc<FnDecl>>,
631 },
632 /// The lowered function `cove_runtime::vm` runs, addressed in the
633 /// [`cove_ir::Program`] that run was given, together with the
634 /// environment object it closes over.
635 ///
636 /// A closure built by one run cannot be called by another, which is true
637 /// of the tree form as well: both name something a particular run owns.
638 /// Which of the two a `Closure` holds is the question *which backend made
639 /// this*, and [`crate::host::Reentry`] is the only thing that asks it.
640 ///
641 /// The environment is here and the captures are not. A `cove-ir`
642 /// closure's captures are inline in a heap object, at the widths its
643 /// layout says, and copying them out into [`Closure::captures`] would be
644 /// materialising a value nothing asked for and losing the identity of the
645 /// storage they came from. So the object crosses instead, as a
646 /// [`LinearClosure`], and [`Closure::captures`] is empty.
647 Linear(LinearClosure),
648}
649
650/// A closure the linear-memory backend made: which function runs, and the
651/// environment object it reads its captures out of.
652///
653/// **It roots the object it names.** A frame is a root because a static map
654/// says which of its slots are references, and the lowering clears a
655/// temporary's slot at its last use — which for a closure handed to a host is
656/// the instruction after the call. The [`crate::host::Reentry`] contract says
657/// a host may keep a callback for later, so the value has to keep the object
658/// alive by itself, and the handle inside this is what does it. Nothing in a
659/// frame need name the object while a host holds one, and after the call
660/// nothing does.
661#[derive(Clone, Debug)]
662pub struct LinearClosure {
663 /// The body, in the program that run was given.
664 pub(crate) function: cove_ir::FunctionId,
665 /// The environment object, and the claim that keeps it a root.
666 pub(crate) env: crate::vm::mem::Rooted,
667}
668
669/// A value usable as a `Map` key or `Set` element.
670///
671/// ADR 0001 draws the line at mutability, not at primitives: "mutable
672/// handles and structs containing them are not valid map keys." A key's
673/// equality must not change while a collection holds it, so this is
674/// recursive rather than a flat list of primitive shapes — a `Struct`, an
675/// `Array`, or an enum case with a payload qualifies exactly when everything
676/// nested inside it does. `Map` and `Set` qualify too: both are immutable
677/// handles, so nesting one as a key changes nothing about the rule, only how
678/// deep the check goes. A `Range` qualifies for the same reason: it is an
679/// immutable value with a stable `eq_value`, ordered consistently by its
680/// `(start, end, inclusive_end)` fields. `Float` is rejected for an unrelated
681/// reason: `NaN` is not equal to itself, which breaks the total order every
682/// key needs.
683#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
684pub enum MapKey {
685 Unit,
686 Bool(bool),
687 Int(i64),
688 Duration(i64),
689 Str(String),
690 /// An enum case, keyed by `(type, case)`, with every payload value
691 /// converted the same way.
692 EnumCase(String, String, Vec<MapKey>),
693 /// A struct, keyed by type name, with every field converted the same
694 /// way, in declaration order, and whether its type is opaque — a key is
695 /// rendered back as a value for `keys()` and for `Display`, and a value
696 /// of an opaque type shows only its name wherever it is read from.
697 Struct(String, Vec<(String, MapKey)>, bool),
698 /// An array, with every element converted the same way. An array is
699 /// fixed-length and immutable, so its equality cannot change.
700 Array(Vec<MapKey>),
701 /// A `Set`. Its elements are already `MapKey`s by construction, so
702 /// nesting one never fails.
703 Set(BTreeSet<MapKey>),
704 /// A `Map`. Its keys are already `MapKey`s by construction; only its
705 /// values need converting, and the first one that cannot be is why
706 /// nesting a `Map` as a key can still fail.
707 Map(BTreeMap<MapKey, MapKey>),
708 /// A range. Immutable with a stable `eq_value`, so it qualifies under the
709 /// same rule as every other key: its equality cannot change while a
710 /// collection holds it. Ordered by `(start, end, inclusive_end)`, which is
711 /// a total order because every field is.
712 Range {
713 start: i64,
714 end: i64,
715 inclusive_end: bool,
716 },
717}
718
719/// Why a value cannot be a `Map` key or `Set` element.
720#[derive(Clone, Debug, PartialEq, Eq)]
721pub struct InvalidKey {
722 /// How the offending part is reached from the value that was tested,
723 /// such as `Point.tags` or `Point.tags[0]`. Empty when the value itself,
724 /// not something nested inside it, is the problem.
725 pub path: String,
726 /// The type that cannot be a key.
727 pub type_name: String,
728}
729
730impl InvalidKey {
731 /// The rule this violation breaks.
732 ///
733 /// `Float` is excluded for a reason distinct from every other rejection:
734 /// `NaN != NaN` breaks the total order a key needs, which has nothing to
735 /// do with mutability. Stating that separately keeps anyone from later
736 /// "fixing" `Float` as if it were just another mutable-handle case.
737 pub fn rule(&self) -> &'static str {
738 if self.type_name == "Float" {
739 "A `Float` cannot be a map key or set element: `NaN` is not equal to itself, which breaks the total order every key needs."
740 } else {
741 "Mutable handles and structs containing them are not valid map keys: a key's equality must not change while a collection holds it."
742 }
743 }
744
745 /// A corrected textual example, tailored to the same distinction.
746 pub fn help(&self) -> String {
747 if self.type_name == "Float" {
748 "convert it to a stable key first, such as rounding to an `Int` or formatting it as a `String`".to_string()
749 } else {
750 "use a value built only from `Bool`, `Int`, `Str`, `Duration`, `Unit`, a range, arrays, structs, enum cases, `Map`, or `Set` — all free of mutable handles".to_string()
751 }
752 }
753}
754
755impl MapKey {
756 /// Converts `value` to a map key or set element, or reports the specific
757 /// part that cannot be one, with the path to reach it.
758 pub fn from_value(value: &Value) -> Result<MapKey, InvalidKey> {
759 Self::convert(None, value)
760 }
761
762 /// `anchor` is the path to `value` from the root value under test, so a
763 /// rejection nested several levels down can still be reported precisely.
764 /// `None` at the root, since a bare value being tested has no name to
765 /// anchor a nested path to; a `Struct` or `Enum` invents one from its own
766 /// type name the first time a path is needed.
767 fn convert(anchor: Option<&str>, value: &Value) -> Result<MapKey, InvalidKey> {
768 // Through the `dyn Trait` wrapper first. Two values `==` calls equal
769 // have to be interchangeable as keys, and equality already looks
770 // through it, so a written `dyn Trait` and a lambda's inferred one
771 // key as the same thing they compare as: the value they hold.
772 match value.erased() {
773 Value(Repr::Unit) => Ok(MapKey::Unit),
774 Value(Repr::Bool(b)) => Ok(MapKey::Bool(*b)),
775 Value(Repr::Int(n)) => Ok(MapKey::Int(*n)),
776 Value(Repr::Duration(ns)) => Ok(MapKey::Duration(*ns)),
777 Value(Repr::Str(s)) => Ok(MapKey::Str(s.to_string())),
778 Value(Repr::Enum(e)) => {
779 let base = anchor
780 .map(str::to_string)
781 .unwrap_or_else(|| format!("{}.{}", short_name(&e.type_name), e.case));
782 let mut payload = Vec::with_capacity(e.payload.len());
783 for (i, item) in e.payload.iter().enumerate() {
784 payload.push(Self::convert(Some(&format!("{base}({i})")), item)?);
785 }
786 Ok(MapKey::EnumCase(
787 e.type_name.to_string(),
788 e.case.to_string(),
789 payload,
790 ))
791 }
792 Value(Repr::Struct(s)) => {
793 let base = anchor
794 .map(str::to_string)
795 .unwrap_or_else(|| short_name(&s.type_name).to_string());
796 let mut fields = Vec::with_capacity(s.fields.len());
797 for (name, field) in &s.fields {
798 let child = Self::convert(Some(&format!("{base}.{name}")), field)?;
799 fields.push((name.to_string(), child));
800 }
801 Ok(MapKey::Struct(s.type_name.to_string(), fields, s.opaque))
802 }
803 Value(Repr::Array(items)) => {
804 let base = anchor.unwrap_or_default();
805 let mut converted = Vec::with_capacity(items.len());
806 for (i, item) in items.iter().enumerate() {
807 converted.push(Self::convert(Some(&format!("{base}[{i}]")), item)?);
808 }
809 Ok(MapKey::Array(converted))
810 }
811 // A `Set`'s elements are already `MapKey`s by construction, so
812 // this never fails.
813 Value(Repr::Set(items)) => Ok(MapKey::Set((**items).clone())),
814 Value(Repr::Map(entries)) => {
815 let base = anchor.unwrap_or_default();
816 let mut converted = BTreeMap::new();
817 for (key, item) in entries.iter() {
818 let child = Self::convert(Some(&format!("{base}[{key}]")), item)?;
819 converted.insert(key.clone(), child);
820 }
821 Ok(MapKey::Map(converted))
822 }
823 Value(Repr::Range {
824 start,
825 end,
826 inclusive_end,
827 }) => Ok(MapKey::Range {
828 start: *start,
829 end: *end,
830 inclusive_end: *inclusive_end,
831 }),
832 Value(Repr::Float(_)) => Err(InvalidKey {
833 path: anchor.map(str::to_string).unwrap_or_default(),
834 type_name: "Float".to_string(),
835 }),
836 other => Err(InvalidKey {
837 path: anchor.map(str::to_string).unwrap_or_default(),
838 type_name: other.type_name(),
839 }),
840 }
841 }
842
843 /// Renders this key back as an ordinary value, for `keys()`, `Set`
844 /// iteration, and `toArray()`.
845 pub fn to_value(&self) -> Value {
846 match self {
847 MapKey::Unit => Value(Repr::Unit),
848 MapKey::Bool(b) => Value(Repr::Bool(*b)),
849 MapKey::Int(n) => Value(Repr::Int(*n)),
850 MapKey::Duration(ns) => Value(Repr::Duration(*ns)),
851 MapKey::Str(s) => Value(Repr::Str(s.as_str().into())),
852 MapKey::EnumCase(type_name, case, payload) => Value(Repr::Enum(Box::new(EnumValue {
853 type_name: type_name.as_str().into(),
854 case: case.as_str().into(),
855 payload: payload.iter().map(MapKey::to_value).collect(),
856 }))),
857 MapKey::Struct(type_name, fields, opaque) => {
858 Value(Repr::Struct(Rc::new(StructValue {
859 type_name: type_name.as_str().into(),
860 fields: fields
861 .iter()
862 .map(|(name, key)| (name.as_str().into(), key.to_value()))
863 .collect(),
864 opaque: *opaque,
865 })))
866 }
867 MapKey::Array(items) => {
868 Value(Repr::Array(items.iter().map(MapKey::to_value).collect()))
869 }
870 MapKey::Set(items) => Value(Repr::Set(Rc::new(items.clone()))),
871 MapKey::Map(entries) => Value(Repr::Map(Rc::new(
872 entries
873 .iter()
874 .map(|(key, value)| (key.clone(), value.to_value()))
875 .collect(),
876 ))),
877 MapKey::Range {
878 start,
879 end,
880 inclusive_end,
881 } => Value(Repr::Range {
882 start: *start,
883 end: *end,
884 inclusive_end: *inclusive_end,
885 }),
886 }
887 }
888}
889
890/// The unqualified name shown in a key path, matching how `Value`'s
891/// `Display` shortens a struct's fully qualified type name.
892fn short_name(qualified: &str) -> &str {
893 qualified.rsplit('.').next().unwrap_or(qualified)
894}
895
896/// A key displays exactly as the value it represents would, so a `Map`'s
897/// entries read the same way here as they would anywhere else in the
898/// language.
899impl fmt::Display for MapKey {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 write!(f, "{}", self.to_value())
902 }
903}
904
905/// The eight builtin names, made once per thread and handed out by
906/// reference count.
907///
908/// `Option` and `Result` are built constantly — every `Array.get`, every
909/// `?`, every fallible builtin — and issue #104 stopped each one allocating
910/// two `Rc<str>` by keeping the strings in a thread-local list and scanning
911/// it for the one asked for. The strings never changed, but the scan stayed:
912/// a `Some(x)` cost two thread-local accesses, two `RefCell` borrows, and
913/// two linear walks comparing string contents. This is the same idea with
914/// the lookup taken out — the names are fields, so a constructor reaches the
915/// thread-local once and clones two `Rc`s out of it. Issue #193 records it
916/// as the other half of #183, which took the payload's allocation and left
917/// this.
918///
919/// Per thread rather than global, for #104's reason: `Rc` is not shareable
920/// across threads, and ADR 0008 gives each task a thread.
921struct BuiltinNames {
922 result: Rc<str>,
923 ok: Rc<str>,
924 err: Rc<str>,
925 option: Rc<str>,
926 some: Rc<str>,
927 none: Rc<str>,
928 error: Rc<str>,
929 message: Rc<str>,
930}
931
932thread_local! {
933 /// Built on the first `Ok`, `Err`, `Some`, `None` or `Error` this thread
934 /// makes, which is the same eight allocations #104's list made lazily,
935 /// paid once rather than one name at a time.
936 static BUILTIN_NAMES: BuiltinNames = BuiltinNames {
937 result: Rc::from(RESULT.name),
938 ok: Rc::from(OK_CASE.name),
939 err: Rc::from(ERR_CASE.name),
940 option: Rc::from(OPTION.name),
941 some: Rc::from(SOME_CASE.name),
942 none: Rc::from(NONE_CASE.name),
943 error: Rc::from(ERROR.name),
944 message: Rc::from(MESSAGE_FIELD.name),
945 };
946}
947
948/// The builtin `Option`, `Result`, and `Error` values, built and read through
949/// the one description of what they are made of.
950///
951/// `Ok`, `Err`, `Some`, `None`, and an `Error`'s `message` are declared in
952/// [`cove_schema::builtins`], which is also where `cove-sema` reads them to
953/// check a `match` and to type a pattern's binding. Everything in this
954/// workspace that builds one of these values or asks which case a value is
955/// goes through the constructors and readers below, so the four case names
956/// are stated once and the question "is this an `Ok`?" has one answer.
957impl Value {
958 /// `Ok(value)`
959 pub fn ok(value: Value) -> Value {
960 BUILTIN_NAMES.with(|names| {
961 Value(Repr::Enum(Box::new(EnumValue {
962 type_name: names.result.clone(),
963 case: names.ok.clone(),
964 payload: Payload::One(value),
965 })))
966 })
967 }
968
969 /// `Err(error)`
970 pub fn err(error: Value) -> Value {
971 BUILTIN_NAMES.with(|names| {
972 Value(Repr::Enum(Box::new(EnumValue {
973 type_name: names.result.clone(),
974 case: names.err.clone(),
975 payload: Payload::One(error),
976 })))
977 })
978 }
979
980 /// `Some(value)`
981 pub fn some(value: Value) -> Value {
982 BUILTIN_NAMES.with(|names| {
983 Value(Repr::Enum(Box::new(EnumValue {
984 type_name: names.option.clone(),
985 case: names.some.clone(),
986 payload: Payload::One(value),
987 })))
988 })
989 }
990
991 /// `None`
992 pub fn none() -> Value {
993 BUILTIN_NAMES.with(|names| {
994 Value(Repr::Enum(Box::new(EnumValue {
995 type_name: names.option.clone(),
996 case: names.none.clone(),
997 payload: Payload::Empty,
998 })))
999 })
1000 }
1001
1002 /// The builtin `Error` struct.
1003 pub fn error(message: impl Into<String>) -> Value {
1004 let message = Value(Repr::Str(message.into().into()));
1005 BUILTIN_NAMES.with(|names| {
1006 Value(Repr::Struct(Rc::new(StructValue {
1007 type_name: names.error.clone(),
1008 fields: vec![(names.message.clone(), message)],
1009 opaque: false,
1010 })))
1011 })
1012 }
1013
1014 /// A value of the declared struct type `type_name`, carrying `fields` in
1015 /// declaration order.
1016 ///
1017 /// `type_name` is the qualified name the declaring module gives it, such
1018 /// as `rules.policy.PullRequest`: that is the name every value of a
1019 /// declared type carries, and the name an invocation and the Host API
1020 /// boundary both check against.
1021 ///
1022 /// This exists so that a host building an argument for
1023 /// [`Vm::invoke`](crate::Vm::invoke) does not have to name
1024 /// [`StructValue`]'s layout to do it — the `Rc`, the field vector, and in
1025 /// particular `opaque`, which records that the *declaration* said `export
1026 /// opaque struct` (ADR 0014) and is therefore not a thing a caller has an
1027 /// answer for. Issue #109 asks that the internal representation become
1028 /// less exposed to embedders; this is one place it was exposed for no
1029 /// reason.
1030 pub fn structure<N: Into<Rc<str>>>(
1031 type_name: impl Into<Rc<str>>,
1032 fields: impl IntoIterator<Item = (N, Value)>,
1033 ) -> Value {
1034 Value(Repr::Struct(Rc::new(StructValue {
1035 type_name: type_name.into(),
1036 fields: fields
1037 .into_iter()
1038 .map(|(name, value)| (name.into(), value))
1039 .collect(),
1040 opaque: false,
1041 })))
1042 }
1043
1044 /// A value of the declared enum type `type_name`, in the case `case`,
1045 /// carrying `payload` in the order the case declares it.
1046 ///
1047 /// The companion of [`Value::structure`] for the other declared shape.
1048 /// [`Value::ok`] and the three beside it build the *builtin* enums, whose
1049 /// case names come from `cove_schema::builtins` and are not a caller's to
1050 /// choose; this one takes both names because a package's own enum is a
1051 /// package's own.
1052 pub fn enumeration(
1053 type_name: impl Into<Rc<str>>,
1054 case: impl Into<Rc<str>>,
1055 payload: impl IntoIterator<Item = Value>,
1056 ) -> Value {
1057 Value(Repr::Enum(Box::new(EnumValue {
1058 type_name: type_name.into(),
1059 case: case.into(),
1060 payload: payload.into_iter().collect(),
1061 })))
1062 }
1063
1064 /// An `Array` holding `items`, in order.
1065 ///
1066 /// The companion of [`Value::structure`], and there for the same reason: a
1067 /// host that builds an array should not have to know that the elements are
1068 /// stored behind a shared pointer to a slice.
1069 pub fn array(items: impl IntoIterator<Item = Value>) -> Value {
1070 Value(Repr::Array(items.into_iter().collect()))
1071 }
1072
1073 /// A `Set` holding `items`.
1074 ///
1075 /// The elements are [`MapKey`]s and not [`Value`]s, and that is the
1076 /// [`MapKey`] restriction showing through rather than an inconvenience: a
1077 /// set of values would be a constructor that could fail, and there is
1078 /// nothing sensible for it to do when it does. A host building one from
1079 /// its own data writes the key it means — `MapKey::Str(name)` for a set of
1080 /// names — and a host holding a [`Value`] it did not build converts with
1081 /// [`MapKey::from_value`], which reports the part that cannot be a key and
1082 /// the path to reach it.
1083 ///
1084 /// Duplicates collapse, exactly as they do for a `Set` a Cove program
1085 /// builds, and the order the set iterates in is ascending key order
1086 /// whatever order they arrived in.
1087 pub fn set(items: impl IntoIterator<Item = MapKey>) -> Value {
1088 Value(Repr::Set(Rc::new(items.into_iter().collect())))
1089 }
1090
1091 /// A `Map` holding `entries`.
1092 ///
1093 /// The companion of [`Value::set`], with the same reason for taking a
1094 /// [`MapKey`]: only the key carries the restriction, so the value half is
1095 /// an ordinary [`Value`]. A later entry under a key an earlier one used
1096 /// replaces it.
1097 pub fn map(entries: impl IntoIterator<Item = (MapKey, Value)>) -> Value {
1098 Value(Repr::Map(Rc::new(entries.into_iter().collect())))
1099 }
1100
1101 /// `()`, the value a statement and a function with no result answer.
1102 pub fn unit() -> Value {
1103 Value(Repr::Unit)
1104 }
1105
1106 /// The `Bool` `b`.
1107 pub fn bool(b: bool) -> Value {
1108 Value(Repr::Bool(b))
1109 }
1110
1111 /// The `Int` `n`.
1112 ///
1113 /// A full sixty-four bits, because an `Int` is one: issue #109 measured
1114 /// the alternatives that are not, and NaN boxing and pointer tagging are
1115 /// refused rather than deferred because neither can hold every `Int` and
1116 /// every `Float` at once.
1117 pub fn int(n: i64) -> Value {
1118 Value(Repr::Int(n))
1119 }
1120
1121 /// The `Float` `x`, including every NaN and both zeroes.
1122 pub fn float(x: f64) -> Value {
1123 Value(Repr::Float(x))
1124 }
1125
1126 /// The `Duration` of `nanos` nanoseconds.
1127 ///
1128 /// Nanoseconds rather than a [`std::time::Duration`], for the reason
1129 /// [`Value::as_duration_nanos`] gives on the way out: a Cove duration is
1130 /// a *signed* count of them, and `-1s` is an ordinary value that
1131 /// `std::time::Duration` cannot hold.
1132 pub fn duration(nanos: i64) -> Value {
1133 Value(Repr::Duration(nanos))
1134 }
1135
1136 /// The `String` `text`.
1137 ///
1138 /// Named for the Cove type and not for Rust's, which is why it takes
1139 /// anything a string can be made from rather than a `String`
1140 /// specifically: `Value::string("hi")` copies the characters once and
1141 /// says nothing about where they end up.
1142 pub fn string(text: impl Into<Rc<str>>) -> Value {
1143 Value(Repr::Str(text.into()))
1144 }
1145
1146 /// The range `start..end`, or `start..<end` when `inclusive_end` is
1147 /// false.
1148 ///
1149 /// Both bounds as source writes them, rather than the normalised
1150 /// half-open pair [`Value::range`] answers with: `1..3` and `1..<4` cover
1151 /// the same integers and are still two different values, since `==`
1152 /// compares the bounds a range was written with.
1153 ///
1154 /// The name is `range_of` and not `range` because the reader took
1155 /// `range`, and the readers are what issue #195 shipped.
1156 pub fn range_of(start: i64, end: i64, inclusive_end: bool) -> Value {
1157 Value(Repr::Range {
1158 start,
1159 end,
1160 inclusive_end,
1161 })
1162 }
1163
1164 /// A handle to a resource the host owns, such as a database connection.
1165 ///
1166 /// The companion of [`Value::resource`], and it takes the whole handle
1167 /// because ADR 0013 decides that a handle *is* a name and every field of
1168 /// it is part of that name. What it hides is the shared pointer, which is
1169 /// there so a handle can cross into a task when its schema allows it —
1170 /// pass either a [`ResourceHandle`] or the `Arc` that
1171 /// [`ResourceHandle::new`](crate::host::ResourceHandle::new) answers.
1172 ///
1173 /// The name is `from_resource` and not `resource` because the reader took
1174 /// `resource`.
1175 pub fn from_resource(handle: impl Into<Arc<ResourceHandle>>) -> Value {
1176 Value(Repr::Resource(handle.into()))
1177 }
1178
1179 /// A bound host operation, such as `console.println`.
1180 ///
1181 /// The companion of [`Value::host_op`]. Two names and not an
1182 /// implementation: what they name is found in the registry at the call.
1183 pub fn host_fn(module: impl Into<Rc<str>>, op: impl Into<Rc<str>>) -> Value {
1184 Value(Repr::HostFn(Rc::new(HostFnValue {
1185 module: module.into(),
1186 op: op.into(),
1187 })))
1188 }
1189
1190 /// A bound host module, such as `console`.
1191 pub fn host_module(name: impl Into<Rc<str>>) -> Value {
1192 Value(Repr::HostModule(name.into()))
1193 }
1194
1195 /// A type used as a value, such as `Vector` in `Vector.of(1, 2)`.
1196 ///
1197 /// The name is `type_value` and not `type_name` because
1198 /// [`Value::type_name`] answers the name of the type a value *is*, which
1199 /// is a different question asked of every value rather than of this one.
1200 pub fn type_value(name: impl Into<Rc<str>>) -> Value {
1201 Value(Repr::Type(name.into()))
1202 }
1203
1204 /// Whether this is an `Ok`, the success case of a `Result`.
1205 pub fn is_ok(&self) -> bool {
1206 self.builtin_case(&RESULT, &OK_CASE).is_some()
1207 }
1208
1209 /// Whether this is an `Err`.
1210 pub fn is_err(&self) -> bool {
1211 self.builtin_case(&RESULT, &ERR_CASE).is_some()
1212 }
1213
1214 /// Whether this is a `Some`.
1215 pub fn is_some(&self) -> bool {
1216 self.builtin_case(&OPTION, &SOME_CASE).is_some()
1217 }
1218
1219 /// What an `Ok` carries, when this is one.
1220 ///
1221 /// The payload is a slice rather than a value because what a caller does
1222 /// with an empty one differs: the `?` operator answers `()` and a
1223 /// diagnostic answers nothing at all. The schema says an `Ok` carries
1224 /// exactly one value, so an empty one is a host that broke its word.
1225 pub fn ok_payload(&self) -> Option<&[Value]> {
1226 self.builtin_case(&RESULT, &OK_CASE)
1227 .map(|case| case.payload.as_slice())
1228 }
1229
1230 /// What an `Err` carries, when this is one.
1231 pub fn err_payload(&self) -> Option<&[Value]> {
1232 self.builtin_case(&RESULT, &ERR_CASE)
1233 .map(|case| case.payload.as_slice())
1234 }
1235
1236 /// What a `Some` carries, when this is one.
1237 pub fn some_payload(&self) -> Option<&[Value]> {
1238 self.builtin_case(&OPTION, &SOME_CASE)
1239 .map(|case| case.payload.as_slice())
1240 }
1241
1242 /// The `message` a builtin `Error` carries, when this is one.
1243 pub fn error_message(&self) -> Option<&Value> {
1244 match self {
1245 Value(Repr::Struct(value)) if &*value.type_name == ERROR.name => {
1246 value.get(MESSAGE_FIELD.name)
1247 }
1248 _ => None,
1249 }
1250 }
1251
1252 /// This value as `case` of the builtin enum `schema`, when it is one.
1253 ///
1254 /// Both halves of the question are asked here: a user enum may declare a
1255 /// case called `Ok`, and it is not this one.
1256 fn builtin_case(&self, schema: &BuiltinSchema, case: &CaseSchema) -> Option<&EnumValue> {
1257 match self {
1258 Value(Repr::Enum(value))
1259 if &*value.type_name == schema.name && &*value.case == case.name =>
1260 {
1261 Some(value)
1262 }
1263 _ => None,
1264 }
1265 }
1266
1267 /// The name shown in diagnostics.
1268 /// Whether `other` is a value of the same type as this one, without
1269 /// naming either type.
1270 ///
1271 /// `==` has to refuse a comparison between two types before it compares
1272 /// two values, and it asked that question by building both type names and
1273 /// comparing the strings. Two allocations per comparison is a great deal
1274 /// to pay for an answer that is a discriminant check and, for the two
1275 /// declared kinds, one string comparison — and a parser compares
1276 /// characters constantly, so this was measurable (issue #104). The names
1277 /// are still built for the diagnostic, which happens once.
1278 pub fn same_type_as(&self, other: &Value) -> bool {
1279 match (self, other) {
1280 (Value(Repr::Struct(left)), Value(Repr::Struct(right))) => {
1281 left.type_name == right.type_name
1282 }
1283 (Value(Repr::Enum(left)), Value(Repr::Enum(right))) => {
1284 left.type_name == right.type_name
1285 }
1286 (Value(Repr::Dyn(left)), Value(Repr::Dyn(right))) => {
1287 left.trait_name == right.trait_name
1288 }
1289 (Value(Repr::Resource(left)), Value(Repr::Resource(right))) => {
1290 left.module == right.module && left.type_name == right.type_name
1291 }
1292 (Value(Repr::HostModule(left)), Value(Repr::HostModule(right))) => left == right,
1293 (Value(Repr::HostFn(left)), Value(Repr::HostFn(right))) => {
1294 left.module == right.module && left.op == right.op
1295 }
1296 (Value(Repr::Type(left)), Value(Repr::Type(right))) => left == right,
1297 // Everything else is one type per variant, so the discriminants
1298 // answering the same is the whole of the question.
1299 _ => std::mem::discriminant(&self.0) == std::mem::discriminant(&other.0),
1300 }
1301 }
1302
1303 /// The name of the declared type this value is of, for a struct or an
1304 /// enum, and `None` for everything else.
1305 ///
1306 /// A method declared in a package can only ever be found on one of those
1307 /// two, so this is what receiver dispatch asks rather than
1308 /// [`Value::type_name`]: no name is built at all for the receivers that
1309 /// have none, and a declared one hands back the name it already holds.
1310 ///
1311 /// **A `Some` here is not a declared type.** The builtin `Option` and
1312 /// `Result` are `Repr::Enum` as well, and answer their own bare names —
1313 /// `Option`, with no module in front. A caller asking "is this a
1314 /// declared type" has to look for the dot; a caller that read `is_some`
1315 /// as the answer got two builtins wrong.
1316 pub fn declared_type_name(&self) -> Option<&Rc<str>> {
1317 match self {
1318 Value(Repr::Struct(value)) => Some(&value.type_name),
1319 Value(Repr::Enum(value)) => Some(&value.type_name),
1320 _ => None,
1321 }
1322 }
1323
1324 pub fn type_name(&self) -> String {
1325 match self {
1326 Value(Repr::Unit) => "Unit".into(),
1327 Value(Repr::Bool(_)) => "Bool".into(),
1328 Value(Repr::Int(_)) => "Int".into(),
1329 Value(Repr::Float(_)) => "Float".into(),
1330 Value(Repr::Duration(_)) => "Duration".into(),
1331 Value(Repr::Str(_)) => "String".into(),
1332 Value(Repr::Array(_)) => "Array".into(),
1333 Value(Repr::Vector(_)) => "Vector".into(),
1334 Value(Repr::Map(_)) => "Map".into(),
1335 Value(Repr::Set(_)) => "Set".into(),
1336 Value(Repr::Struct(s)) => s.type_name.to_string(),
1337 Value(Repr::Enum(e)) => e.type_name.to_string(),
1338 Value(Repr::Closure(_)) => "fn".into(),
1339 Value(Repr::Dyn(d)) => format!("dyn {}", d.trait_name),
1340 Value(Repr::HostModule(m)) => format!("host module `{m}`"),
1341 Value(Repr::Resource(handle)) => handle.qualified_type(),
1342 Value(Repr::HostFn(host)) => {
1343 format!("host operation `{}.{}`", host.module, host.op)
1344 }
1345 Value(Repr::Type(t)) => format!("type `{t}`"),
1346 Value(Repr::Range { .. }) => "Range".into(),
1347 Value(Repr::TaskScope(_)) => "TaskScope".into(),
1348 Value(Repr::Task(_)) => "Task".into(),
1349 Value(Repr::Shared(_)) => "Shared".into(),
1350 }
1351 }
1352
1353 /// The value a trait object holds, or this value when it is not one.
1354 ///
1355 /// A `dyn Trait` wrapper records where a value was converted, and the
1356 /// checker decides where that is: a written type converts and a lambda's
1357 /// inferred result does not, though both have type `dyn Trait`. Nothing
1358 /// a program can ask should be able to tell those two apart, so
1359 /// everything that compares, renders, or keys a value looks through the
1360 /// wrapper first.
1361 pub fn erased(&self) -> &Value {
1362 match self {
1363 Value(Repr::Dyn(d)) => d.value.erased(),
1364 other => other,
1365 }
1366 }
1367
1368 /// Value equality. Identity, when available, is explicit and separate.
1369 pub fn eq_value(&self, other: &Value) -> bool {
1370 match (self.erased(), other.erased()) {
1371 (Value(Repr::Unit), Value(Repr::Unit)) => true,
1372 (Value(Repr::Bool(a)), Value(Repr::Bool(b))) => a == b,
1373 (Value(Repr::Int(a)), Value(Repr::Int(b))) => a == b,
1374 (Value(Repr::Float(a)), Value(Repr::Float(b))) => a == b,
1375 (Value(Repr::Duration(a)), Value(Repr::Duration(b))) => a == b,
1376 (Value(Repr::Str(a)), Value(Repr::Str(b))) => a == b,
1377 (Value(Repr::Array(a)), Value(Repr::Array(b))) => {
1378 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_value(y))
1379 }
1380 // Both sides are `BTreeMap`s keyed the same way, so two maps with
1381 // the same keys line up entry-for-entry once both are in their
1382 // one true ascending order.
1383 (Value(Repr::Map(a)), Value(Repr::Map(b))) => {
1384 a.len() == b.len()
1385 && a.iter()
1386 .zip(b.iter())
1387 .all(|((ka, va), (kb, vb))| ka == kb && va.eq_value(vb))
1388 }
1389 // `BTreeSet<MapKey>` already compares as a set of keys.
1390 (Value(Repr::Set(a)), Value(Repr::Set(b))) => a == b,
1391 (Value(Repr::Struct(a)), Value(Repr::Struct(b))) => {
1392 a.type_name == b.type_name
1393 && a.fields.len() == b.fields.len()
1394 && a.fields
1395 .iter()
1396 .zip(b.fields.iter())
1397 .all(|((_, x), (_, y))| x.eq_value(y))
1398 }
1399 (Value(Repr::Enum(a)), Value(Repr::Enum(b))) => {
1400 a.type_name == b.type_name
1401 && a.case == b.case
1402 && a.payload.len() == b.payload.len()
1403 && a.payload
1404 .iter()
1405 .zip(b.payload.iter())
1406 .all(|(x, y)| x.eq_value(y))
1407 }
1408 // Ranges compare by the bounds they were written with, so `0..<3`
1409 // and `0..2` are distinct values even though they yield the same
1410 // integers.
1411 (
1412 Value(Repr::Range {
1413 start: a,
1414 end: b,
1415 inclusive_end: a_inclusive,
1416 }),
1417 Value(Repr::Range {
1418 start: c,
1419 end: d,
1420 inclusive_end: b_inclusive,
1421 }),
1422 ) => a == c && b == d && a_inclusive == b_inclusive,
1423 // Two handles are equal when they name the same resource. A
1424 // handle has no contents to compare, so naming the same thing is
1425 // the whole of being the same value.
1426 (Value(Repr::Resource(a)), Value(Repr::Resource(b))) => a.names_same(b),
1427 // `==` means value equality regardless of mutability, so `Vector`
1428 // compares its current elements structurally, exactly like
1429 // `Array`. Storage identity — whether two handles are the same
1430 // growable buffer — is the separate question `is` answers.
1431 (Value(Repr::Vector(a)), Value(Repr::Vector(b))) => {
1432 let a = a.elements.borrow();
1433 let b = b.elements.borrow();
1434 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_value(y))
1435 }
1436 _ => false,
1437 }
1438 }
1439}
1440
1441/// Reading a value without naming its representation.
1442///
1443/// The constructors above — [`Value::structure`], [`Value::enumeration`],
1444/// [`Value::array`], [`Value::set`], [`Value::map`], and the builtin four —
1445/// let a host *build* every shape that crosses the boundary without writing
1446/// an `Rc`, a `Box`, a field vector or the `opaque` flag. These are the other
1447/// half: they let a host *read* the same shapes the same way.
1448///
1449/// Only one half existed, and the missing half cost something every time the
1450/// representation moved. Issue #104 made `Value::Struct` an
1451/// `Rc<StructValue>`; issue #109 put `Value::HostFn`'s two names behind one
1452/// pointer and took every value in the program from forty bytes to
1453/// twenty-four; issue #121 replaced a closure's parameter list with an arity;
1454/// issue #183 replaced an enum payload's `Vec<Value>` with [`Payload`]. Every
1455/// one of those was invisible to a host that only built values and a source
1456/// break for one that read them, because reading meant matching on a variant
1457/// and a match on a variant is a match on the representation. Issue #186 is
1458/// where that was written down, and this is its answer.
1459///
1460/// **A reader borrows.** It hands back a reference into the value it was
1461/// asked about and the caller clones what it means to keep, which is what
1462/// [`Value::ok_payload`] and [`StructValue::get`] already did and what a host
1463/// wants: a conversion into the host's own types reads each part once and
1464/// keeps no `Value` at all. Borrowing is the half of this that constrains
1465/// what can still move, and it constrains it in one direction — every part a
1466/// reader answers with has to be *stored* as the thing it answers with. A
1467/// struct's fields can move behind a different pointer, a shared shape table,
1468/// or an inline arity the way [`Payload`] already did, and none of that is
1469/// visible here; they cannot become values that are *computed* — unpacked
1470/// from a tagged word, decoded lazily, or held under a lock — without these
1471/// signatures changing. A reader that cloned would forbid none of that, and
1472/// would charge every read for the possibility. A `Vector` is where
1473/// the line already falls, and it falls the same way for building: its
1474/// elements are behind a `RefCell` because the language lets an alias write
1475/// them, so there is no borrowing reader for one here and no constructor for
1476/// one above.
1477///
1478/// **A wrong shape answers `None`.** Asking an `Int` for its fields is the
1479/// host's mistake rather than the program's — no Cove code asked for it and
1480/// none can handle it — so it is not a
1481/// [`RuntimeError`](crate::error::RuntimeError); and it is not a panic
1482/// either, because a host converting a value it did not build wants to report
1483/// what arrived instead. [`Value::type_name`] is what names that in the
1484/// report. This is the convention the readers that already existed use:
1485/// [`Value::ok_payload`], [`Value::error_message`] and [`StructValue::get`]
1486/// all answer `None` to the question they were not the right value for.
1487///
1488/// **A reader looks through `dyn Trait`.** Each of these calls
1489/// [`Value::erased`] first, for the reason that method gives: the wrapper
1490/// records where a value was converted, nothing a program can ask should be
1491/// able to tell a written `dyn Trait` from a lambda's inferred one, and
1492/// [`fmt::Display`] already looks through it — "the wrapper is a
1493/// representation, not something the program put there". There is no reader
1494/// for the wrapper itself, which matches the constructors, none of which can
1495/// build one.
1496impl Value {
1497 /// The `Bool` this is.
1498 pub fn as_bool(&self) -> Option<bool> {
1499 match self.erased() {
1500 Value(Repr::Bool(b)) => Some(*b),
1501 _ => None,
1502 }
1503 }
1504
1505 /// The `Int` this is.
1506 ///
1507 /// A full sixty-four bits, because an `Int` is one and overflow is a
1508 /// broken invariant rather than a wrap.
1509 pub fn as_int(&self) -> Option<i64> {
1510 match self.erased() {
1511 Value(Repr::Int(n)) => Some(*n),
1512 _ => None,
1513 }
1514 }
1515
1516 /// The `Float` this is.
1517 pub fn as_float(&self) -> Option<f64> {
1518 match self.erased() {
1519 Value(Repr::Float(x)) => Some(*x),
1520 _ => None,
1521 }
1522 }
1523
1524 /// The `Duration` this is, in nanoseconds.
1525 ///
1526 /// Nanoseconds rather than a [`std::time::Duration`], because a Cove
1527 /// duration is a signed count of them: `-1s` is an ordinary value and
1528 /// `std::time::Duration` cannot hold it.
1529 pub fn as_duration_nanos(&self) -> Option<i64> {
1530 match self.erased() {
1531 Value(Repr::Duration(ns)) => Some(*ns),
1532 _ => None,
1533 }
1534 }
1535
1536 /// The `String` this is.
1537 pub fn as_str(&self) -> Option<&str> {
1538 match self.erased() {
1539 Value(Repr::Str(text)) => Some(text),
1540 _ => None,
1541 }
1542 }
1543
1544 /// Whether this is `()`.
1545 pub fn is_unit(&self) -> bool {
1546 matches!(self.erased(), Value(Repr::Unit))
1547 }
1548
1549 /// The declared type this value is of — `rules.policy.Decision`, or
1550 /// `Option` for a builtin — for a struct or an enum, and `None` for
1551 /// everything else.
1552 ///
1553 /// The qualified name [`Value::structure`] and [`Value::enumeration`]
1554 /// take, which is what a host checks an answer against before reading it
1555 /// apart. [`Value::declared_type_name`] answers the same question with
1556 /// the shared handle itself, because the two backends clone it to
1557 /// dispatch a method; this is the reader, and it does not say what the
1558 /// handle is made of.
1559 pub fn declared_type(&self) -> Option<&str> {
1560 self.erased().declared_type_name().map(|name| &**name)
1561 }
1562
1563 /// The field `name` of a struct value.
1564 ///
1565 /// `None` both when this is not a struct and when the struct declares no
1566 /// such field, because a host has the same thing to say about either and
1567 /// [`Value::type_name`] is what says it: "`Int` carries no field
1568 /// `policy`" and "`rules.policy.Decision` carries no field `polciy`" are
1569 /// the same sentence with the name filled in.
1570 pub fn field(&self, name: &str) -> Option<&Value> {
1571 match self.erased() {
1572 Value(Repr::Struct(value)) => value.get(name),
1573 _ => None,
1574 }
1575 }
1576
1577 /// A struct value's fields, in declaration order, and `None` when this is
1578 /// not a struct — which is also how a host asks whether it is one.
1579 ///
1580 /// Declaration order rather than the order anything asked for: it is the
1581 /// order [`Value::structure`] was handed and the order the declaration
1582 /// states, so a host reading a struct positionally reads what a host
1583 /// building one wrote.
1584 ///
1585 /// An `export opaque struct` (ADR 0014) answers here like any other. The
1586 /// flag governs *rendering*, because a `Display` has no idea which module
1587 /// is watching; a host holding the value has already been handed it, and
1588 /// hiding the fields from it would hide them from the very code the
1589 /// module exported the value to.
1590 pub fn fields(&self) -> Option<impl Iterator<Item = (&str, &Value)> + '_> {
1591 match self.erased() {
1592 Value(Repr::Struct(value)) => Some(value.fields.iter().map(|(name, v)| (&**name, v))),
1593 _ => None,
1594 }
1595 }
1596
1597 /// The case of an enum value, such as `Some`, `Err`, or `Require`.
1598 ///
1599 /// The case alone, unqualified, exactly as [`Value::enumeration`] takes
1600 /// it; [`Value::declared_type`] is the other half of the name.
1601 pub fn case(&self) -> Option<&str> {
1602 match self.erased() {
1603 Value(Repr::Enum(value)) => Some(&value.case),
1604 _ => None,
1605 }
1606 }
1607
1608 /// What an enum value's case carries, in the order the case declares it.
1609 ///
1610 /// A slice, and an empty one for a case that carries nothing, for the
1611 /// reason [`Value::ok_payload`] gives: what a caller does with an empty
1612 /// payload differs and only the caller knows which. Those four ask a
1613 /// builtin question — "is this an `Ok`?" — and answer the payload as a
1614 /// consequence; this one is asked of a value whose case the caller reads
1615 /// for itself with [`Value::case`], which is what a package's own enum
1616 /// needs.
1617 pub fn payload(&self) -> Option<&[Value]> {
1618 match self.erased() {
1619 Value(Repr::Enum(value)) => Some(value.payload.as_slice()),
1620 _ => None,
1621 }
1622 }
1623
1624 /// An `Array`'s elements, in order.
1625 ///
1626 /// The companion of [`Value::array`]. A `Vector` answers `None` and that
1627 /// is not an oversight: its elements are behind a `RefCell` because an
1628 /// alias may write them, so nothing can hand out a plain slice of them,
1629 /// and there is no constructor for one either.
1630 /// [`Value::vector_elements`] is how a vector is read — a guard rather
1631 /// than a slice, which is what a part behind a cell can answer with.
1632 pub fn items(&self) -> Option<&[Value]> {
1633 match self.erased() {
1634 Value(Repr::Array(items)) => Some(items),
1635 _ => None,
1636 }
1637 }
1638
1639 /// A `Set`'s elements, in ascending key order.
1640 ///
1641 /// [`MapKey`]s and not [`Value`]s, for the reason [`Value::set`] gives on
1642 /// the way in: the restriction is real, and showing it is better than a
1643 /// reader that pretends a set holds anything. [`MapKey::to_value`]
1644 /// converts one back.
1645 ///
1646 /// Ascending key order whatever order they were inserted in, which is the
1647 /// order a Cove program iterating the same set sees.
1648 pub fn elements(&self) -> Option<impl Iterator<Item = &MapKey> + '_> {
1649 match self.erased() {
1650 Value(Repr::Set(items)) => Some(items.iter()),
1651 _ => None,
1652 }
1653 }
1654
1655 /// A `Map`'s entries, in ascending key order.
1656 ///
1657 /// The companion of [`Value::map`], with the same split: only the key
1658 /// carries the [`MapKey`] restriction, so the value half is an ordinary
1659 /// [`Value`].
1660 pub fn entries(&self) -> Option<impl Iterator<Item = (&MapKey, &Value)> + '_> {
1661 match self.erased() {
1662 Value(Repr::Map(entries)) => Some(entries.iter()),
1663 _ => None,
1664 }
1665 }
1666
1667 /// A `Range`'s bounds, half-open.
1668 ///
1669 /// [`RangeBounds`] rather than the three fields the variant holds,
1670 /// because `..` and `..<` are two ways of writing one range: `1..3` and
1671 /// `1..<4` cover the same integers, and a host asking what a range covers
1672 /// should not have to normalise them itself. The bounds are `i128` so
1673 /// that an inclusive `i64::MAX` end cannot overflow.
1674 pub fn range(&self) -> Option<RangeBounds> {
1675 match *self.erased() {
1676 Value(Repr::Range {
1677 start,
1678 end,
1679 inclusive_end,
1680 }) => Some(RangeBounds::of(start, end, inclusive_end)),
1681 _ => None,
1682 }
1683 }
1684
1685 /// The resource handle this is.
1686 ///
1687 /// [`ResourceHandle`] is the answer rather than something this hides,
1688 /// because ADR 0013 decides that a handle *is* a name: "every field of it
1689 /// is part of the name", and there is no field for state because the
1690 /// state is the host's. What this hides is the `Arc`, which is there so
1691 /// that a handle can cross into a task when its schema allows it.
1692 pub fn resource(&self) -> Option<&ResourceHandle> {
1693 match self.erased() {
1694 Value(Repr::Resource(handle)) => Some(handle),
1695 _ => None,
1696 }
1697 }
1698
1699 /// The module and operation a bound host operation names, such as
1700 /// `("console", "println")`.
1701 ///
1702 /// Two names and not an implementation: a bound host operation is a name
1703 /// the way [`ValueView::HostModule`] is, and what it names is found in the
1704 /// registry at the call. This is the reader for the variant issue #109
1705 /// boxed to buy the sixteen bytes — a host that matched `Value::HostFn {
1706 /// module, op }` had to be rewritten, and one that had called this would
1707 /// not have noticed.
1708 pub fn host_op(&self) -> Option<(&str, &str)> {
1709 match self.erased() {
1710 Value(Repr::HostFn(host)) => Some((&host.module, &host.op)),
1711 _ => None,
1712 }
1713 }
1714
1715 /// How many parameters a closure value declares.
1716 ///
1717 /// Parameters and not arguments a call must supply: a defaulted or a
1718 /// variadic parameter counts like any other. A host that was handed a
1719 /// callback asks this to refuse one of the wrong shape before calling it
1720 /// back through [`Reentry`](crate::host::Reentry), which is the only way
1721 /// to call one, since the body belongs to the backend that made it. This
1722 /// is the reader for the field issue #121 replaced with a count, and it
1723 /// is the whole of a closure a host has any business reading.
1724 pub fn arity(&self) -> Option<usize> {
1725 match self.erased() {
1726 Value(Repr::Closure(closure)) => Some(closure.arity),
1727 _ => None,
1728 }
1729 }
1730
1731 /// A `Vector`'s elements, in order, for as long as the guard is held.
1732 ///
1733 /// The companion of [`Value::items`], which answers `None` for a
1734 /// `Vector` because its elements sit behind a cell — an alias may write
1735 /// them, so nothing can hand out a plain `&[Value]` of them. Issue #196
1736 /// records that as "the one place the borrow-based reader design cannot
1737 /// reach"; ADR 0028 decision 7 is where it is reached, and this is the
1738 /// shape of the answer: a part whose storage will not sit still is handed
1739 /// out as an opaque guard, and the guard is public API.
1740 ///
1741 /// [`Elements`] derefs to `[Value]`, so a host reads a vector the way it
1742 /// reads an array. Holding one *borrows* the vector: drop it before
1743 /// calling back into Cove through
1744 /// [`Reentry`](crate::host::Reentry), because Cove code that writes the
1745 /// same vector while the guard is alive is a panic rather than a data
1746 /// race.
1747 pub fn vector_elements(&self) -> Option<Elements<'_>> {
1748 match self.erased() {
1749 Value(Repr::Vector(storage)) => Some(Elements(storage.elements.borrow())),
1750 _ => None,
1751 }
1752 }
1753
1754 /// The trait a `dyn Trait` value was used at, such as `render.Display`.
1755 ///
1756 /// The one reader that does *not* look through the wrapper, because it is
1757 /// the reader for the wrapper. Every other reader and
1758 /// [`Value::view`] call [`Value::erased`] first, for the reason that
1759 /// method gives — the wrapper is a representation, not something the
1760 /// program put there — so this is how a host that genuinely wants to name
1761 /// the trait in a diagnostic asks for it.
1762 pub fn dyn_trait(&self) -> Option<&str> {
1763 match self {
1764 Value(Repr::Dyn(d)) => Some(&d.trait_name),
1765 _ => None,
1766 }
1767 }
1768
1769 /// Classify this value: what *kind* of Cove value it is, and its parts.
1770 ///
1771 /// O(1), allocates nothing, and borrows from `self`. It looks through
1772 /// `dyn Trait` exactly as every reader beside it does, which is why
1773 /// [`ValueView`] has no `Dyn` variant; [`Value::dyn_trait`] is how a host
1774 /// asks about the wrapper.
1775 ///
1776 /// This is the exhaustive match that sealing takes away, given back
1777 /// deliberately. See [`ValueView`] for what it promises and when it
1778 /// breaks.
1779 ///
1780 /// A `Vector` borrows its elements for as long as the view is held, for
1781 /// the reason [`Value::vector_elements`] gives.
1782 pub fn view(&self) -> ValueView<'_> {
1783 match self.erased() {
1784 Value(Repr::Unit) => ValueView::Unit,
1785 Value(Repr::Bool(b)) => ValueView::Bool(*b),
1786 Value(Repr::Int(n)) => ValueView::Int(*n),
1787 Value(Repr::Float(x)) => ValueView::Float(*x),
1788 Value(Repr::Duration(ns)) => ValueView::Duration(*ns),
1789 Value(Repr::Str(text)) => ValueView::Str(text),
1790 Value(Repr::Array(items)) => ValueView::Array(items),
1791 Value(Repr::Vector(storage)) => ValueView::Vector(Elements(storage.elements.borrow())),
1792 Value(Repr::Map(entries)) => ValueView::Map(Entries(entries)),
1793 Value(Repr::Set(members)) => ValueView::Set(Members(members)),
1794 Value(Repr::Struct(value)) => ValueView::Struct(StructView(value)),
1795 Value(Repr::Enum(value)) => ValueView::Enum(EnumView(value)),
1796 Value(Repr::Closure(closure)) => ValueView::Closure(ClosureView(closure)),
1797 Value(Repr::HostModule(name)) => ValueView::HostModule(name),
1798 Value(Repr::HostFn(host)) => ValueView::HostFn {
1799 module: &host.module,
1800 op: &host.op,
1801 },
1802 Value(Repr::Resource(handle)) => ValueView::Resource(handle),
1803 Value(Repr::Type(name)) => ValueView::Type(name),
1804 Value(Repr::Range {
1805 start,
1806 end,
1807 inclusive_end,
1808 }) => ValueView::Range(RangeBounds::of(*start, *end, *inclusive_end)),
1809 Value(Repr::Task(task)) => ValueView::Task(TaskView(task)),
1810 Value(Repr::TaskScope(scope)) => ValueView::TaskScope(TaskScopeView(scope)),
1811 Value(Repr::Shared(_)) => ValueView::Shared(SharedView(std::marker::PhantomData)),
1812 // `erased` looks through every wrapper, including a wrapper
1813 // holding a wrapper, so control never arrives here.
1814 Value(Repr::Dyn(_)) => unreachable!("`Value::erased` answers no `dyn` wrapper"),
1815 }
1816 }
1817}
1818
1819/// What kind of Cove value this is: the stable public classification, and the
1820/// exhaustive match a host is allowed to write.
1821///
1822/// # Why this exists
1823///
1824/// [`Value`]'s variants are sealed (ADR 0028 decision 6), which takes away a
1825/// real safety property: a host that matched every variant got a compile
1826/// error when a new one arrived. Issue #196 raises exactly that objection.
1827/// This is the answer, and it is a better answer than the thing it replaces,
1828/// because today one enum carries two unrelated kinds of change and a host
1829/// cannot tell them apart. Moving a struct from a `Box` to an `Rc` (issue
1830/// #104) and "Cove has a new kind of value" arrive at a host as the same
1831/// compile error.
1832///
1833/// After this they are different events:
1834///
1835/// - a **representation** change is invisible — nothing here names an `Rc`, a
1836/// `Box`, a slot, a heap object or a tag, so how the runtime holds a value
1837/// may move without a host noticing;
1838/// - a **language** change is a compile error at every `match` — a new kind
1839/// of Cove value is a new variant here, and that is the right way round.
1840///
1841/// # It is exhaustive on purpose
1842///
1843/// This is deliberately **not** `#[non_exhaustive]`, and that is the whole
1844/// point. A `#[non_exhaustive]` view would give back the syntax of an
1845/// exhaustive match and none of its value: every host would carry a `_` arm,
1846/// and the compile error that a new kind of value *should* cause would never
1847/// happen anywhere.
1848///
1849/// The cost is real and is accepted: this is a second place every new kind of
1850/// Cove value must be added, and adding one is a breaking change for every
1851/// embedder. Forgetting is a compile error inside this crate, at
1852/// [`Value::view`], which is the good case.
1853///
1854/// # What it promises
1855///
1856/// Each payload borrows from the value or copies out of it, and building one
1857/// allocates nothing — so every part named here must still be *stored* as the
1858/// thing it answers with. That is a promise about a materialized boundary
1859/// value and not about how the linear-memory backend holds one: ADR 0028
1860/// separates the two, and the parts that will actually move — slots, heap
1861/// objects, dynamic values — are not [`Value`] and never reach here.
1862///
1863/// A part whose storage sits behind a cell is answered as an opaque guard
1864/// rather than a borrow: [`Elements`] is the one that exists, and it is what
1865/// lets `Vector` be viewed at all.
1866///
1867/// There is no `Dyn` variant, because [`Value::view`] looks through the
1868/// wrapper like every reader beside it. [`Value::dyn_trait`] answers the
1869/// trait name for a host that wants it.
1870#[derive(Clone, Debug)]
1871pub enum ValueView<'a> {
1872 /// `()`
1873 Unit,
1874 Bool(bool),
1875 Int(i64),
1876 Float(f64),
1877 /// A duration in nanoseconds, signed, exactly as
1878 /// [`Value::as_duration_nanos`] answers it.
1879 Duration(i64),
1880 Str(&'a str),
1881 /// A fixed-length immutable sequence.
1882 Array(&'a [Value]),
1883 /// A growable sequence, borrowed for as long as the view is held.
1884 Vector(Elements<'a>),
1885 Map(Entries<'a>),
1886 Set(Members<'a>),
1887 Struct(StructView<'a>),
1888 /// An enum value, including `Option` and `Result`.
1889 Enum(EnumView<'a>),
1890 /// A callback. A host calls one back through
1891 /// [`Reentry`](crate::host::Reentry) and never directly, since the body
1892 /// belongs to the backend that made it.
1893 Closure(ClosureView<'a>),
1894 /// A bound host module such as `console`.
1895 HostModule(&'a str),
1896 /// A bound host operation such as `console.println`.
1897 HostFn {
1898 /// The host module, such as `console`.
1899 module: &'a str,
1900 /// The operation's own name, such as `println`.
1901 op: &'a str,
1902 },
1903 /// A handle to a resource the host owns. ADR 0013 decides that the handle
1904 /// is a name and that every field of it is part of that name, which is
1905 /// why the whole of it is the answer.
1906 Resource(&'a ResourceHandle),
1907 /// A type used as a value, such as `Vector` in `Vector.of(1, 2)`.
1908 Type(&'a str),
1909 /// An integer range, normalised to half-open bounds.
1910 Range(RangeBounds),
1911 /// A handle to a spawned task. Its value is reachable only through
1912 /// `await` or through the scope settling it.
1913 Task(TaskView<'a>),
1914 /// The scope `scope tasks { ... }` binds.
1915 TaskScope(TaskScopeView<'a>),
1916 /// Mutable state more than one task may reach. Its contents are reachable
1917 /// only through `lock`, so there is nothing here to read.
1918 Shared(SharedView<'a>),
1919}
1920
1921/// A `Vector`'s elements, borrowed.
1922///
1923/// Reads as `[Value]`, so a host reads a vector the way it reads an array:
1924/// `elements.len()`, `elements[0]`, `for value in &elements`.
1925///
1926/// It is a guard and not a slice because the elements sit behind a cell — the
1927/// language lets an alias write them — and a guard is ADR 0028's general
1928/// answer for a part whose storage will not sit still. Holding one borrows
1929/// the vector, so drop it before letting Cove code write the same vector.
1930pub struct Elements<'a>(std::cell::Ref<'a, Vec<Value>>);
1931
1932impl Clone for Elements<'_> {
1933 /// Another guard onto the same elements, which is a second shared borrow
1934 /// and never a copy of them.
1935 fn clone(&self) -> Self {
1936 Elements(std::cell::Ref::clone(&self.0))
1937 }
1938}
1939
1940impl std::ops::Deref for Elements<'_> {
1941 type Target = [Value];
1942
1943 fn deref(&self) -> &[Value] {
1944 &self.0
1945 }
1946}
1947
1948impl fmt::Debug for Elements<'_> {
1949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1950 fmt::Debug::fmt(&*self.0, f)
1951 }
1952}
1953
1954impl<'a, 'b> IntoIterator for &'b Elements<'a> {
1955 type Item = &'b Value;
1956 type IntoIter = std::slice::Iter<'b, Value>;
1957
1958 fn into_iter(self) -> Self::IntoIter {
1959 self.iter()
1960 }
1961}
1962
1963/// A `Map`'s entries, in ascending key order.
1964///
1965/// Opaque so that the key-ordered storage behind it stays the runtime's
1966/// business; what it promises is the order, which is the order a Cove program
1967/// iterating the same map sees.
1968#[derive(Clone, Copy, Debug)]
1969pub struct Entries<'a>(&'a BTreeMap<MapKey, Value>);
1970
1971impl<'a> Entries<'a> {
1972 /// How many entries the map holds.
1973 pub fn len(self) -> usize {
1974 self.0.len()
1975 }
1976
1977 /// Whether the map holds none.
1978 pub fn is_empty(self) -> bool {
1979 self.0.is_empty()
1980 }
1981
1982 /// What `key` maps to, if anything.
1983 pub fn get(self, key: &MapKey) -> Option<&'a Value> {
1984 self.0.get(key)
1985 }
1986
1987 /// The entries, in ascending key order.
1988 pub fn iter(self) -> impl Iterator<Item = (&'a MapKey, &'a Value)> {
1989 self.0.iter()
1990 }
1991}
1992
1993impl<'a> IntoIterator for Entries<'a> {
1994 type Item = (&'a MapKey, &'a Value);
1995 type IntoIter = std::collections::btree_map::Iter<'a, MapKey, Value>;
1996
1997 fn into_iter(self) -> Self::IntoIter {
1998 self.0.iter()
1999 }
2000}
2001
2002/// A `Set`'s elements, in ascending key order.
2003///
2004/// [`MapKey`]s and not [`Value`]s, for the reason [`Value::set`] gives on the
2005/// way in: the restriction is real, and showing it is better than pretending
2006/// a set holds anything.
2007#[derive(Clone, Copy, Debug)]
2008pub struct Members<'a>(&'a BTreeSet<MapKey>);
2009
2010impl<'a> Members<'a> {
2011 /// How many elements the set holds.
2012 pub fn len(self) -> usize {
2013 self.0.len()
2014 }
2015
2016 /// Whether the set holds none.
2017 pub fn is_empty(self) -> bool {
2018 self.0.is_empty()
2019 }
2020
2021 /// Whether `member` is one of them.
2022 pub fn contains(self, member: &MapKey) -> bool {
2023 self.0.contains(member)
2024 }
2025
2026 /// The elements, in ascending key order.
2027 pub fn iter(self) -> impl Iterator<Item = &'a MapKey> {
2028 self.0.iter()
2029 }
2030}
2031
2032impl<'a> IntoIterator for Members<'a> {
2033 type Item = &'a MapKey;
2034 type IntoIter = std::collections::btree_set::Iter<'a, MapKey>;
2035
2036 fn into_iter(self) -> Self::IntoIter {
2037 self.0.iter()
2038 }
2039}
2040
2041/// A struct value's name and fields.
2042#[derive(Clone, Copy, Debug)]
2043pub struct StructView<'a>(&'a StructValue);
2044
2045impl<'a> StructView<'a> {
2046 /// The qualified name of the declared type, such as
2047 /// `rules.policy.PullRequest` — the name [`Value::structure`] takes.
2048 pub fn type_name(self) -> &'a str {
2049 &self.0.type_name
2050 }
2051
2052 /// The field `name`, or `None` when the struct declares no such field.
2053 pub fn field(self, name: &str) -> Option<&'a Value> {
2054 self.0.get(name)
2055 }
2056
2057 /// The fields, in declaration order.
2058 pub fn fields(self) -> impl Iterator<Item = (&'a str, &'a Value)> {
2059 self.0.fields.iter().map(|(name, value)| (&**name, value))
2060 }
2061
2062 /// How many fields the struct declares.
2063 pub fn len(self) -> usize {
2064 self.0.fields.len()
2065 }
2066
2067 /// Whether the struct declares no fields at all.
2068 pub fn is_empty(self) -> bool {
2069 self.0.fields.is_empty()
2070 }
2071
2072 /// Whether the declaration said `export opaque struct` (ADR 0014), which
2073 /// governs how the value *renders* and nothing else.
2074 ///
2075 /// The fields are readable here whatever this answers, for the reason
2076 /// [`Value::fields`] gives: a host holding the value has already been
2077 /// handed it.
2078 pub fn is_opaque(self) -> bool {
2079 self.0.opaque
2080 }
2081}
2082
2083/// An enum value's name, case, and payload.
2084#[derive(Clone, Copy, Debug)]
2085pub struct EnumView<'a>(&'a EnumValue);
2086
2087impl<'a> EnumView<'a> {
2088 /// The qualified name of the declared type, or `Option` / `Result` for
2089 /// the builtins.
2090 pub fn type_name(self) -> &'a str {
2091 &self.0.type_name
2092 }
2093
2094 /// The case, unqualified: `Some`, `Err`, `Require`.
2095 pub fn case(self) -> &'a str {
2096 &self.0.case
2097 }
2098
2099 /// What the case carries, in the order the case declares it, and an empty
2100 /// slice for a case that carries nothing.
2101 pub fn payload(self) -> &'a [Value] {
2102 self.0.payload.as_slice()
2103 }
2104}
2105
2106/// What a host may read of a callback.
2107///
2108/// The body is not here and cannot be: the interpreter walks a tree and the
2109/// VM runs a lowered function, and calling one is
2110/// [`Reentry`](crate::host::Reentry)'s job because only the backend that made
2111/// a closure can run it.
2112#[derive(Clone, Copy, Debug)]
2113pub struct ClosureView<'a>(&'a Closure);
2114
2115impl ClosureView<'_> {
2116 /// How many parameters the closure declares — parameters, not arguments a
2117 /// call must supply, so a defaulted or a variadic one counts like any
2118 /// other.
2119 pub fn arity(self) -> usize {
2120 self.0.arity
2121 }
2122
2123 /// Whether it was declared `async`.
2124 pub fn is_async(self) -> bool {
2125 self.0.is_async
2126 }
2127}
2128
2129/// What a host may read of a task handle.
2130#[derive(Clone, Copy, Debug)]
2131pub struct TaskView<'a>(&'a Task);
2132
2133impl<'a> TaskView<'a> {
2134 /// Trace identity, unique across the run.
2135 pub fn id(self) -> u64 {
2136 self.0.id
2137 }
2138
2139 /// The name of the scope that owns the task.
2140 pub fn scope(self) -> &'a str {
2141 &self.0.scope
2142 }
2143
2144 /// Position in spawn order within that scope, counting from one.
2145 pub fn position(self) -> usize {
2146 self.0.position
2147 }
2148}
2149
2150/// What a host may read of a task scope.
2151#[derive(Clone, Copy, Debug)]
2152pub struct TaskScopeView<'a>(&'a TaskScope);
2153
2154impl<'a> TaskScopeView<'a> {
2155 /// The name the scope is bound to.
2156 pub fn name(self) -> &'a str {
2157 &self.0.name
2158 }
2159}
2160
2161/// A `Shared` cell, which has nothing readable on it.
2162///
2163/// Its contents are reachable only through `lock`, and showing them here
2164/// would be a read outside one — the single thing the type exists to prevent.
2165/// The variant is in [`ValueView`] so that a host can *tell* a `Shared` from
2166/// everything else, which is all a host can do with one.
2167///
2168/// It carries the borrow and no accessor, so the cell it was made from is not
2169/// reachable through it — deliberately, since reaching it is what `lock` is
2170/// for.
2171#[derive(Clone, Copy, Debug)]
2172pub struct SharedView<'a>(std::marker::PhantomData<&'a SharedCell>);
2173
2174/// How a value appears inside string interpolation and `console.println`.
2175impl fmt::Display for Value {
2176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2177 match self {
2178 Value(Repr::Unit) => f.write_str("()"),
2179 Value(Repr::Bool(b)) => write!(f, "{b}"),
2180 Value(Repr::Int(i)) => write!(f, "{i}"),
2181 Value(Repr::Float(x)) => write_float(f, *x),
2182 Value(Repr::Duration(ns)) => write_duration(f, *ns),
2183 Value(Repr::Str(s)) => f.write_str(s),
2184 Value(Repr::Array(items)) => {
2185 f.write_str("[")?;
2186 for (i, item) in items.iter().enumerate() {
2187 if i > 0 {
2188 f.write_str(", ")?;
2189 }
2190 write!(f, "{item}")?;
2191 }
2192 f.write_str("]")
2193 }
2194 Value(Repr::Vector(storage)) => {
2195 f.write_str("[")?;
2196 for (i, item) in storage.elements.borrow().iter().enumerate() {
2197 if i > 0 {
2198 f.write_str(", ")?;
2199 }
2200 write!(f, "{item}")?;
2201 }
2202 f.write_str("]")
2203 }
2204 Value(Repr::Map(entries)) => {
2205 f.write_str("{")?;
2206 for (i, (k, v)) in entries.iter().enumerate() {
2207 if i > 0 {
2208 f.write_str(", ")?;
2209 }
2210 write!(f, "{k}: {v}")?;
2211 }
2212 f.write_str("}")
2213 }
2214 Value(Repr::Set(items)) => {
2215 f.write_str("{")?;
2216 for (i, item) in items.iter().enumerate() {
2217 if i > 0 {
2218 f.write_str(", ")?;
2219 }
2220 write!(f, "{item}")?;
2221 }
2222 f.write_str("}")
2223 }
2224 Value(Repr::Struct(s)) => {
2225 if &*s.type_name == ERROR.name {
2226 return match s.get(MESSAGE_FIELD.name) {
2227 Some(Value(Repr::Str(m))) => f.write_str(m),
2228 _ => f.write_str(ERROR.name),
2229 };
2230 }
2231 let short = s.type_name.rsplit('.').next().unwrap_or(&s.type_name);
2232 // An opaque type renders as its name and nothing else. Its
2233 // fields are the module's own business, and a rendering is
2234 // read by whoever the string reaches, so showing them here
2235 // would publish through `println` what the checker refuses
2236 // to publish through a field access.
2237 if s.opaque {
2238 return f.write_str(short);
2239 }
2240 write!(f, "{short}(")?;
2241 for (i, (name, value)) in s.fields.iter().enumerate() {
2242 if i > 0 {
2243 f.write_str(", ")?;
2244 }
2245 write!(f, "{name}: {value}")?;
2246 }
2247 f.write_str(")")
2248 }
2249 Value(Repr::Enum(e)) => {
2250 f.write_str(&e.case)?;
2251 if !e.payload.is_empty() {
2252 f.write_str("(")?;
2253 for (i, value) in e.payload.iter().enumerate() {
2254 if i > 0 {
2255 f.write_str(", ")?;
2256 }
2257 write!(f, "{value}")?;
2258 }
2259 f.write_str(")")?;
2260 }
2261 Ok(())
2262 }
2263 // A trait object shows the value it holds: the wrapper is a
2264 // representation, not something the program put there.
2265 Value(Repr::Dyn(d)) => write!(f, "{}", d.value),
2266 Value(Repr::Closure(_)) => f.write_str("<fn>"),
2267 Value(Repr::HostModule(m)) => write!(f, "<host module {m}>"),
2268 // A handle prints as what it names, identity included: two
2269 // connections are told apart by the number the host issued and
2270 // by nothing else.
2271 Value(Repr::Resource(handle)) => write!(f, "<{}>", handle),
2272 Value(Repr::HostFn(host)) => write!(f, "<host fn {}.{}>", host.module, host.op),
2273 Value(Repr::Type(t)) => write!(f, "<type {t}>"),
2274 Value(Repr::Range {
2275 start,
2276 end,
2277 inclusive_end,
2278 }) => {
2279 let operator = if *inclusive_end { ".." } else { "..<" };
2280 write!(f, "{start}{operator}{end}")
2281 }
2282 Value(Repr::TaskScope(scope)) => write!(f, "<task scope {}>", scope.name),
2283 // A task prints as a handle, never as the value it will produce:
2284 // that value is observable only through `await` or scope exit.
2285 Value(Repr::Task(_)) => f.write_str("<task>"),
2286 // A `Shared` prints as the handle it is. Showing what it holds
2287 // would be a read outside a `lock`, which is the one thing the
2288 // type exists to prevent.
2289 Value(Repr::Shared(_)) => f.write_str("<shared>"),
2290 }
2291 }
2292}
2293
2294/// Renders a `Float` so that it is never mistaken for an `Int`.
2295///
2296/// Cove performs no implicit numeric conversions, so a float with no
2297/// fractional part still shows its point: `4.0`, not `4`. Negative zero keeps
2298/// its sign, and the non-finite values print as `NaN`, `inf`, and `-inf`.
2299fn write_float(f: &mut fmt::Formatter<'_>, x: f64) -> fmt::Result {
2300 if x.is_nan() {
2301 return f.write_str("NaN");
2302 }
2303 if x.is_infinite() {
2304 return f.write_str(if x.is_sign_negative() { "-inf" } else { "inf" });
2305 }
2306 if x.fract() == 0.0 {
2307 write!(f, "{x:.1}")
2308 } else {
2309 write!(f, "{x}")
2310 }
2311}
2312
2313/// Nanoseconds per duration unit, largest first, using the suffixes the lexer
2314/// accepts.
2315const DURATION_UNITS: [(i64, &str); 6] = [
2316 (3_600_000_000_000, "h"),
2317 (60_000_000_000, "m"),
2318 (1_000_000_000, "s"),
2319 (1_000_000, "ms"),
2320 (1_000, "us"),
2321 (1, "ns"),
2322];
2323
2324/// Renders a `Duration` in the largest unit that divides it exactly.
2325///
2326/// A duration no larger unit divides exactly stays in nanoseconds, and a
2327/// negative duration keeps its sign. Zero has no largest unit, so it prints as
2328/// `0ns`.
2329fn write_duration(f: &mut fmt::Formatter<'_>, ns: i64) -> fmt::Result {
2330 if ns == 0 {
2331 return f.write_str("0ns");
2332 }
2333 for (factor, suffix) in DURATION_UNITS {
2334 if ns % factor == 0 {
2335 return write!(f, "{}{suffix}", ns / factor);
2336 }
2337 }
2338 unreachable!("every duration is divisible by one nanosecond")
2339}
2340
2341#[cfg(test)]
2342mod tests {
2343 use super::*;
2344
2345 /// Inlining the common arities cost an `EnumValue` nothing at all.
2346 ///
2347 /// A `Payload` is three variants, one of them a whole [`Value`], and it
2348 /// is still twenty-four bytes — the width of the `Vec` it replaced —
2349 /// because `Value`'s discriminant lives in a `bool` niche with room to
2350 /// spare and `Payload`'s fits beside it. So `Some(x)` lost an allocation
2351 /// and gained no width, and `Marker::visit`'s
2352 /// `size_of::<EnumValue>()` charge means what it meant.
2353 ///
2354 /// Asserted rather than remembered because it is not obvious and because
2355 /// a future variant of either enum could take it away silently: a
2356 /// `Payload` wider than a `Vec` makes every enum value's box bigger, and
2357 /// this is the only place that would say so.
2358 #[test]
2359 fn a_payload_is_no_wider_than_the_vector_it_replaced() {
2360 assert_eq!(size_of::<Payload>(), size_of::<Vec<Value>>());
2361 assert_eq!(size_of::<Payload>(), 24);
2362 assert_eq!(size_of::<EnumValue>(), 56);
2363 }
2364
2365 fn shown(value: Value) -> String {
2366 value.to_string()
2367 }
2368
2369 #[test]
2370 fn a_float_is_never_shown_as_an_int() {
2371 assert_eq!(shown(Value(Repr::Float(4.0))), "4.0");
2372 assert_eq!(shown(Value(Repr::Float(-4.0))), "-4.0");
2373 assert_eq!(shown(Value(Repr::Float(1500.0))), "1500.0");
2374 assert_eq!(shown(Value(Repr::Float(1.5))), "1.5");
2375 assert_eq!(shown(Value(Repr::Float(0.25))), "0.25");
2376 assert_eq!(shown(Value(Repr::Float(-0.75))), "-0.75");
2377 assert_eq!(shown(Value(Repr::Float(0.02))), "0.02");
2378 }
2379
2380 #[test]
2381 fn float_edge_cases_are_explicit() {
2382 assert_eq!(shown(Value(Repr::Float(0.0))), "0.0");
2383 assert_eq!(shown(Value(Repr::Float(-0.0))), "-0.0");
2384 assert_eq!(shown(Value(Repr::Float(f64::INFINITY))), "inf");
2385 assert_eq!(shown(Value(Repr::Float(f64::NEG_INFINITY))), "-inf");
2386 assert_eq!(shown(Value(Repr::Float(f64::NAN))), "NaN");
2387 }
2388
2389 #[test]
2390 fn a_duration_uses_the_largest_unit_that_divides_it() {
2391 assert_eq!(shown(Value(Repr::Duration(0))), "0ns");
2392 assert_eq!(shown(Value(Repr::Duration(1))), "1ns");
2393 assert_eq!(shown(Value(Repr::Duration(1_000))), "1us");
2394 assert_eq!(shown(Value(Repr::Duration(1_000_000))), "1ms");
2395 assert_eq!(shown(Value(Repr::Duration(1_000_000_000))), "1s");
2396 assert_eq!(shown(Value(Repr::Duration(60_000_000_000))), "1m");
2397 assert_eq!(shown(Value(Repr::Duration(3_600_000_000_000))), "1h");
2398 assert_eq!(shown(Value(Repr::Duration(500_000_000))), "500ms");
2399 assert_eq!(shown(Value(Repr::Duration(1_500_000_000))), "1500ms");
2400 assert_eq!(shown(Value(Repr::Duration(90_000_000_000))), "90s");
2401 }
2402
2403 #[test]
2404 fn a_duration_no_larger_unit_divides_stays_in_nanoseconds() {
2405 assert_eq!(shown(Value(Repr::Duration(1_001))), "1001ns");
2406 assert_eq!(
2407 shown(Value(Repr::Duration(i64::MAX))),
2408 format!("{}ns", i64::MAX)
2409 );
2410 }
2411
2412 #[test]
2413 fn a_negative_duration_keeps_its_sign() {
2414 assert_eq!(shown(Value(Repr::Duration(-3_600_000_000_000))), "-1h");
2415 assert_eq!(shown(Value(Repr::Duration(-500_000_000))), "-500ms");
2416 assert_eq!(shown(Value(Repr::Duration(-1))), "-1ns");
2417 }
2418
2419 fn range(start: i64, end: i64, inclusive_end: bool) -> Value {
2420 Value(Repr::Range {
2421 start,
2422 end,
2423 inclusive_end,
2424 })
2425 }
2426
2427 #[test]
2428 fn a_range_shows_the_operator_it_was_written_with() {
2429 assert_eq!(shown(range(0, 3, false)), "0..<3");
2430 assert_eq!(shown(range(0, 3, true)), "0..3");
2431 assert_eq!(shown(range(-2, -1, false)), "-2..<-1");
2432 }
2433
2434 #[test]
2435 fn ranges_compare_by_value() {
2436 assert!(range(0, 3, false).eq_value(&range(0, 3, false)));
2437 assert!(!range(0, 3, false).eq_value(&range(0, 3, true)));
2438 assert!(!range(0, 3, false).eq_value(&range(1, 3, false)));
2439 assert!(!range(0, 3, false).eq_value(&Value(Repr::Int(0))));
2440 }
2441
2442 #[test]
2443 fn range_bounds_measure_and_test_membership() {
2444 let exclusive = RangeBounds::of(0, 3, false);
2445 assert_eq!(exclusive.len(), 3);
2446 assert!(!exclusive.is_empty());
2447 assert!(exclusive.contains(0));
2448 assert!(exclusive.contains(2));
2449 assert!(!exclusive.contains(3));
2450 assert!(!exclusive.contains(-1));
2451
2452 let inclusive = RangeBounds::of(0, 3, true);
2453 assert_eq!(inclusive.len(), 4);
2454 assert!(inclusive.contains(3));
2455 }
2456
2457 #[test]
2458 fn a_reversed_or_empty_range_is_empty() {
2459 for bounds in [
2460 RangeBounds::of(3, 0, false),
2461 RangeBounds::of(3, 0, true),
2462 RangeBounds::of(0, 0, false),
2463 ] {
2464 assert_eq!(bounds.len(), 0);
2465 assert!(bounds.is_empty());
2466 assert!(bounds.items().is_empty());
2467 assert!(!bounds.contains(0));
2468 }
2469 }
2470
2471 #[test]
2472 fn an_inclusive_range_that_ends_at_the_largest_int_does_not_overflow() {
2473 let bounds = RangeBounds::of(i64::MAX, i64::MAX, true);
2474 assert_eq!(bounds.len(), 1);
2475 assert!(bounds.contains(i64::MAX));
2476 }
2477
2478 fn payload_free_case(type_name: &str, case: &str) -> Value {
2479 Value(Repr::Enum(Box::new(EnumValue {
2480 type_name: type_name.into(),
2481 case: case.into(),
2482 payload: Payload::Empty,
2483 })))
2484 }
2485
2486 fn point(x: i64, y: i64) -> Value {
2487 Value(Repr::Struct(Rc::new(StructValue {
2488 type_name: "test.Point".into(),
2489 fields: vec![
2490 ("x".into(), Value(Repr::Int(x))),
2491 ("y".into(), Value(Repr::Int(y))),
2492 ],
2493 opaque: false,
2494 })))
2495 }
2496
2497 #[test]
2498 fn map_keys_accept_the_primitive_shapes() {
2499 assert_eq!(MapKey::from_value(&Value(Repr::Unit)), Ok(MapKey::Unit));
2500 assert_eq!(
2501 MapKey::from_value(&Value(Repr::Bool(true))),
2502 Ok(MapKey::Bool(true))
2503 );
2504 assert_eq!(MapKey::from_value(&Value(Repr::Int(7))), Ok(MapKey::Int(7)));
2505 assert_eq!(
2506 MapKey::from_value(&Value(Repr::Duration(500))),
2507 Ok(MapKey::Duration(500))
2508 );
2509 assert_eq!(
2510 MapKey::from_value(&Value(Repr::Str("a".into()))),
2511 Ok(MapKey::Str("a".to_string()))
2512 );
2513 assert_eq!(
2514 MapKey::from_value(&payload_free_case("Color", "Red")),
2515 Ok(MapKey::EnumCase(
2516 "Color".to_string(),
2517 "Red".to_string(),
2518 Vec::new()
2519 ))
2520 );
2521 }
2522
2523 /// A `Range` is immutable with a stable `eq_value`, so it qualifies as a
2524 /// map key or set element under the same rule as every other value here.
2525 #[test]
2526 fn a_range_is_a_valid_map_key() {
2527 assert_eq!(
2528 MapKey::from_value(&Value(Repr::Range {
2529 start: 0,
2530 end: 3,
2531 inclusive_end: false,
2532 })),
2533 Ok(MapKey::Range {
2534 start: 0,
2535 end: 3,
2536 inclusive_end: false,
2537 })
2538 );
2539 // `0..<3` and `0..2` are distinct keys, exactly as they are distinct
2540 // values: `eq_value` compares the bounds a range was written with.
2541 assert_ne!(
2542 MapKey::from_value(&Value(Repr::Range {
2543 start: 0,
2544 end: 3,
2545 inclusive_end: false,
2546 })),
2547 MapKey::from_value(&Value(Repr::Range {
2548 start: 0,
2549 end: 2,
2550 inclusive_end: true,
2551 }))
2552 );
2553 }
2554
2555 #[test]
2556 fn a_struct_built_only_from_admissible_fields_is_a_valid_key() {
2557 let key = MapKey::from_value(&point(1, 2)).expect("a struct of Ints is a valid key");
2558 assert_eq!(
2559 key,
2560 MapKey::Struct(
2561 "test.Point".to_string(),
2562 vec![
2563 ("x".to_string(), MapKey::Int(1)),
2564 ("y".to_string(), MapKey::Int(2)),
2565 ],
2566 false
2567 )
2568 );
2569 }
2570
2571 #[test]
2572 fn a_struct_nested_inside_a_struct_is_a_valid_key_when_every_field_is() {
2573 let line = Value(Repr::Struct(Rc::new(StructValue {
2574 type_name: "test.Line".into(),
2575 fields: vec![("from".into(), point(0, 0)), ("to".into(), point(1, 1))],
2576 opaque: false,
2577 })));
2578 let key = MapKey::from_value(&line).expect("nested structs of Ints are a valid key");
2579 assert_eq!(
2580 key,
2581 MapKey::Struct(
2582 "test.Line".to_string(),
2583 vec![
2584 (
2585 "from".to_string(),
2586 MapKey::Struct(
2587 "test.Point".to_string(),
2588 vec![
2589 ("x".to_string(), MapKey::Int(0)),
2590 ("y".to_string(), MapKey::Int(0)),
2591 ],
2592 false
2593 )
2594 ),
2595 (
2596 "to".to_string(),
2597 MapKey::Struct(
2598 "test.Point".to_string(),
2599 vec![
2600 ("x".to_string(), MapKey::Int(1)),
2601 ("y".to_string(), MapKey::Int(1)),
2602 ],
2603 false
2604 )
2605 ),
2606 ],
2607 false
2608 )
2609 );
2610 }
2611
2612 #[test]
2613 fn an_enum_case_with_an_admissible_payload_is_a_valid_key() {
2614 let value = Value(Repr::Enum(Box::new(EnumValue {
2615 type_name: "test.Colour".into(),
2616 case: "Named".into(),
2617 payload: Payload::One(Value(Repr::Str("teal".into()))),
2618 })));
2619 assert_eq!(
2620 MapKey::from_value(&value),
2621 Ok(MapKey::EnumCase(
2622 "test.Colour".to_string(),
2623 "Named".to_string(),
2624 vec![MapKey::Str("teal".to_string())]
2625 ))
2626 );
2627 }
2628
2629 #[test]
2630 fn an_array_built_only_from_admissible_elements_is_a_valid_key() {
2631 let value = Value(Repr::Array(
2632 vec![Value(Repr::Int(1)), Value(Repr::Int(2))].into(),
2633 ));
2634 assert_eq!(
2635 MapKey::from_value(&value),
2636 Ok(MapKey::Array(vec![MapKey::Int(1), MapKey::Int(2)]))
2637 );
2638 }
2639
2640 #[test]
2641 fn map_keys_reject_a_float_for_a_reason_distinct_from_mutability() {
2642 let invalid = MapKey::from_value(&Value(Repr::Float(1.0))).unwrap_err();
2643 assert_eq!(invalid.type_name, "Float");
2644 assert!(invalid.path.is_empty());
2645 assert!(
2646 invalid.rule().contains("NaN"),
2647 "a Float's rejection must cite the broken order, not mutability: {}",
2648 invalid.rule()
2649 );
2650 }
2651
2652 #[test]
2653 fn map_keys_reject_a_vector_naming_it_directly_at_the_root() {
2654 let invalid =
2655 MapKey::from_value(&Value(Repr::Vector(VectorStorage::new(Vec::new())))).unwrap_err();
2656 assert_eq!(invalid.type_name, "Vector");
2657 assert!(invalid.path.is_empty());
2658 assert!(
2659 invalid.rule().contains("Mutable handles"),
2660 "{}",
2661 invalid.rule()
2662 );
2663 }
2664
2665 #[test]
2666 fn a_struct_containing_a_vector_is_rejected_naming_the_nested_field() {
2667 let value = Value(Repr::Struct(Rc::new(StructValue {
2668 type_name: "test.Point".into(),
2669 fields: vec![(
2670 "tags".into(),
2671 Value(Repr::Vector(VectorStorage::new(Vec::new()))),
2672 )],
2673 opaque: false,
2674 })));
2675 let invalid = MapKey::from_value(&value).unwrap_err();
2676 assert_eq!(invalid.type_name, "Vector");
2677 assert_eq!(invalid.path, "Point.tags");
2678 }
2679
2680 #[test]
2681 fn a_map_key_round_trips_through_to_value() {
2682 for key in [
2683 MapKey::Unit,
2684 MapKey::Bool(false),
2685 MapKey::Int(42),
2686 MapKey::Duration(500),
2687 MapKey::Str("hi".to_string()),
2688 MapKey::EnumCase("Color".to_string(), "Red".to_string(), Vec::new()),
2689 MapKey::Array(vec![MapKey::Int(1), MapKey::Int(2)]),
2690 MapKey::Range {
2691 start: 0,
2692 end: 3,
2693 inclusive_end: false,
2694 },
2695 MapKey::Struct(
2696 "test.Point".to_string(),
2697 vec![
2698 ("x".to_string(), MapKey::Int(1)),
2699 ("y".to_string(), MapKey::Int(2)),
2700 ],
2701 false,
2702 ),
2703 ] {
2704 let value = key.to_value();
2705 assert_eq!(MapKey::from_value(&value), Ok(key));
2706 }
2707 }
2708
2709 #[test]
2710 fn a_set_is_a_valid_key_because_its_elements_are_already_map_keys() {
2711 let inner = Value(Repr::Set(Rc::new(BTreeSet::from([
2712 MapKey::Int(1),
2713 MapKey::Int(2),
2714 ]))));
2715 assert_eq!(
2716 MapKey::from_value(&inner),
2717 Ok(MapKey::Set(BTreeSet::from([
2718 MapKey::Int(1),
2719 MapKey::Int(2)
2720 ])))
2721 );
2722 }
2723
2724 #[test]
2725 fn a_map_is_a_valid_key_when_every_value_is_admissible() {
2726 let inner = Value(Repr::Map(Rc::new(BTreeMap::from([(
2727 MapKey::Str("a".to_string()),
2728 Value(Repr::Int(1)),
2729 )]))));
2730 assert_eq!(
2731 MapKey::from_value(&inner),
2732 Ok(MapKey::Map(BTreeMap::from([(
2733 MapKey::Str("a".to_string()),
2734 MapKey::Int(1)
2735 )])))
2736 );
2737 }
2738
2739 #[test]
2740 fn a_map_containing_an_inadmissible_value_is_rejected_naming_the_entry() {
2741 let inner = Value(Repr::Map(Rc::new(BTreeMap::from([(
2742 MapKey::Str("a".to_string()),
2743 Value(Repr::Vector(VectorStorage::new(Vec::new()))),
2744 )]))));
2745 let invalid = MapKey::from_value(&inner).unwrap_err();
2746 assert_eq!(invalid.type_name, "Vector");
2747 assert_eq!(invalid.path, "[a]");
2748 }
2749
2750 fn map_of(pairs: Vec<(MapKey, Value)>) -> Value {
2751 Value(Repr::Map(Rc::new(pairs.into_iter().collect())))
2752 }
2753
2754 fn set_of(keys: Vec<MapKey>) -> Value {
2755 Value(Repr::Set(Rc::new(keys.into_iter().collect())))
2756 }
2757
2758 #[test]
2759 fn maps_compare_structurally() {
2760 let a = map_of(vec![(MapKey::Str("x".to_string()), Value(Repr::Int(1)))]);
2761 let b = map_of(vec![(MapKey::Str("x".to_string()), Value(Repr::Int(1)))]);
2762 let c = map_of(vec![(MapKey::Str("x".to_string()), Value(Repr::Int(2)))]);
2763 assert!(a.eq_value(&b));
2764 assert!(!a.eq_value(&c));
2765 }
2766
2767 #[test]
2768 fn sets_compare_structurally() {
2769 let a = set_of(vec![MapKey::Int(1), MapKey::Int(2)]);
2770 let b = set_of(vec![MapKey::Int(2), MapKey::Int(1)]);
2771 let c = set_of(vec![MapKey::Int(1)]);
2772 assert!(a.eq_value(&b));
2773 assert!(!a.eq_value(&c));
2774 }
2775
2776 /// `==` means value equality regardless of mutability, so two separately
2777 /// built `Vector`s with the same elements are equal; a vector with
2778 /// different elements, or a different length, is not. Storage identity
2779 /// is the separate question `is` answers, not `eq_value`.
2780 #[test]
2781 fn vectors_compare_structurally() {
2782 let a = Value(Repr::Vector(VectorStorage::new(vec![
2783 Value(Repr::Int(1)),
2784 Value(Repr::Int(2)),
2785 ])));
2786 let b = Value(Repr::Vector(VectorStorage::new(vec![
2787 Value(Repr::Int(1)),
2788 Value(Repr::Int(2)),
2789 ])));
2790 let c = Value(Repr::Vector(VectorStorage::new(vec![
2791 Value(Repr::Int(1)),
2792 Value(Repr::Int(3)),
2793 ])));
2794 let d = Value(Repr::Vector(VectorStorage::new(vec![Value(Repr::Int(1))])));
2795 assert!(a.eq_value(&b));
2796 assert!(!a.eq_value(&c));
2797 assert!(!a.eq_value(&d));
2798 }
2799
2800 /// A vector equals itself under `==` too, even though it is a mutable
2801 /// handle: `==` never asks the identity question.
2802 #[test]
2803 fn a_vector_equals_itself_structurally() {
2804 let a = Value(Repr::Vector(VectorStorage::new(vec![Value(Repr::Int(1))])));
2805 assert!(a.eq_value(&a.clone()));
2806 }
2807
2808 #[test]
2809 fn a_map_shows_entries_in_ascending_key_order() {
2810 let value = map_of(vec![
2811 (MapKey::Int(2), Value(Repr::Str("b".into()))),
2812 (MapKey::Int(1), Value(Repr::Str("a".into()))),
2813 ]);
2814 assert_eq!(shown(value), "{1: a, 2: b}");
2815 }
2816
2817 #[test]
2818 fn a_set_shows_elements_in_ascending_order() {
2819 let value = set_of(vec![MapKey::Int(3), MapKey::Int(1), MapKey::Int(2)]);
2820 assert_eq!(shown(value), "{1, 2, 3}");
2821 }
2822
2823 /// Every shape a constructor builds, read back through a reader, with no
2824 /// variant named on either side.
2825 ///
2826 /// This is the round trip issue #186 asked for: the constructors were the
2827 /// only half that existed, so a host could build a boundary value without
2828 /// naming `Rc<StructValue>` and could not read one back the same way.
2829 #[test]
2830 fn every_shape_a_constructor_builds_reads_back_through_a_reader() {
2831 let structure = Value::structure(
2832 "rules.policy.Decision",
2833 [
2834 ("policy", Value(Repr::Int(1))),
2835 ("findings", Value::array([])),
2836 ],
2837 );
2838 assert_eq!(structure.declared_type(), Some("rules.policy.Decision"));
2839 assert_eq!(structure.field("policy").and_then(Value::as_int), Some(1));
2840 assert!(structure.field("absent").is_none());
2841 assert_eq!(
2842 structure
2843 .fields()
2844 .expect("a struct has fields")
2845 .map(|(name, _)| name)
2846 .collect::<Vec<_>>(),
2847 ["policy", "findings"],
2848 "declaration order, which is the order the constructor was handed"
2849 );
2850
2851 let enumeration = Value::enumeration(
2852 "rules.policy.ReviewPolicy",
2853 "Require",
2854 [Value(Repr::Int(2)), Value(Repr::Str("large change".into()))],
2855 );
2856 assert_eq!(
2857 enumeration.declared_type(),
2858 Some("rules.policy.ReviewPolicy")
2859 );
2860 assert_eq!(enumeration.case(), Some("Require"));
2861 assert_eq!(enumeration.payload().map(<[Value]>::len), Some(2));
2862
2863 let array = Value::array([Value(Repr::Int(1)), Value(Repr::Int(2))]);
2864 assert_eq!(
2865 array.items().map(|items| items.len()),
2866 Some(2),
2867 "an `Array` reads as the slice it is"
2868 );
2869
2870 let set = Value::set([MapKey::Int(2), MapKey::Int(1), MapKey::Int(2)]);
2871 assert_eq!(
2872 set.elements()
2873 .expect("a set has elements")
2874 .collect::<Vec<_>>(),
2875 [&MapKey::Int(1), &MapKey::Int(2)],
2876 "ascending key order, and a duplicate collapsed"
2877 );
2878
2879 let map = Value::map([
2880 (MapKey::Int(2), Value(Repr::Str("b".into()))),
2881 (MapKey::Int(1), Value(Repr::Str("a".into()))),
2882 ]);
2883 assert_eq!(
2884 map.entries()
2885 .expect("a map has entries")
2886 .map(|(key, value)| (key.clone(), value.to_string()))
2887 .collect::<Vec<_>>(),
2888 [
2889 (MapKey::Int(1), "a".to_string()),
2890 (MapKey::Int(2), "b".to_string()),
2891 ],
2892 "ascending key order, which is what a Cove program iterating sees"
2893 );
2894
2895 assert_eq!(
2896 Value::ok(Value(Repr::Int(1))).payload().map(<[Value]>::len),
2897 Some(1),
2898 "a builtin enum reads through the general reader as well as the four"
2899 );
2900 assert_eq!(
2901 Value::none().payload().map(<[Value]>::len),
2902 Some(0),
2903 "a case that carries nothing reads as an empty slice"
2904 );
2905 assert_eq!(
2906 Value::error("broken")
2907 .error_message()
2908 .and_then(Value::as_str),
2909 Some("broken")
2910 );
2911 }
2912
2913 /// Every scalar reads back as the Rust value it was built from.
2914 #[test]
2915 fn a_scalar_reads_back_as_itself() {
2916 assert_eq!(Value(Repr::Bool(true)).as_bool(), Some(true));
2917 assert_eq!(Value(Repr::Int(-7)).as_int(), Some(-7));
2918 assert_eq!(Value(Repr::Float(1.5)).as_float(), Some(1.5));
2919 assert_eq!(
2920 Value(Repr::Duration(-1_000)).as_duration_nanos(),
2921 Some(-1_000)
2922 );
2923 assert_eq!(Value(Repr::Str("hello".into())).as_str(), Some("hello"));
2924 assert!(Value(Repr::Unit).is_unit());
2925 assert_eq!(
2926 Value(Repr::Range {
2927 start: 1,
2928 end: 3,
2929 inclusive_end: true,
2930 })
2931 .range()
2932 .map(|bounds| (bounds.start, bounds.end)),
2933 Some((1, 4)),
2934 "`..` and `..<` normalise to one half-open pair"
2935 );
2936 }
2937
2938 /// A wrong shape answers `None` rather than panicking, which is the
2939 /// convention `ok_payload` and `StructValue::get` already set.
2940 #[test]
2941 fn a_reader_asked_of_the_wrong_shape_answers_none() {
2942 let value = Value(Repr::Int(1));
2943 assert_eq!(value.as_str(), None);
2944 assert_eq!(value.as_bool(), None);
2945 assert_eq!(value.declared_type(), None);
2946 assert!(value.field("policy").is_none());
2947 assert!(value.fields().is_none());
2948 assert_eq!(value.case(), None);
2949 assert!(value.payload().is_none());
2950 assert!(value.items().is_none());
2951 assert!(value.elements().is_none());
2952 assert!(value.entries().is_none());
2953 assert!(value.range().is_none());
2954 assert!(value.resource().is_none());
2955 assert_eq!(value.host_op(), None);
2956 assert_eq!(value.arity(), None);
2957 assert!(!value.is_unit());
2958
2959 // A `Vector` is not an `Array` and says so, because its elements are
2960 // behind a `RefCell` and nothing can hand out a slice of them.
2961 let vector = Value(Repr::Vector(VectorStorage::new(vec![Value(Repr::Int(1))])));
2962 assert!(vector.items().is_none());
2963 }
2964
2965 /// A reader looks through a `dyn Trait` wrapper, exactly as `Display` and
2966 /// `eq_value` do: nothing a program can ask tells a written conversion
2967 /// from a lambda's inferred one.
2968 #[test]
2969 fn a_reader_looks_through_a_trait_object() {
2970 let wrapped = Value(Repr::Dyn(Rc::new(DynValue {
2971 trait_name: "render.Display".into(),
2972 value: Value::structure("app.Point", [("x", Value(Repr::Int(1)))]),
2973 })));
2974 assert_eq!(wrapped.declared_type(), Some("app.Point"));
2975 assert_eq!(wrapped.field("x").and_then(Value::as_int), Some(1));
2976
2977 let wrapped_scalar = Value(Repr::Dyn(Rc::new(DynValue {
2978 trait_name: "render.Display".into(),
2979 value: Value(Repr::Str("shown".into())),
2980 })));
2981 assert_eq!(wrapped_scalar.as_str(), Some("shown"));
2982 }
2983
2984 /// The three representation changes that were embedder source breaks, read
2985 /// through the API that would have hidden each of them.
2986 ///
2987 /// Not a test of behaviour so much as of what the signatures admit: every
2988 /// assertion below names a shape the *language* has and no type the
2989 /// runtime chose to hold it in. Issue #104 moved a struct from a `Box` to
2990 /// an `Rc`, issue #109 moved a bound host operation's two names behind one
2991 /// pointer, and issue #183 replaced an enum payload's `Vec<Value>` with
2992 /// [`Payload`] — a host written against these lines would have compiled
2993 /// unchanged across all three, and the point of writing them down is that
2994 /// the next such change has to keep them compiling.
2995 #[test]
2996 fn a_reader_hides_each_representation_change_that_was_a_source_break() {
2997 // #104: the struct behind an `Rc`, where a host once wrote
2998 // `let Value::Struct(s) = value` and bound a `&Box<StructValue>`.
2999 let decision = Value::structure("app.Decision", [("reviewers", Value(Repr::Int(2)))]);
3000 assert_eq!(decision.field("reviewers").and_then(Value::as_int), Some(2));
3001
3002 // #183: the payload at each of the three arities `Payload` holds, read
3003 // as one slice whichever it is.
3004 for (payload, len) in [
3005 (Vec::new(), 0),
3006 (vec![Value(Repr::Int(1))], 1),
3007 (vec![Value(Repr::Int(1)), Value(Repr::Int(2))], 2),
3008 ] {
3009 let value = Value::enumeration("app.Verdict", "Case", payload);
3010 assert_eq!(value.case(), Some("Case"));
3011 assert_eq!(value.payload().map(<[Value]>::len), Some(len));
3012 }
3013
3014 // #109: the two names of a bound host operation, which were inline
3015 // fields of the variant until they cost every value in the program
3016 // sixteen bytes.
3017 let bound = Value(Repr::HostFn(Rc::new(HostFnValue {
3018 module: "console".into(),
3019 op: "println".into(),
3020 })));
3021 assert_eq!(bound.host_op(), Some(("console", "println")));
3022
3023 // #121, the fourth of the same kind: a closure's parameter list became
3024 // a count, and a host only ever wanted the count.
3025 let closure = Value(Repr::Closure(Rc::new(Closure {
3026 is_async: false,
3027 arity: 2,
3028 body: ClosureBody::Tree {
3029 params: Vec::new(),
3030 block: Arc::new(cove_syntax::ast::Block {
3031 statements: Vec::new(),
3032 tail: None,
3033 span: cove_diag::Span::new(cove_diag::FileId(0), 0, 0),
3034 }),
3035 decl: None,
3036 },
3037 module: "app".into(),
3038 captures: Vec::new(),
3039 })));
3040 assert_eq!(closure.arity(), Some(2));
3041 }
3042
3043 /// One value of every kind the language has, classified.
3044 ///
3045 /// The list is exhaustive on purpose: [`ValueView`] is not
3046 /// `#[non_exhaustive]`, so a new kind of Cove value is a compile error at
3047 /// `Value::view` first and here second, and this is where the count is
3048 /// checked. A `_` arm below would defeat both.
3049 #[test]
3050 fn a_view_names_every_kind_of_value() {
3051 let cell = SharedCell::new(crate::Transfer::Int(1));
3052 let scope = TaskScope::new("work".into());
3053 let task = Task::settled(Value::unit());
3054 let kinds = [
3055 Value::unit(),
3056 Value::bool(true),
3057 Value::int(1),
3058 Value::float(1.0),
3059 Value::duration(1),
3060 Value::string("hi"),
3061 Value::array([Value::int(1)]),
3062 Value(Repr::Vector(VectorStorage::new(vec![Value::int(1)]))),
3063 Value::map([(MapKey::Int(1), Value::int(2))]),
3064 Value::set([MapKey::Int(1)]),
3065 Value::structure("app.Point", [("x", Value::int(1))]),
3066 Value::some(Value::int(1)),
3067 Value(Repr::Closure(Rc::new(Closure {
3068 is_async: true,
3069 arity: 2,
3070 body: ClosureBody::Tree {
3071 params: Vec::new(),
3072 block: Arc::new(cove_syntax::ast::Block {
3073 statements: Vec::new(),
3074 tail: None,
3075 span: cove_diag::Span::new(cove_diag::FileId(0), 0, 0),
3076 }),
3077 decl: None,
3078 },
3079 module: "app".into(),
3080 captures: Vec::new(),
3081 }))),
3082 Value::host_module("console"),
3083 Value::host_fn("console", "println"),
3084 Value::from_resource(ResourceHandle {
3085 module: "database".to_string(),
3086 type_name: "Connection".to_string(),
3087 id: 1,
3088 task_safe: true,
3089 }),
3090 Value::type_value("Vector"),
3091 Value::range_of(1, 3, false),
3092 Value(Repr::Task(task)),
3093 Value(Repr::TaskScope(scope)),
3094 Value(Repr::Shared(cell)),
3095 ];
3096 let mut seen = 0;
3097 for value in &kinds {
3098 seen += 1;
3099 match value.view() {
3100 ValueView::Unit => assert_eq!(seen, 1),
3101 ValueView::Bool(b) => assert!(b),
3102 ValueView::Int(n) => assert_eq!(n, 1),
3103 ValueView::Float(x) => assert_eq!(x, 1.0),
3104 ValueView::Duration(ns) => assert_eq!(ns, 1),
3105 ValueView::Str(text) => assert_eq!(text, "hi"),
3106 ValueView::Array(items) => assert_eq!(items.len(), 1),
3107 // The one part that answers a guard rather than a borrow,
3108 // and it reads as the slice it guards.
3109 ValueView::Vector(elements) => assert_eq!(elements[0].as_int(), Some(1)),
3110 ValueView::Map(entries) => {
3111 assert_eq!(
3112 entries.get(&MapKey::Int(1)).and_then(Value::as_int),
3113 Some(2)
3114 )
3115 }
3116 ValueView::Set(members) => assert!(members.contains(&MapKey::Int(1))),
3117 ValueView::Struct(value) => {
3118 assert_eq!(value.type_name(), "app.Point");
3119 assert!(!value.is_opaque());
3120 assert_eq!(value.field("x").and_then(Value::as_int), Some(1));
3121 }
3122 ValueView::Enum(value) => {
3123 assert_eq!((value.type_name(), value.case()), ("Option", "Some"));
3124 assert_eq!(value.payload().len(), 1);
3125 }
3126 ValueView::Closure(closure) => {
3127 assert!(closure.is_async());
3128 assert_eq!(closure.arity(), 2);
3129 }
3130 ValueView::HostModule(name) => assert_eq!(name, "console"),
3131 ValueView::HostFn { module, op } => {
3132 assert_eq!((module, op), ("console", "println"))
3133 }
3134 ValueView::Resource(handle) => assert_eq!(handle.id, 1),
3135 ValueView::Type(name) => assert_eq!(name, "Vector"),
3136 ValueView::Range(bounds) => assert_eq!((bounds.start, bounds.end), (1, 3)),
3137 ValueView::Task(task) => assert_eq!(task.scope(), "this call"),
3138 ValueView::TaskScope(scope) => assert_eq!(scope.name(), "work"),
3139 ValueView::Shared(_) => assert_eq!(seen, 21),
3140 }
3141 }
3142 assert_eq!(seen, kinds.len());
3143 }
3144
3145 /// The view looks through a `dyn Trait` wrapper, exactly as every reader
3146 /// beside it does — which is why there is no `Dyn` variant to match, and
3147 /// why the trait name is a reader instead.
3148 #[test]
3149 fn a_view_looks_through_a_trait_object() {
3150 let wrapped = Value(Repr::Dyn(Rc::new(DynValue {
3151 trait_name: "render.Display".into(),
3152 value: Value::structure("app.Point", [("x", Value::int(1))]),
3153 })));
3154 let ValueView::Struct(value) = wrapped.view() else {
3155 panic!("a wrapped struct views as a struct, not as a wrapper");
3156 };
3157 assert_eq!(value.type_name(), "app.Point");
3158 assert_eq!(wrapped.dyn_trait(), Some("render.Display"));
3159 assert_eq!(Value::int(1).dyn_trait(), None);
3160
3161 // Twice over: `erased` looks through a wrapper holding a wrapper, so
3162 // `view` never has one to answer.
3163 let twice = Value(Repr::Dyn(Rc::new(DynValue {
3164 trait_name: "render.Display".into(),
3165 value: wrapped,
3166 })));
3167 assert!(matches!(twice.view(), ValueView::Struct(_)));
3168 }
3169
3170 /// Viewing a value shares nothing new.
3171 ///
3172 /// ADR 0028 decision 8 separates three multiplicities and a view has to
3173 /// leave all three alone. It does, because it clones nothing: no `Rc`
3174 /// count changes, so the shortfall rule that makes a Rust local a root
3175 /// answers exactly what it answered before; no root storage location is
3176 /// yielded, so `Roots::walk` still reports each reference once; and the
3177 /// graph `Marker::visit` expands is the same graph, since a view adds no
3178 /// edge to it. A view that cloned an `Rc` would add a reference no walk
3179 /// can see and keep a dead object alive; one a walk could see twice would
3180 /// conceal the very shortfall the collector's soundness rests on. This is
3181 /// what says neither happens.
3182 ///
3183 /// The `Vector` guard holds a shared `RefCell` borrow rather than a
3184 /// reference, which is a different question and is answered the same way:
3185 /// `Marker::visit` borrows the elements shared, and the sweep clears them
3186 /// through `try_borrow_mut`, so an outstanding guard cannot make either
3187 /// panic.
3188 #[test]
3189 fn a_view_changes_no_reference_count() {
3190 let storage = VectorStorage::new(vec![Value::int(1)]);
3191 let vector = Value(Repr::Vector(storage.clone()));
3192 let fields = Rc::new(StructValue {
3193 type_name: "app.Point".into(),
3194 fields: vec![("x".into(), Value::int(1))],
3195 opaque: false,
3196 });
3197 let structure = Value(Repr::Struct(fields.clone()));
3198
3199 let before = (Rc::strong_count(&storage), Rc::strong_count(&fields));
3200 let views = (vector.view(), structure.view(), vector.vector_elements());
3201 assert_eq!(
3202 before,
3203 (Rc::strong_count(&storage), Rc::strong_count(&fields))
3204 );
3205 drop(views);
3206 assert_eq!(
3207 before,
3208 (Rc::strong_count(&storage), Rc::strong_count(&fields))
3209 );
3210 }
3211
3212 /// Every scalar a host can build, built without naming a variant and read
3213 /// back through the reader it mirrors.
3214 ///
3215 /// There was no way to build an `Int` at all until this: a host wrote
3216 /// `Value::Int(3)` because there was nothing else to write, which is why
3217 /// sealing the variants had to wait for the constructors. Each line pairs
3218 /// a constructor with the reader ADR 0028 calls its mirror, so a
3219 /// constructor that stopped agreeing with its reader fails here.
3220 #[test]
3221 fn every_scalar_has_a_constructor_that_mirrors_its_reader() {
3222 assert!(Value::unit().is_unit());
3223 assert_eq!(Value::bool(true).as_bool(), Some(true));
3224 assert_eq!(Value::int(i64::MIN).as_int(), Some(i64::MIN));
3225 assert_eq!(Value::float(-0.5).as_float(), Some(-0.5));
3226 assert_eq!(
3227 Value::duration(-1_000_000_000).as_duration_nanos(),
3228 Some(-1_000_000_000)
3229 );
3230 assert_eq!(Value::string("hi").as_str(), Some("hi"));
3231 assert_eq!(Value::string(String::from("hi")).as_str(), Some("hi"));
3232
3233 // `1..3` and `1..<4` cover the same integers and are still two
3234 // different values, so the constructor takes the bounds as written
3235 // and the reader answers the normalised pair.
3236 let bounds = Value::range_of(1, 3, true).range().expect("a range");
3237 assert_eq!((bounds.start, bounds.end), (1, 4));
3238
3239 assert_eq!(
3240 Value::host_fn("console", "println").host_op(),
3241 Some(("console", "println"))
3242 );
3243 assert_eq!(
3244 Value::host_module("console").type_name(),
3245 "host module `console`"
3246 );
3247 assert_eq!(Value::type_value("Vector").type_name(), "type `Vector`");
3248
3249 let handle = ResourceHandle {
3250 module: "database".to_string(),
3251 type_name: "Connection".to_string(),
3252 id: 7,
3253 task_safe: true,
3254 };
3255 let value = Value::from_resource(handle.clone());
3256 assert!(value.resource().expect("a resource").names_same(&handle));
3257 // The `Arc` a host already holds is accepted as it stands, so nothing
3258 // has to clone a handle to build a value out of one.
3259 assert!(Value::from_resource(Arc::new(handle)).resource().is_some());
3260 }
3261}