Skip to main content

shape_value/
value.rs

1//! Core value types for Shape
2//!
3//! This module defines supporting types used throughout the Shape runtime and VM.
4//! The canonical runtime value representation is `ValueWord` (8-byte NaN-boxed).
5
6use std::collections::HashMap;
7use std::sync::{Arc, RwLock};
8
9use crate::value_word::ValueWord;
10
11/// Type alias for array storage — ValueWord elements for 9x memory reduction.
12pub type VMArray = Arc<Vec<ValueWord>>;
13
14/// Upvalue - a captured variable that can be shared between closures and their enclosing scope.
15///
16/// Most captures are immutable (the compiler never emits `StoreClosure`), so the
17/// `Immutable` variant stores the ValueWord directly — no Arc, no RwLock, just an
18/// 8-byte clone.  The `Mutable` variant preserves the old `Arc<RwLock<ValueWord>>`
19/// path for the rare case where a capture is written to.
20#[derive(Debug, Clone)]
21pub enum Upvalue {
22    /// Direct value — no lock, no Arc overhead.  Clone is 8 bytes (or Arc bump for heap values).
23    Immutable(ValueWord),
24    /// Shared mutable capture — used if `StoreClosure` is ever emitted.
25    Mutable(Arc<RwLock<ValueWord>>),
26}
27
28impl Upvalue {
29    /// Create a new **immutable** upvalue (fast path — default for all captures).
30    #[inline]
31    pub fn new(value: ValueWord) -> Self {
32        Upvalue::Immutable(value)
33    }
34
35    /// Create a new **mutable** upvalue (slow path — only when writes are needed).
36    #[inline]
37    pub fn new_mutable(value: ValueWord) -> Self {
38        Upvalue::Mutable(Arc::new(RwLock::new(value)))
39    }
40
41    /// Get a clone of the contained ValueWord value.
42    #[inline]
43    pub fn get(&self) -> ValueWord {
44        match self {
45            Upvalue::Immutable(nb) => nb.clone(),
46            Upvalue::Mutable(arc) => arc.read().unwrap().clone(),
47        }
48    }
49
50    /// Set the contained value.
51    ///
52    /// If the upvalue is `Immutable`, it is upgraded to `Mutable` on the first write.
53    /// This requires `&mut self`.
54    pub fn set(&mut self, value: ValueWord) {
55        match self {
56            Upvalue::Mutable(arc) => {
57                *arc.write().unwrap() = value;
58            }
59            Upvalue::Immutable(_) => {
60                // Upgrade to mutable on first write
61                *self = Upvalue::Mutable(Arc::new(RwLock::new(value)));
62            }
63        }
64    }
65}
66
67/// Print result with structured spans for reformattable output
68#[derive(Debug, Clone)]
69pub struct PrintResult {
70    /// Rendered output string (cached)
71    pub rendered: String,
72
73    /// Structured spans with metadata for reformatting
74    pub spans: Vec<PrintSpan>,
75}
76
77/// A span in print output (literal text or formatted value)
78#[derive(Debug, Clone)]
79pub enum PrintSpan {
80    /// Literal text span
81    Literal {
82        text: String,
83        start: usize,
84        end: usize,
85        span_id: String,
86    },
87
88    /// Value span with formatting metadata
89    Value {
90        text: String,
91        start: usize,
92        end: usize,
93        span_id: String,
94        variable_name: Option<String>,
95        raw_value: Box<ValueWord>,
96        type_name: String,
97        current_format: String,
98        format_params: HashMap<String, ValueWord>,
99    },
100}
101
102/// A callable closure backed by native Rust code with captured state.
103/// Used by extension modules to return objects with callable methods (e.g., DbTable.filter).
104#[derive(Clone)]
105pub struct HostCallable {
106    inner: Arc<dyn Fn(&[ValueWord]) -> Result<ValueWord, String> + Send + Sync>,
107}
108
109impl HostCallable {
110    /// Create a new HostCallable from a closure
111    pub fn new(
112        f: impl Fn(&[ValueWord]) -> Result<ValueWord, String> + Send + Sync + 'static,
113    ) -> Self {
114        Self { inner: Arc::new(f) }
115    }
116
117    /// Call the host closure with the given arguments
118    pub fn call(&self, args: &[ValueWord]) -> Result<ValueWord, String> {
119        (self.inner)(args)
120    }
121}
122
123impl std::fmt::Debug for HostCallable {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        f.write_str("<host_closure>")
126    }
127}
128
129/// Comparison operator for filter expressions
130#[derive(Debug, Clone, PartialEq)]
131pub enum FilterOp {
132    Eq,
133    Neq,
134    Gt,
135    Gte,
136    Lt,
137    Lte,
138}
139
140/// A literal value in a filter expression (for SQL generation)
141#[derive(Debug, Clone, PartialEq)]
142pub enum FilterLiteral {
143    Int(i64),
144    Float(f64),
145    String(String),
146    Bool(bool),
147    Null,
148}
149
150/// Filter expression tree for SQL pushdown.
151/// Built from ExprProxy comparisons and logical operations.
152#[derive(Debug, Clone, PartialEq)]
153pub enum FilterNode {
154    /// Column compared to a literal value
155    Compare {
156        column: String,
157        op: FilterOp,
158        value: FilterLiteral,
159    },
160    /// Logical AND of two filter nodes
161    And(Box<FilterNode>, Box<FilterNode>),
162    /// Logical OR of two filter nodes
163    Or(Box<FilterNode>, Box<FilterNode>),
164    /// Logical NOT of a filter node
165    Not(Box<FilterNode>),
166}
167
168/// Virtual method table for trait objects.
169///
170/// Maps method names to function IDs for dynamic dispatch.
171/// Created when a concrete value is boxed into a `dyn Trait`.
172#[derive(Debug, Clone)]
173pub struct VTable {
174    /// Trait names this vtable implements
175    pub trait_names: Vec<String>,
176    /// Map from method name to function ID (bytecode offset or closure)
177    pub methods: HashMap<String, VTableEntry>,
178}
179
180/// An entry in a vtable — how to dispatch a method call
181#[derive(Debug, Clone)]
182pub enum VTableEntry {
183    /// A compiled function by ID
184    FunctionId(u16),
185    /// A closure with captured upvalues
186    Closure {
187        function_id: u16,
188        upvalues: Vec<Upvalue>,
189    },
190}
191
192/// Create a VMArray from an iterator of ValueWord values.
193pub fn vmarray_from_value_words(iter: impl IntoIterator<Item = ValueWord>) -> VMArray {
194    Arc::new(iter.into_iter().collect())
195}
196
197/// Backward-compatibility alias.
198pub fn vmarray_from_nanboxed(iter: impl IntoIterator<Item = ValueWord>) -> VMArray {
199    vmarray_from_value_words(iter)
200}