Skip to main content

Value

Enum Value 

Source
pub enum Value {
Show 16 variants Nil, True, False, Number(isize), Char(char), Cons { car: ArenaIndex, cdr: ArenaIndex, }, Symbol(ArenaIndex), Lambda { params: ArenaIndex, body_env: ArenaIndex, }, Builtin(Builtin), StdLib(StdLib), Array { len: usize, data: ArenaIndex, }, String { len: usize, data: ArenaIndex, }, Native { id: usize, name_hash: usize, }, Ref(ArenaIndex), Usize(usize), SyntaxRules { literals: ArenaIndex, rules_env: ArenaIndex, },
}
Expand description

A Lisp value

§Memory Optimization

This enum inlines fixed-size data directly into variants to save arena slots and improve cache locality. Variable-length data (strings, arrays) still uses arena storage but with inline length for O(1) access.

Variants§

§

Nil

The empty list (NOT false - use False for that)

§

True

Boolean true (#t)

§

False

Boolean false (#f) - the ONLY false value

§

Number(isize)

Integer number

§

Char(char)

Single character (used in strings and symbol storage)

§

Cons

Cons cell (pair) with inline car/cdr indices

Both car and cdr are stored inline, saving 2 arena slots per cons.

§Memory Savings

Previously: 1 slot for Cons + 2 slots for [Ref(car), Ref(cdr)] = 3 slots Now: 1 slot for Cons with inline car/cdr = 1 slot (saves 2 slots)

Use Lisp::cons(), Lisp::car(), Lisp::cdr() to create and access.

Fields

§

Symbol(ArenaIndex)

Symbol (contains a contiguous string) Points to a Value::String which contains the symbol name. The length is obtained from the String value, providing a single source of truth.

§

Lambda

Lambda / closure with inline params and body_env indices

  • params: ArenaIndex to list of parameter symbols
  • body_env: ArenaIndex to a cons cell containing (body . env)

§Memory Savings

Previously: 1 slot for Lambda + 3 slots for [Ref(params), Ref(body), Ref(env)] = 4 slots Now: 1 slot for Lambda with inline params/body_env + 1 cons for body.env = 2 slots (saves 2 slots)

Use Lisp::lambda() to create and Lisp::lambda_parts() to extract.

Fields

§params: ArenaIndex
§body_env: ArenaIndex
§

Builtin(Builtin)

Built-in function (optimized)

§

StdLib(StdLib)

Standard library function (stored in static memory)

Unlike Lambda which stores code in the arena, StdLib references static function definitions. The function body is parsed on each call.

§Memory Efficiency

  • Function definitions are in static memory (const strings)
  • No arena allocation for the function definition itself
  • Parsed AST is temporary and GC’d after evaluation
§

Array

Vector/Array with inline length and data pointer

Vectors store values contiguously in the arena. The length is inlined for O(1) access, saving 1 arena slot per array.

§Memory Layout

  • len: Number of elements (inline)
  • data: Points directly to first element (no length header in arena)
  • Empty arrays have len=0 and data == NIL

§Memory Savings

Previously: 1 slot for Array + Number(len) header + elements Now: 1 slot for Array with inline len + elements only (saves 1 slot)

§Example

(define vec (make-vector 3 0))  ; Create vector of 3 zeros
(vector-set! vec 1 42)          ; Set index 1 to 42
(vector-ref vec 1)              ; => 42
(vector-length vec)             ; => 3 (O(1) - inline!)
#(1 2 3)                        ; Vector literal syntax

Fields

§len: usize
§

String

String with inline length and data pointer

Strings store characters contiguously in the arena. The length is inlined for O(1) access, saving 1 arena slot per string.

§Memory Layout

  • len: Number of characters (inline)
  • data: Points directly to first Char value (no length header in arena)
  • Empty strings have len=0 and data == NIL

§Memory Savings

Previously: 1 slot for String + Number(len) header + chars Now: 1 slot for String with inline len + chars only (saves 1 slot)

§Example

(string-length "hello")   ; => 5 (O(1) - inline!)
(string-ref "hello" 0)    ; => #\h

Fields

§len: usize
§

Native

Native function with inline id and name_hash

Native functions are registered at runtime and identified by their ID. The actual function pointer is stored in the evaluator’s NativeRegistry.

§Memory Savings

Previously: 1 slot for Native + 2 slots for [Usize(id), Usize(name_hash)] = 3 slots Now: 1 slot for Native with inline id/name_hash = 1 slot (saves 2 slots)

Fields

§name_hash: usize
§

Ref(ArenaIndex)

Raw arena index reference

Used internally for storing arena indices in contiguous blocks. This allows other variants (like Cons) to store their references in the arena rather than inline, enabling memory optimizations.

§Note

This is an internal implementation detail and should not be exposed to Lisp code directly. It’s traced by the GC like any other reference.

§

Usize(usize)

Unsigned integer (internal use)

Used for storing unsigned values like array lengths, indices, or other internal counters that need the full positive range of a machine word.

§Note

This is primarily an internal implementation detail. For user-facing integers, prefer Number(isize) which supports negative values.

§

SyntaxRules

Syntax-rules macro transformer

Stores a compiled macro with literals, rules, and definition environment. Following the same 2-index constraint as Lambda, we pack fields into cons cells.

§Memory Layout

  • literals: ArenaIndex to list of literal keyword symbols
  • rules_env: ArenaIndex to cons cell (rules . definition_env)
    • car: list of (pattern . template) pairs
    • cdr: environment where macro was defined (for hygiene)

This matches Lambda’s layout: 2 inline ArenaIndex fields = 1 arena slot.

§Example

(define-syntax when
  (syntax-rules ()
    ((when test body ...)
     (if test (begin body ...)))))

Stored as:

  • literals: ()
  • rules_env: (rules_list . global_env) where rules_list = (((when test body …) . (if test (begin body …))))

Fields

§literals: ArenaIndex
§rules_env: ArenaIndex

Implementations§

Source§

impl Value

Source

pub const fn is_nil(&self) -> bool

Check if this value is nil (empty list)

Source

pub const fn is_false(&self) -> bool

Check if this value is false (#f) This is the ONLY way to be false in this Lisp

Source

pub const fn is_true(&self) -> bool

Check if this value is true (#t)

Source

pub const fn is_boolean(&self) -> bool

Check if this value is a boolean (#t or #f)

Source

pub const fn is_atom(&self) -> bool

Check if this value is an atom (not a cons cell)

Source

pub const fn is_number(&self) -> bool

Check if this value is a number

Source

pub const fn is_integer(&self) -> bool

Check if this value is an integer

Source

pub const fn as_ref(&self) -> Option<ArenaIndex>

Extract ArenaIndex from a Ref value. Returns None if not a Ref.

Source

pub fn unwrap_ref(self) -> ArenaIndex

Extract ArenaIndex from a Ref value, panicking if not a Ref. Use only when you are certain the value is a Ref (e.g., after alloc_contiguous for Refs).

Source

pub const fn is_symbol(&self) -> bool

Check if this value is a symbol

Source

pub const fn is_cons(&self) -> bool

Check if this value is a cons cell (pair)

Source

pub const fn is_lambda(&self) -> bool

Check if this value is a lambda

Source

pub const fn is_builtin(&self) -> bool

Check if this value is a builtin

Source

pub const fn is_stdlib(&self) -> bool

Check if this value is a stdlib function

Source

pub const fn is_native(&self) -> bool

Check if this value is a native (Rust) function

Source

pub const fn is_procedure(&self) -> bool

Check if this value is a procedure (lambda, builtin, stdlib, or native function)

Source

pub const fn is_array(&self) -> bool

Check if this value is an array

Source

pub const fn is_string(&self) -> bool

Check if this value is a string

Source

pub const fn is_ref(&self) -> bool

Check if this value is a ref (internal arena index reference)

Source

pub const fn as_number(&self) -> Option<isize>

Get the number value if this is an integer

Source

pub const fn as_char(&self) -> Option<char>

Get the char value if this is a char

Source

pub const fn is_usize(&self) -> bool

Check if this value is a usize (internal unsigned integer)

Source

pub const fn as_usize(&self) -> Option<usize>

Get the usize value if this is a Usize

Source

pub const fn type_name(&self) -> &'static str

Get a human-readable type name

Source

pub const fn is_syntax_rules(&self) -> bool

Check if this value is a syntax-rules transformer

Trait Implementations§

Source§

impl Clone for Value

Source§

fn clone(&self) -> Value

Returns a duplicate of the value. Read more
1.0.0 · 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 PartialEq for Value

Source§

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

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

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

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<const N: usize> Trace<Value, N> for Value

Implement Trace for GC support

With inline fields, tracing is simpler - we just trace the ArenaIndex fields directly. No arena access needed to determine structure, which improves GC performance.

Source§

fn trace<F: FnMut(ArenaIndex)>(&self, tracer: F)

Trace all ArenaIndex references contained in this value. Read more
Source§

fn trace_with_arena<F: FnMut(ArenaIndex)>( &self, _arena: &Arena<Value, N>, tracer: F, )

Trace with arena access for types that store metadata in the arena. Read more
Source§

impl Copy for Value

Source§

impl StructuralPartialEq for Value

Auto Trait Implementations§

§

impl Freeze for Value

§

impl RefUnwindSafe for Value

§

impl Send for Value

§

impl Sync for Value

§

impl Unpin 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> 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, 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.