Skip to main content

Value

Enum Value 

Source
pub enum Value {
Show 27 variants Int(i32), Float(f32), Bool(bool), String(Arc<str>), List(Arc<ListValue>), DivertTarget(DefinitionId), VariablePointer(DefinitionId), TempPointer { slot: u16, frame_depth: u16, }, Null, FragmentRef(u32), Array(Arc<Vec<Value>>), Map(Arc<OrderedMap>), Record { shape: ShapeId, fields: Arc<Vec<Value>>, }, FnRef(DefinitionId), Closure(Arc<ClosureValue>), Handle { kind: NameId, id: u64, }, Projection(Arc<ProjectionValue>), OptionVal(Option<Arc<Value>>), Range { start: i32, end: i32, inclusive: bool, }, Vec2(Vec2), Vec3(Vec3), Vec4(Vec4), Quat(Quat), Mat2(Mat2), Mat3(Mat3), Mat4(Mat4), Weighted(Arc<WeightedValue>),
}
Expand description

A runtime value in the ink VM.

Heap-allocating variants (String, List, Array, Map, Record, Closure, Projection, OptionVal, Weighted) are wrapped in Arc so that cloning a Value is always O(1) — a refcount bump, not a deep copy — which makes call-frame cloning (during fork_thread) essentially free. Atomic refcounts are used so Value can flow through Bevy’s parallel scheduler.

This Arc wrapping is a performance mechanism under value semantics, not reference semantics: sharing the underlying allocation is unobservable (docs/value-model-spec.md §3), because every mutating entry point forks the shared allocation on write (take → make_mut → write-back — see docs/runtime-spec.md’s “Value model” section). A binding that never observed a mutation never sees it, regardless of whether it shares the Arc underneath.

The Array/Map collections follow the ratified value model (docs/value-model-spec.md §4/§5): value semantics with copy-on-write sharing. Sharing is unobservable (§3) — equality is structural with an Arc::ptr_eq fast path, and mutation goes through the take → make_mut → write-back RMW discipline so an unshared collection mutates in place and a shared one performs a single copy.

PartialEq is implemented by hand rather than derived so the collection arms can take the ptr_eq shortcut; every scalar arm matches what the derive would have produced.

Variants§

§

Int(i32)

§

Float(f32)

§

Bool(bool)

§

String(Arc<str>)

§

List(Arc<ListValue>)

§

DivertTarget(DefinitionId)

§

VariablePointer(DefinitionId)

A reference to a global variable, used for ref parameters.

§

TempPointer

A runtime-only pointer to a temp in a specific call frame. Used for ref parameters that target temp variables.

Fields

§slot: u16
§frame_depth: u16
§

Null

§

FragmentRef(u32)

A reference to a fragment in the output buffer’s fragment store. Fragments preserve structural output parts for locale re-rendering.

§

Array(Arc<Vec<Value>>)

An ordered, copy-on-write collection of values (value-model-spec §4).

The backing Vec is shared behind an Arc; clone is a refcount bump. Mutation goes through array_make_mut, which copies the backing vector only when the Arc is shared.

§

Map(Arc<OrderedMap>)

An insertion-ordered, copy-on-write map with scalar keys (value-model-spec §4). Keys are int/string/bool (MapKey); iteration order is insertion order, so the value is deterministic without sorting or hashing.

§

Record

A closed-shape record (typed-dialect era, TM-4; docs/value-model-spec.md §11c / docs/typed-mode-spec.md §6).

fields is a flat, shape-ordered vector shared behind an Arc — the exact same COW discipline as Array/Map: clone is a refcount bump, mutation goes through record_make_mut. The shape is closed (no dynamic add/remove of fields) and identified by ShapeId, an interned index into the compiled story’s StructShapes table — two records are never equal unless their shapes match, even if their field vectors happen to coincide.

Fields

§shape: ShapeId
§fields: Arc<Vec<Value>>
§

FnRef(DefinitionId)

A zero-bound function value (docs/t1c-spec.md §1/§6, wire tag VAL_FN_REF). Partial application over a statically-named function with no bound-arg prefix — #fn(name) where the target has no ref params. The DefinitionId is the fn token (hashes from the target’s name, so a saved token survives recompiles that only edit the body).

A no-payload scalar (Copy-cheap DefinitionId); no Arc needed. Structural equality is “same fn token” (§5, sharing-unobservable).

§

Closure(Arc<ClosureValue>)

A function value with a bound-arg prefix (docs/t1c-spec.md §1/§6, wire tag VAL_CLOSURE). Despite the name there is no lexical environment — ink has no free variables; the “env” is the bound prefix of the target’s declared params (a val entry snapshots the value at creation, a ref entry captures a durable cell as a VariablePointer).

Wrapped in Arc for the same O(1)-clone discipline as the collection variants. Structural equality (§5): same fn token and equal env rows — ref entries compare by bound cell, val entries by value, both of which fall out of the derived per-entry comparison because a ref payload is a VariablePointer (compared by its DefinitionId).

§

Handle

An opaque host-resource token (docs/t1d-spec.md §1/§2, wire tag VAL_HANDLE). Host resources (entities, audio instances, assets, timers) enter the script world as Handle tokens: {kind, id} scalars with value semantics — copied like ints, serializable, compared by token. No live pointer ever lives in a Value; dereferencing happens only host-side, against the host’s registry, inside bindings (the sharing-unobservable dogma applies verbatim — a handle is a name, re-bound at a defined seam).

kind is a NameId into the compiled story’s manifest-declared kind vocabulary (analyzer-side, not the format — the format ships only the token shape, docs/format-v4-rfc.md §2). id is an opaque u64 the host allocates; the script never interprets it.

A no-payload scalar (Copy-cheap: NameId + u64); no Arc needed. Structural equality is token equality (kind == kind && id == id, §6) — no ordering exists (any </>/<=/>= is a runtime fault in gradual mode, a compile error under the typed dialect), and a handle is never a legal map key (the domain stays int/string/bool — same restriction as function values).

No literal syntax and no dedicated opcode construct this value — handles enter the script world only via bindings (docs/t1d-spec.md §2 RULED). This variant, its wire encoding, and its .inkt atom exist so a handle received from a binding can flow through globals, collections, saves, and the transcript like any other value.

Fields

§kind: NameId

The manifest-declared kind name (analyzer-side vocabulary).

§id: u64

The host-allocated token id. Opaque to the script.

§

Projection(Arc<ProjectionValue>)

A symbolic path projection (docs/t1e-spec.md §1/§3, wire tag VAL_PROJECTION): (root cell, path segments) — never an interior pointer. Created only in ref-argument position (ref npc.inventory[3]); reads walk the path against the root’s current value, writes desugar to root-cell RMW (take → walk → make_mut spine → write → store back, spec §3). The segment list is fixed at creation (“index expressions snapshot at ref creation”, spec §1) — there is no lazy re-evaluation.

Wrapped in Arc for the same O(1)-clone discipline as Closure. Structural equality (spec §4 PROPOSED, implemented here): same root cell and equal segments.

§

OptionVal(Option<Arc<Value>>)

A typed-absence value — the compiler-owned Option[T] enum (NS-A1, docs/stdlib-spec.md §1.1/§1.4, ruled 2026-07-18: “a fault says ‘your program is wrong’; Option says ‘the world didn’t have one’”).

Option[T] is the third compiler-known parameterized builtin (joining [T]/[K: V]) — a compiler-owned enum shape, NOT user generics. Runtime representation: None is payload-free (no allocation); Some wraps its inner value behind an Arc so clone stays O(1) like every other heap-bearing variant. Nesting is legal and meaningful (some(none) != none — the wire and equality both preserve it).

Named OptionVal (not Option) purely to avoid the eternal core::option::Option shadowing hazard inside match arms; the ValueType discriminant and every author-facing surface still say “option”.

Structural equality: none == none; some(x) == some(y) iff x == y; an Option is never equal to a bare T (the ruled Option[T] ≠ T strictness holds at the value layer too). Display (stringify/string(x)): none / some(<inner>) — the boring, stable form, total forever (F28). The §1.6b display-boundary forgiveness (Track B4) is a brink-runtime-only concern layered on top at read time (value_ops::stringify_display) — deliberately not implemented at this value-definition layer, since string() and every non-display consumer must keep seeing the total form.

§

Range

An integer range value (NS-A5, docs/stdlib-spec.md §7 — F7, ruled 2026-07-19: “ranges are a REAL Value kind”). start..end (exclusive) or start..=end (inclusive) over int bounds — v1 is int-only.

Ranges join the closed iterable set (for i in 0..n), index like a virtual array of their elements, and are the substrate of the language’s first value refinement (the inhabited range consumed by rand::int). A durable wire form exists (VAL_RANGE) because FlowFrame spills for-loop iterators across await — a range held in a loop snapshot must survive save/load.

A no-payload scalar (two i32s + a flag); no Arc needed. The written form is preserved1..7 and 1..=6 keep their inclusive flag through saves, the transcript, and display — but equality is content equality (F7’s ruling word): two ranges are equal iff they denote the same integer sequence, so 1..=6 == 1..7 and every empty range equals every other empty range. This is the same content-over-form posture as the #909 map-equality ruling (insertion order iterates, content compares).

Fields

§start: i32

The first element of the range (always inclusive).

§end: i32

The written end bound; whether it is an element depends on inclusive.

§inclusive: bool

true for the ..= form (end is the last element), false for the .. form (end is one past the last element).

§

Vec2(Vec2)

A 2-lane f32 vector (NS-A8, docs/tower-mini-spec.md T1: the tower value kinds are glam-backed — glam is the in-memory compute type, so vector/quaternion/matrix ops arrive correct-by-construction).

Serde discipline (T5): the derive on Value routes every tower variant through the hand-written lane modules in [tower_serde] — explicit x, y(, z, w) lane order for vectors and the quat, column-major column-by-column for matrices — NEVER glam’s memory representation (which varies with SIMD features and versions) and never glam’s own serde feature (kept off in Cargo.toml).

Equality (T4): componentwise IEEE via glam’s derived PartialEq — a NaN-bearing vector never equals itself, -0.0 == +0.0 per lane, exactly like bare Float. Tower values are NOT orderable (§4b: a vector in an ordering context is a NotOrderable fault) and are never legal map keys (MapKey::from_value has no tower arms).

§

Vec3(Vec3)

A 3-lane f32 vector (NS-A8). The unaligned glam::Vec3 (not Vec3A) per the mini-spec — aligned variants would bloat every Value. See Vec2 for the shared tower discipline.

§

Vec4(Vec4)

A 4-lane f32 vector (NS-A8). See Vec2.

§

Quat(Quat)

A rotation quaternion (NS-A8), lane order (x, y, z, w) per glam (T3: conventions per glam, wholesale — right-handed, quat * quat composes, quat * vec rotates). See Vec2.

§

Mat2(Mat2)

A column-major 2×2 f32 matrix (NS-A8, T2: all matrix sizes ship). See Vec2.

§

Mat3(Mat3)

A column-major 3×3 f32 matrix (NS-A8). The unaligned glam::Mat3 (not Mat3A). See Vec2.

§

Mat4(Mat4)

A column-major 4×4 f32 matrix (NS-A8). See Vec2.

§

Weighted(Arc<WeightedValue>)

A weighted table (NS-A7, docs/stdlib-spec.md §8): Weighted[T] — positive-int weights over values, in construction order. Evidence-by-construction: the only producer (weighted_new) refuses empty tables and non-positive/non-int weights, so a Weighted that exists is always a valid roll target (total). The entry row is a multiset (F17: duplicate weights legal and meaningful — deliberately divergent from Map’s key-set). v1 is construct-and-roll: no len, no iteration, no mutation.

Implementations§

Source§

impl Value

Source

pub fn value_type(&self) -> ValueType

Return the type discriminant for this value.

Source

pub fn range(start: i32, end: i32, inclusive: bool) -> Self

Build a Range from its written bounds.

Source

pub fn as_range(&self) -> Option<(i32, i32, bool)>

Borrow the (start, end, inclusive) triple if this value is a Range.

Source

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

The one-past-the-last element bound of a Range, normalized over the written form (i64 so 1..=i32::MAX cannot overflow). None for any non-range value.

Source

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

Number of elements a Range denotes (0 for an empty range — a range never has negative length). None for any non-range value. i64 because i32::MIN..=i32::MAX has 2³² elements.

Source

pub fn weighted(entries: Vec<(i32, Value)>) -> Self

Build a Weighted table from (weight, value) entries. The caller owns the §8 evidence-by-construction invariant (non-empty, positive weights) — the VM’s weighted_new op and the wire reader both validate before calling this.

Source

pub fn some(inner: Value) -> Self

Build a some(inner) OptionVal.

Source

pub fn none() -> Self

Build a none OptionVal.

Source

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

Borrow the Option payload if this value is an OptionVal: Some(Some(&inner)) for some(x), Some(None) for none, None for any non-Option value.

Source

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

Extract an i32 if this value is an Int.

Strict: does not coerce floats or booleans. Returns None for any other variant. For binding authors that want to read an integer argument from ink.

Source

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

Extract an f32 if this value is numeric.

Lenient on the int → float direction only: an Int is widened to f32 (matching ink’s implicit int→float promotion), but a float is never truncated to an int by as_int.

Source

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

Extract a bool if this value is a Bool.

Strict: does not treat nonzero numbers as truthy. Use the VM’s own truthiness rules if you need ink-style coercion.

Source

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

Borrow the string contents if this value is a String.

Source

pub fn array(items: Vec<Value>) -> Self

Build an Array from a vector of values.

Source

pub fn map(map: OrderedMap) -> Self

Build a Map from an OrderedMap.

Source

pub fn record(shape: ShapeId, fields: Vec<Value>) -> Self

Build a Record from a shape id and its field values (already in the shape’s declared field order — the caller, not this constructor, is responsible for ordering).

Source

pub fn as_record(&self) -> Option<(ShapeId, &Arc<Vec<Value>>)>

Borrow the record payload if this value is a Record.

Source

pub fn closure(target: DefinitionId, env: Vec<ClosureEnvEntry>) -> Self

Build a Closure from a target and its bound-arg prefix (T1c, docs/t1c-spec.md §6).

Source

pub fn fn_target(&self) -> Option<DefinitionId>

The fn token (target DefinitionId) if this value is a function value — FnRef or Closure.

Source

pub fn as_closure(&self) -> Option<&Arc<ClosureValue>>

Borrow the closure payload if this value is a Closure.

Source

pub fn as_weighted(&self) -> Option<&Arc<WeightedValue>>

Borrow the weighted-table payload if this value is a Weighted.

Source

pub fn handle(kind: NameId, id: u64) -> Self

Build a Handle token from a kind and host-allocated id (T1d, docs/t1d-spec.md §2). Note: this constructor is a plain value builder, not a capability mint — the invariant that handles only ever originate from a binding is enforced by the compiler (no literal syntax, no opcode constructs this value), not by this type.

Source

pub fn as_handle(&self) -> Option<(NameId, u64)>

Borrow the (kind, id) pair if this value is a Handle.

Source

pub fn projection(cell: DefinitionId, segments: Vec<ProjSegment>) -> Self

Build a Projection from a root cell and its ordered segment chain (docs/t1e-spec.md §1/§3).

Source

pub fn as_projection(&self) -> Option<&Arc<ProjectionValue>>

Borrow the projection payload if this value is a Projection.

Source

pub fn as_vec2(&self) -> Option<Vec2>

Extract the glam payload if this value is a Vec2 — the NS-A8 identity-marshal read for binding authors (T1: glam is the compute type on both sides of the boundary). Strict like as_int: no cross-kind coercion.

Source

pub fn as_vec3(&self) -> Option<Vec3>

Extract the glam payload if this value is a Vec3.

Source

pub fn as_vec4(&self) -> Option<Vec4>

Extract the glam payload if this value is a Vec4.

Source

pub fn as_quat(&self) -> Option<Quat>

Extract the glam payload if this value is a Quat.

Source

pub fn as_mat2(&self) -> Option<Mat2>

Extract the glam payload if this value is a Mat2.

Source

pub fn as_mat3(&self) -> Option<Mat3>

Extract the glam payload if this value is a Mat3.

Source

pub fn as_mat4(&self) -> Option<Mat4>

Extract the glam payload if this value is a Mat4.

Source

pub fn as_array(&self) -> Option<&Arc<Vec<Value>>>

Borrow the array payload if this value is an Array.

Read-only: the returned slice never triggers a copy. Mutation uses array_make_mut.

Source

pub fn as_map(&self) -> Option<&Arc<OrderedMap>>

Borrow the map payload if this value is a Map.

Read-only: mutation uses map_make_mut.

Source

pub fn array_make_mut(&mut self) -> Option<&mut Vec<Value>>

Copy-on-write mutable access to an Array’s backing vector, or None for any other value.

This is the make_mut step of the take → make_mut → write-back RMW discipline (value-model-spec §5). When the backing Arc is unique the mutation is in place (O(1) amortized append); when it is shared with a snapshot or another slot, exactly one O(n) copy is made and the value becomes unique again. Because sharing is unobservable (§3), callers cannot tell which path was taken.

Source

pub fn map_make_mut(&mut self) -> Option<&mut OrderedMap>

Copy-on-write mutable access to a Map’s contents, or None for any other value. See array_make_mut for the RMW discipline this implements.

Source

pub fn record_make_mut(&mut self) -> Option<&mut Vec<Value>>

Copy-on-write mutable access to a Record’s flat field vector, or None for any other value. See array_make_mut for the RMW discipline this implements — the shape itself never changes (closed shape), only field values.

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

Source§

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

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

impl<'de> Deserialize<'de> for Value

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<&str> for Value

Source§

fn from(v: &str) -> Self

Converts to this type from the input type.
Source§

impl From<()> for Value

Source§

fn from((): ()) -> Self

The unit type maps to Null — the natural return for a fire-and-forget external that produces no value.

Source§

impl From<Arc<str>> for Value

Source§

fn from(v: Arc<str>) -> Self

Converts to this type from the input type.
Source§

impl From<Mat2> for Value

Source§

fn from(v: Mat2) -> Self

Converts to this type from the input type.
Source§

impl From<Mat3> for Value

Source§

fn from(v: Mat3) -> Self

Converts to this type from the input type.
Source§

impl From<Mat4> for Value

Source§

fn from(v: Mat4) -> Self

Converts to this type from the input type.
Source§

impl From<Quat> for Value

Source§

fn from(v: Quat) -> Self

Converts to this type from the input type.
Source§

impl From<String> for Value

Source§

fn from(v: String) -> Self

Converts to this type from the input type.
Source§

impl From<Vec2> for Value

Source§

fn from(v: Vec2) -> Self

Converts to this type from the input type.
Source§

impl From<Vec3> for Value

Source§

fn from(v: Vec3) -> Self

Converts to this type from the input type.
Source§

impl From<Vec4> for Value

Source§

fn from(v: Vec4) -> Self

Converts to this type from the input type.
Source§

impl From<bool> for Value

Source§

fn from(v: bool) -> Self

Converts to this type from the input type.
Source§

impl From<f32> for Value

Source§

fn from(v: f32) -> Self

Converts to this type from the input type.
Source§

impl From<i32> for Value

Source§

fn from(v: i32) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Value

Structural equality with an Arc::ptr_eq fast path for collections (value-model-spec §4/§5).

Every scalar arm reproduces exactly what #[derive(PartialEq)] would emit. The Array/Map arms add the ptr_eq shortcut: two values that share the same Arc (the same snapshot) compare equal immediately, otherwise the comparison is element-wise structural. NaN-bearing collections that are not the same snapshot never compare equal, because f32 equality composes structurally through the elements; a collection compared against itself (same Arc) is equal even if it contains a NaN — the spec calls this out as harmless and stated (§4).

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Value

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Value

§

impl RefUnwindSafe for Value

§

impl Send for Value

§

impl Sync for Value

§

impl Unpin for Value

§

impl UnsafeUnpin for Value

§

impl UnwindSafe 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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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.