Skip to main content

Value

Struct Value 

Source
pub struct Value(/* private fields */);
Expand description

A Cove value.

An abstract type. What it holds is private to this crate: a host builds one through a constructor, reads one through a reader, and classifies one through Value::view. ADR 0028 decision 6 is where that was decided and issue #196 is where it was asked. Every change to what a value is had been a source break for the hosts that matched on it, and the record is not that pub variants are survivable but that each change was individually rescued — twice by luck and once by a hand-written compatibility shim.

The one thing sealing takes away is the compile error a host got when a new variant arrived, and ValueView gives that back deliberately and exhaustively. What it does not give back is a compile error when the runtime moves a value from a Box to an Rc, which is the whole point: those two were the same error before, and they are unrelated events.

Implementations§

Source§

impl Value

The builtin Option, Result, and Error values, built and read through the one description of what they are made of.

Ok, Err, Some, None, and an Error’s message are declared in cove_schema::builtins, which is also where cove-sema reads them to check a match and to type a pattern’s binding. Everything in this workspace that builds one of these values or asks which case a value is goes through the constructors and readers below, so the four case names are stated once and the question “is this an Ok?” has one answer.

Source

pub fn ok(value: Value) -> Value

Ok(value)

Source

pub fn err(error: Value) -> Value

Err(error)

Source

pub fn some(value: Value) -> Value

Some(value)

Source

pub fn none() -> Value

None

Source

pub fn error(message: impl Into<String>) -> Value

The builtin Error struct.

Source

pub fn structure<N: Into<Rc<str>>>( type_name: impl Into<Rc<str>>, fields: impl IntoIterator<Item = (N, Value)>, ) -> Value

A value of the declared struct type type_name, carrying fields in declaration order.

type_name is the qualified name the declaring module gives it, such as rules.policy.PullRequest: that is the name every value of a declared type carries, and the name an invocation and the Host API boundary both check against.

This exists so that a host building an argument for Vm::invoke does not have to name StructValue’s layout to do it — the Rc, the field vector, and in particular opaque, which records that the declaration said export opaque struct (ADR 0014) and is therefore not a thing a caller has an answer for. Issue #109 asks that the internal representation become less exposed to embedders; this is one place it was exposed for no reason.

Source

pub fn enumeration( type_name: impl Into<Rc<str>>, case: impl Into<Rc<str>>, payload: impl IntoIterator<Item = Value>, ) -> Value

A value of the declared enum type type_name, in the case case, carrying payload in the order the case declares it.

The companion of Value::structure for the other declared shape. Value::ok and the three beside it build the builtin enums, whose case names come from cove_schema::builtins and are not a caller’s to choose; this one takes both names because a package’s own enum is a package’s own.

Source

pub fn array(items: impl IntoIterator<Item = Value>) -> Value

An Array holding items, in order.

The companion of Value::structure, and there for the same reason: a host that builds an array should not have to know that the elements are stored behind a shared pointer to a slice.

Source

pub fn set(items: impl IntoIterator<Item = MapKey>) -> Value

A Set holding items.

The elements are MapKeys and not Values, and that is the MapKey restriction showing through rather than an inconvenience: a set of values would be a constructor that could fail, and there is nothing sensible for it to do when it does. A host building one from its own data writes the key it means — MapKey::Str(name) for a set of names — and a host holding a Value it did not build converts with MapKey::from_value, which reports the part that cannot be a key and the path to reach it.

Duplicates collapse, exactly as they do for a Set a Cove program builds, and the order the set iterates in is ascending key order whatever order they arrived in.

Source

pub fn map(entries: impl IntoIterator<Item = (MapKey, Value)>) -> Value

A Map holding entries.

The companion of Value::set, with the same reason for taking a MapKey: only the key carries the restriction, so the value half is an ordinary Value. A later entry under a key an earlier one used replaces it.

Source

pub fn unit() -> Value

(), the value a statement and a function with no result answer.

Source

pub fn bool(b: bool) -> Value

The Bool b.

Source

pub fn int(n: i64) -> Value

The Int n.

A full sixty-four bits, because an Int is one: issue #109 measured the alternatives that are not, and NaN boxing and pointer tagging are refused rather than deferred because neither can hold every Int and every Float at once.

Source

pub fn float(x: f64) -> Value

The Float x, including every NaN and both zeroes.

Source

pub fn duration(nanos: i64) -> Value

The Duration of nanos nanoseconds.

Nanoseconds rather than a std::time::Duration, for the reason Value::as_duration_nanos gives on the way out: a Cove duration is a signed count of them, and -1s is an ordinary value that std::time::Duration cannot hold.

Source

pub fn string(text: impl Into<Rc<str>>) -> Value

The String text.

Named for the Cove type and not for Rust’s, which is why it takes anything a string can be made from rather than a String specifically: Value::string("hi") copies the characters once and says nothing about where they end up.

Source

pub fn range_of(start: i64, end: i64, inclusive_end: bool) -> Value

The range start..end, or start..<end when inclusive_end is false.

Both bounds as source writes them, rather than the normalised half-open pair Value::range answers with: 1..3 and 1..<4 cover the same integers and are still two different values, since == compares the bounds a range was written with.

The name is range_of and not range because the reader took range, and the readers are what issue #195 shipped.

Source

pub fn from_resource(handle: impl Into<Arc<ResourceHandle>>) -> Value

A handle to a resource the host owns, such as a database connection.

The companion of Value::resource, and it takes the whole handle because ADR 0013 decides that a handle is a name and every field of it is part of that name. What it hides is the shared pointer, which is there so a handle can cross into a task when its schema allows it — pass either a ResourceHandle or the Arc that ResourceHandle::new answers.

The name is from_resource and not resource because the reader took resource.

Source

pub fn host_fn(module: impl Into<Rc<str>>, op: impl Into<Rc<str>>) -> Value

A bound host operation, such as console.println.

The companion of Value::host_op. Two names and not an implementation: what they name is found in the registry at the call.

Source

pub fn host_module(name: impl Into<Rc<str>>) -> Value

A bound host module, such as console.

Source

pub fn type_value(name: impl Into<Rc<str>>) -> Value

A type used as a value, such as Vector in Vector.of(1, 2).

The name is type_value and not type_name because Value::type_name answers the name of the type a value is, which is a different question asked of every value rather than of this one.

Source

pub fn is_ok(&self) -> bool

Whether this is an Ok, the success case of a Result.

Source

pub fn is_err(&self) -> bool

Whether this is an Err.

Source

pub fn is_some(&self) -> bool

Whether this is a Some.

Source

pub fn ok_payload(&self) -> Option<&[Value]>

What an Ok carries, when this is one.

The payload is a slice rather than a value because what a caller does with an empty one differs: the ? operator answers () and a diagnostic answers nothing at all. The schema says an Ok carries exactly one value, so an empty one is a host that broke its word.

Source

pub fn err_payload(&self) -> Option<&[Value]>

What an Err carries, when this is one.

Source

pub fn some_payload(&self) -> Option<&[Value]>

What a Some carries, when this is one.

Source

pub fn error_message(&self) -> Option<&Value>

The message a builtin Error carries, when this is one.

Source

pub fn same_type_as(&self, other: &Value) -> bool

The name shown in diagnostics. Whether other is a value of the same type as this one, without naming either type.

== has to refuse a comparison between two types before it compares two values, and it asked that question by building both type names and comparing the strings. Two allocations per comparison is a great deal to pay for an answer that is a discriminant check and, for the two declared kinds, one string comparison — and a parser compares characters constantly, so this was measurable (issue #104). The names are still built for the diagnostic, which happens once.

Source

pub fn declared_type_name(&self) -> Option<&Rc<str>>

The name of the declared type this value is of, for a struct or an enum, and None for everything else.

A method declared in a package can only ever be found on one of those two, so this is what receiver dispatch asks rather than Value::type_name: no name is built at all for the receivers that have none, and a declared one hands back the name it already holds.

A Some here is not a declared type. The builtin Option and Result are Repr::Enum as well, and answer their own bare names — Option, with no module in front. A caller asking “is this a declared type” has to look for the dot; a caller that read is_some as the answer got two builtins wrong.

Source

pub fn type_name(&self) -> String

Source

pub fn erased(&self) -> &Value

The value a trait object holds, or this value when it is not one.

A dyn Trait wrapper records where a value was converted, and the checker decides where that is: a written type converts and a lambda’s inferred result does not, though both have type dyn Trait. Nothing a program can ask should be able to tell those two apart, so everything that compares, renders, or keys a value looks through the wrapper first.

Source

pub fn eq_value(&self, other: &Value) -> bool

Value equality. Identity, when available, is explicit and separate.

Source§

impl Value

Reading a value without naming its representation.

The constructors above — Value::structure, Value::enumeration, Value::array, Value::set, Value::map, and the builtin four — let a host build every shape that crosses the boundary without writing an Rc, a Box, a field vector or the opaque flag. These are the other half: they let a host read the same shapes the same way.

Only one half existed, and the missing half cost something every time the representation moved. Issue #104 made Value::Struct an Rc<StructValue>; issue #109 put Value::HostFn’s two names behind one pointer and took every value in the program from forty bytes to twenty-four; issue #121 replaced a closure’s parameter list with an arity; issue #183 replaced an enum payload’s Vec<Value> with Payload. Every one of those was invisible to a host that only built values and a source break for one that read them, because reading meant matching on a variant and a match on a variant is a match on the representation. Issue #186 is where that was written down, and this is its answer.

A reader borrows. It hands back a reference into the value it was asked about and the caller clones what it means to keep, which is what Value::ok_payload and StructValue::get already did and what a host wants: a conversion into the host’s own types reads each part once and keeps no Value at all. Borrowing is the half of this that constrains what can still move, and it constrains it in one direction — every part a reader answers with has to be stored as the thing it answers with. A struct’s fields can move behind a different pointer, a shared shape table, or an inline arity the way Payload already did, and none of that is visible here; they cannot become values that are computed — unpacked from a tagged word, decoded lazily, or held under a lock — without these signatures changing. A reader that cloned would forbid none of that, and would charge every read for the possibility. A Vector is where the line already falls, and it falls the same way for building: its elements are behind a RefCell because the language lets an alias write them, so there is no borrowing reader for one here and no constructor for one above.

A wrong shape answers None. Asking an Int for its fields is the host’s mistake rather than the program’s — no Cove code asked for it and none can handle it — so it is not a RuntimeError; and it is not a panic either, because a host converting a value it did not build wants to report what arrived instead. Value::type_name is what names that in the report. This is the convention the readers that already existed use: Value::ok_payload, Value::error_message and StructValue::get all answer None to the question they were not the right value for.

A reader looks through dyn Trait. Each of these calls Value::erased first, for the reason that method gives: the wrapper records where a value was converted, nothing a program can ask should be able to tell a written dyn Trait from a lambda’s inferred one, and fmt::Display already looks through it — “the wrapper is a representation, not something the program put there”. There is no reader for the wrapper itself, which matches the constructors, none of which can build one.

Source

pub fn as_bool(&self) -> Option<bool>

The Bool this is.

Source

pub fn as_int(&self) -> Option<i64>

The Int this is.

A full sixty-four bits, because an Int is one and overflow is a broken invariant rather than a wrap.

Source

pub fn as_float(&self) -> Option<f64>

The Float this is.

Source

pub fn as_duration_nanos(&self) -> Option<i64>

The Duration this is, in nanoseconds.

Nanoseconds rather than a std::time::Duration, because a Cove duration is a signed count of them: -1s is an ordinary value and std::time::Duration cannot hold it.

Source

pub fn as_str(&self) -> Option<&str>

The String this is.

Source

pub fn is_unit(&self) -> bool

Whether this is ().

Source

pub fn declared_type(&self) -> Option<&str>

The declared type this value is of — rules.policy.Decision, or Option for a builtin — for a struct or an enum, and None for everything else.

The qualified name Value::structure and Value::enumeration take, which is what a host checks an answer against before reading it apart. Value::declared_type_name answers the same question with the shared handle itself, because the two backends clone it to dispatch a method; this is the reader, and it does not say what the handle is made of.

Source

pub fn field(&self, name: &str) -> Option<&Value>

The field name of a struct value.

None both when this is not a struct and when the struct declares no such field, because a host has the same thing to say about either and Value::type_name is what says it: “Int carries no field policy” and “rules.policy.Decision carries no field polciy” are the same sentence with the name filled in.

Source

pub fn fields(&self) -> Option<impl Iterator<Item = (&str, &Value)> + '_>

A struct value’s fields, in declaration order, and None when this is not a struct — which is also how a host asks whether it is one.

Declaration order rather than the order anything asked for: it is the order Value::structure was handed and the order the declaration states, so a host reading a struct positionally reads what a host building one wrote.

An export opaque struct (ADR 0014) answers here like any other. The flag governs rendering, because a Display has no idea which module is watching; a host holding the value has already been handed it, and hiding the fields from it would hide them from the very code the module exported the value to.

Source

pub fn case(&self) -> Option<&str>

The case of an enum value, such as Some, Err, or Require.

The case alone, unqualified, exactly as Value::enumeration takes it; Value::declared_type is the other half of the name.

Source

pub fn payload(&self) -> Option<&[Value]>

What an enum value’s case carries, in the order the case declares it.

A slice, and an empty one for a case that carries nothing, for the reason Value::ok_payload gives: what a caller does with an empty payload differs and only the caller knows which. Those four ask a builtin question — “is this an Ok?” — and answer the payload as a consequence; this one is asked of a value whose case the caller reads for itself with Value::case, which is what a package’s own enum needs.

Source

pub fn items(&self) -> Option<&[Value]>

An Array’s elements, in order.

The companion of Value::array. A Vector answers None and that is not an oversight: its elements are behind a RefCell because an alias may write them, so nothing can hand out a plain slice of them, and there is no constructor for one either. Value::vector_elements is how a vector is read — a guard rather than a slice, which is what a part behind a cell can answer with.

Source

pub fn elements(&self) -> Option<impl Iterator<Item = &MapKey> + '_>

A Set’s elements, in ascending key order.

MapKeys and not Values, for the reason Value::set gives on the way in: the restriction is real, and showing it is better than a reader that pretends a set holds anything. MapKey::to_value converts one back.

Ascending key order whatever order they were inserted in, which is the order a Cove program iterating the same set sees.

Source

pub fn entries(&self) -> Option<impl Iterator<Item = (&MapKey, &Value)> + '_>

A Map’s entries, in ascending key order.

The companion of Value::map, with the same split: only the key carries the MapKey restriction, so the value half is an ordinary Value.

Source

pub fn range(&self) -> Option<RangeBounds>

A Range’s bounds, half-open.

RangeBounds rather than the three fields the variant holds, because .. and ..< are two ways of writing one range: 1..3 and 1..<4 cover the same integers, and a host asking what a range covers should not have to normalise them itself. The bounds are i128 so that an inclusive i64::MAX end cannot overflow.

Source

pub fn resource(&self) -> Option<&ResourceHandle>

The resource handle this is.

ResourceHandle is the answer rather than something this hides, because ADR 0013 decides that a handle is a name: “every field of it is part of the name”, and there is no field for state because the state is the host’s. What this hides is the Arc, which is there so that a handle can cross into a task when its schema allows it.

Source

pub fn host_op(&self) -> Option<(&str, &str)>

The module and operation a bound host operation names, such as ("console", "println").

Two names and not an implementation: a bound host operation is a name the way ValueView::HostModule is, and what it names is found in the registry at the call. This is the reader for the variant issue #109 boxed to buy the sixteen bytes — a host that matched Value::HostFn { module, op } had to be rewritten, and one that had called this would not have noticed.

Source

pub fn arity(&self) -> Option<usize>

How many parameters a closure value declares.

Parameters and not arguments a call must supply: a defaulted or a variadic parameter counts like any other. A host that was handed a callback asks this to refuse one of the wrong shape before calling it back through Reentry, which is the only way to call one, since the body belongs to the backend that made it. This is the reader for the field issue #121 replaced with a count, and it is the whole of a closure a host has any business reading.

Source

pub fn vector_elements(&self) -> Option<Elements<'_>>

A Vector’s elements, in order, for as long as the guard is held.

The companion of Value::items, which answers None for a Vector because its elements sit behind a cell — an alias may write them, so nothing can hand out a plain &[Value] of them. Issue #196 records that as “the one place the borrow-based reader design cannot reach”; ADR 0028 decision 7 is where it is reached, and this is the shape of the answer: a part whose storage will not sit still is handed out as an opaque guard, and the guard is public API.

Elements derefs to [Value], so a host reads a vector the way it reads an array. Holding one borrows the vector: drop it before calling back into Cove through Reentry, because Cove code that writes the same vector while the guard is alive is a panic rather than a data race.

Source

pub fn dyn_trait(&self) -> Option<&str>

The trait a dyn Trait value was used at, such as render.Display.

The one reader that does not look through the wrapper, because it is the reader for the wrapper. Every other reader and Value::view call Value::erased first, for the reason that method gives — the wrapper is a representation, not something the program put there — so this is how a host that genuinely wants to name the trait in a diagnostic asks for it.

Source

pub fn view(&self) -> ValueView<'_>

Classify this value: what kind of Cove value it is, and its parts.

O(1), allocates nothing, and borrows from self. It looks through dyn Trait exactly as every reader beside it does, which is why ValueView has no Dyn variant; Value::dyn_trait is how a host asks about the wrapper.

This is the exhaustive match that sealing takes away, given back deliberately. See ValueView for what it promises and when it breaks.

A Vector borrows its elements for as long as the view is held, for the reason Value::vector_elements gives.

Trait Implementations§

Source§

impl Clone for Value

Source§

fn clone(&self) -> Value

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Value

Value prints as the value it is, and not as a wrapper around one.

Forwarded rather than derived so that the newtype the seal is made of leaves no trace in a rendering: a Debug of an Int is Int(3), exactly as it was when Value was the enum itself. Tests, traces and diagnostics all read this, and none of them should have to know.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Value

How a value appears inside string interpolation and console.println.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl FromIterator<Value> for Payload

Source§

fn from_iter<I: IntoIterator<Item = Value>>(values: I) -> Payload

Creates a value from an iterator. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Value

§

impl !Send for Value

§

impl !Sync for Value

§

impl !UnwindSafe for Value

§

impl Freeze for Value

§

impl Unpin for Value

§

impl UnsafeUnpin for Value

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.