formualizer_eval/engine/arena/
value_ref.rs

1/// Unified value reference type with bit-packed layout
2///
3/// Bit layout (32 bits):
4/// [31:28] Value Type (4 bits)
5/// [27:0]  Payload (28 bits)
6use std::fmt;
7
8/// Type of value stored in the reference
9#[repr(u8)]
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ValueType {
12    Empty = 0,
13    SmallInt = 1, // Inline i28
14    LargeInt = 2, // Index into scalar arena (integers)
15    Number = 3,   // Index into scalar arena (floats)
16    String = 4,   // Index into string interner
17    Boolean = 5,  // Inline boolean (bit 0)
18    Error = 6,    // Error code in bits [27:24]
19    Array = 7,    // Index into array arena
20    DateTime = 8, // Serial number in scalar arena
21    Duration = 9, // Nanoseconds in scalar arena
22    Pending = 10, // Pending evaluation marker
23    FormulaAst = 11, // Index into AST arena
24                  // 12-15 reserved for future use
25}
26
27impl ValueType {
28    fn from_bits(bits: u8) -> Option<Self> {
29        match bits {
30            0 => Some(ValueType::Empty),
31            1 => Some(ValueType::SmallInt),
32            2 => Some(ValueType::LargeInt),
33            3 => Some(ValueType::Number),
34            4 => Some(ValueType::String),
35            5 => Some(ValueType::Boolean),
36            6 => Some(ValueType::Error),
37            7 => Some(ValueType::Array),
38            8 => Some(ValueType::DateTime),
39            9 => Some(ValueType::Duration),
40            10 => Some(ValueType::Pending),
41            11 => Some(ValueType::FormulaAst),
42            _ => None,
43        }
44    }
45}
46
47/// Unified reference to any value type
48#[derive(Copy, Clone, Eq, PartialEq, Hash)]
49pub struct ValueRef {
50    raw: u32,
51}
52
53impl ValueRef {
54    // Bit masks
55    const TYPE_SHIFT: u32 = 28;
56    const TYPE_MASK: u32 = 0xF0000000;
57    const PAYLOAD_MASK: u32 = 0x0FFFFFFF;
58
59    // Small int constants
60    const SMALL_INT_MAX: i32 = (1 << 27) - 1; // 2^27 - 1
61    const SMALL_INT_MIN: i32 = -(1 << 27); // -2^27
62    const SMALL_INT_SIGN_BIT: u32 = 1 << 27; // Sign bit for i28
63
64    /// Create an empty/uninitialized reference
65    pub const fn empty() -> Self {
66        Self { raw: 0 }
67    }
68
69    /// Create a reference from raw bits (for testing)
70    #[cfg(test)]
71    pub const fn from_raw(raw: u32) -> Self {
72        Self { raw }
73    }
74
75    /// Get the raw bits
76    pub const fn as_raw(self) -> u32 {
77        self.raw
78    }
79
80    /// Get the value type
81    pub fn value_type(self) -> ValueType {
82        let type_bits = ((self.raw & Self::TYPE_MASK) >> Self::TYPE_SHIFT) as u8;
83        ValueType::from_bits(type_bits).unwrap_or(ValueType::Empty)
84    }
85
86    /// Get the payload (lower 28 bits)
87    fn payload(self) -> u32 {
88        self.raw & Self::PAYLOAD_MASK
89    }
90
91    /// Check if this is an empty reference
92    pub fn is_empty(self) -> bool {
93        self.raw == 0
94    }
95
96    /// Create a small integer reference (fits in 28 bits with sign)
97    pub fn small_int(value: i32) -> Option<Self> {
98        if (Self::SMALL_INT_MIN..=Self::SMALL_INT_MAX).contains(&value) {
99            // Pack the signed integer into 28 bits
100            let payload = (value as u32) & Self::PAYLOAD_MASK;
101            Some(Self {
102                raw: (ValueType::SmallInt as u32) << Self::TYPE_SHIFT | payload,
103            })
104        } else {
105            None
106        }
107    }
108
109    /// Extract a small integer value
110    pub fn as_small_int(self) -> Option<i32> {
111        if self.value_type() == ValueType::SmallInt {
112            let payload = self.payload();
113            // Sign-extend from 28 bits to 32 bits
114            if payload & Self::SMALL_INT_SIGN_BIT != 0 {
115                // Negative number - set upper bits
116                Some((payload | !Self::PAYLOAD_MASK) as i32)
117            } else {
118                // Positive number
119                Some(payload as i32)
120            }
121        } else {
122            None
123        }
124    }
125
126    /// Create a boolean reference
127    pub fn boolean(value: bool) -> Self {
128        Self {
129            raw: (ValueType::Boolean as u32) << Self::TYPE_SHIFT | (value as u32),
130        }
131    }
132
133    /// Extract a boolean value
134    pub fn as_boolean(self) -> Option<bool> {
135        if self.value_type() == ValueType::Boolean {
136            Some(self.payload() & 1 != 0)
137        } else {
138            None
139        }
140    }
141
142    /// Create an error reference with an ErrorRef index
143    pub fn error(error_ref: u32) -> Self {
144        assert!(
145            error_ref <= Self::PAYLOAD_MASK,
146            "ErrorRef must fit in 28 bits"
147        );
148        Self {
149            raw: (ValueType::Error as u32) << Self::TYPE_SHIFT | error_ref,
150        }
151    }
152
153    /// Extract an error reference
154    pub fn as_error_ref(self) -> Option<u32> {
155        if self.value_type() == ValueType::Error {
156            Some(self.payload())
157        } else {
158            None
159        }
160    }
161
162    /// Create a pending reference
163    pub fn pending() -> Self {
164        Self {
165            raw: (ValueType::Pending as u32) << Self::TYPE_SHIFT,
166        }
167    }
168
169    /// Create a reference to a large integer in the scalar arena
170    pub fn large_int(index: u32) -> Self {
171        assert!(index <= Self::PAYLOAD_MASK, "Large int index overflow");
172        Self {
173            raw: (ValueType::LargeInt as u32) << Self::TYPE_SHIFT | index,
174        }
175    }
176
177    /// Create a reference to a number in the scalar arena
178    pub fn number(index: u32) -> Self {
179        assert!(index <= Self::PAYLOAD_MASK, "Number index overflow");
180        Self {
181            raw: (ValueType::Number as u32) << Self::TYPE_SHIFT | index,
182        }
183    }
184
185    /// Create a reference to a string in the interner
186    pub fn string(index: u32) -> Self {
187        assert!(index <= Self::PAYLOAD_MASK, "String index overflow");
188        Self {
189            raw: (ValueType::String as u32) << Self::TYPE_SHIFT | index,
190        }
191    }
192
193    /// Create a reference to an array
194    pub fn array(index: u32) -> Self {
195        assert!(index <= Self::PAYLOAD_MASK, "Array index overflow");
196        Self {
197            raw: (ValueType::Array as u32) << Self::TYPE_SHIFT | index,
198        }
199    }
200
201    /// Create a reference to a date/time serial number
202    pub fn date_time(index: u32) -> Self {
203        assert!(index <= Self::PAYLOAD_MASK, "DateTime index overflow");
204        Self {
205            raw: (ValueType::DateTime as u32) << Self::TYPE_SHIFT | index,
206        }
207    }
208
209    /// Create a reference to a duration
210    pub fn duration(index: u32) -> Self {
211        assert!(index <= Self::PAYLOAD_MASK, "Duration index overflow");
212        Self {
213            raw: (ValueType::Duration as u32) << Self::TYPE_SHIFT | index,
214        }
215    }
216
217    /// Create a reference to an AST node
218    pub fn formula_ast(index: u32) -> Self {
219        assert!(index <= Self::PAYLOAD_MASK, "AST index overflow");
220        Self {
221            raw: (ValueType::FormulaAst as u32) << Self::TYPE_SHIFT | index,
222        }
223    }
224
225    /// Get the arena index for types that use external storage
226    pub fn arena_index(self) -> Option<u32> {
227        match self.value_type() {
228            ValueType::LargeInt
229            | ValueType::Number
230            | ValueType::String
231            | ValueType::Array
232            | ValueType::DateTime
233            | ValueType::Duration
234            | ValueType::FormulaAst => Some(self.payload()),
235            _ => None,
236        }
237    }
238}
239
240impl fmt::Debug for ValueRef {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        match self.value_type() {
243            ValueType::Empty => write!(f, "Empty"),
244            ValueType::SmallInt => {
245                if let Some(v) = self.as_small_int() {
246                    write!(f, "SmallInt({v})")
247                } else {
248                    write!(f, "SmallInt(?)")
249                }
250            }
251            ValueType::Boolean => {
252                if let Some(v) = self.as_boolean() {
253                    write!(f, "Boolean({v})")
254                } else {
255                    write!(f, "Boolean(?)")
256                }
257            }
258            ValueType::Error => {
259                if let Some(code) = self.as_error_ref() {
260                    write!(f, "Error(code={code})")
261                } else {
262                    write!(f, "Error(?)")
263                }
264            }
265            ValueType::Pending => write!(f, "Pending"),
266            vt => write!(f, "{:?}(idx={})", vt, self.payload()),
267        }
268    }
269}
270
271impl Default for ValueRef {
272    fn default() -> Self {
273        Self::empty()
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use super::*;
280
281    #[test]
282    fn test_value_ref_empty() {
283        let vref = ValueRef::empty();
284        assert!(vref.is_empty());
285        assert_eq!(vref.value_type(), ValueType::Empty);
286        assert_eq!(vref.as_raw(), 0);
287    }
288
289    #[test]
290    fn test_value_ref_small_int() {
291        // Test positive small int
292        let vref = ValueRef::small_int(42).unwrap();
293        assert_eq!(vref.value_type(), ValueType::SmallInt);
294        assert_eq!(vref.as_small_int(), Some(42));
295
296        // Test negative small int
297        let vref = ValueRef::small_int(-100).unwrap();
298        assert_eq!(vref.as_small_int(), Some(-100));
299
300        // Test boundary values
301        let vref = ValueRef::small_int(ValueRef::SMALL_INT_MAX).unwrap();
302        assert_eq!(vref.as_small_int(), Some(ValueRef::SMALL_INT_MAX));
303
304        let vref = ValueRef::small_int(ValueRef::SMALL_INT_MIN).unwrap();
305        assert_eq!(vref.as_small_int(), Some(ValueRef::SMALL_INT_MIN));
306
307        // Test overflow
308        assert!(ValueRef::small_int(ValueRef::SMALL_INT_MAX + 1).is_none());
309        assert!(ValueRef::small_int(ValueRef::SMALL_INT_MIN - 1).is_none());
310    }
311
312    #[test]
313    fn test_value_ref_boolean() {
314        let true_ref = ValueRef::boolean(true);
315        assert_eq!(true_ref.value_type(), ValueType::Boolean);
316        assert_eq!(true_ref.as_boolean(), Some(true));
317
318        let false_ref = ValueRef::boolean(false);
319        assert_eq!(false_ref.value_type(), ValueType::Boolean);
320        assert_eq!(false_ref.as_boolean(), Some(false));
321    }
322
323    #[test]
324    fn test_value_ref_error() {
325        let error_ref = ValueRef::error(5);
326        assert_eq!(error_ref.value_type(), ValueType::Error);
327        assert_eq!(error_ref.as_error_ref(), Some(5));
328
329        // Test larger values within 28-bit range
330        let error_ref = ValueRef::error(1000);
331        assert_eq!(error_ref.as_error_ref(), Some(1000));
332    }
333
334    #[test]
335    fn test_value_ref_pending() {
336        let pending = ValueRef::pending();
337        assert_eq!(pending.value_type(), ValueType::Pending);
338        assert!(!pending.is_empty());
339    }
340
341    #[test]
342    fn test_value_ref_arena_types() {
343        let large_int = ValueRef::large_int(100);
344        assert_eq!(large_int.value_type(), ValueType::LargeInt);
345        assert_eq!(large_int.arena_index(), Some(100));
346
347        let number = ValueRef::number(200);
348        assert_eq!(number.value_type(), ValueType::Number);
349        assert_eq!(number.arena_index(), Some(200));
350
351        let string = ValueRef::string(300);
352        assert_eq!(string.value_type(), ValueType::String);
353        assert_eq!(string.arena_index(), Some(300));
354
355        let array = ValueRef::array(400);
356        assert_eq!(array.value_type(), ValueType::Array);
357        assert_eq!(array.arena_index(), Some(400));
358
359        let ast = ValueRef::formula_ast(500);
360        assert_eq!(ast.value_type(), ValueType::FormulaAst);
361        assert_eq!(ast.arena_index(), Some(500));
362    }
363
364    #[test]
365    fn test_value_ref_type_checking() {
366        let int_ref = ValueRef::small_int(42).unwrap();
367        assert!(int_ref.as_boolean().is_none());
368        assert!(int_ref.as_error_ref().is_none());
369
370        let bool_ref = ValueRef::boolean(true);
371        assert!(bool_ref.as_small_int().is_none());
372        assert!(bool_ref.as_error_ref().is_none());
373    }
374
375    #[test]
376    fn test_value_ref_debug() {
377        assert_eq!(format!("{:?}", ValueRef::empty()), "Empty");
378        assert_eq!(
379            format!("{:?}", ValueRef::small_int(42).unwrap()),
380            "SmallInt(42)"
381        );
382        assert_eq!(format!("{:?}", ValueRef::boolean(true)), "Boolean(true)");
383        assert_eq!(format!("{:?}", ValueRef::error(5)), "Error(code=5)");
384        assert_eq!(format!("{:?}", ValueRef::pending()), "Pending");
385        assert_eq!(format!("{:?}", ValueRef::number(100)), "Number(idx=100)");
386    }
387
388    #[test]
389    fn test_value_ref_sign_extension() {
390        // Test that negative numbers are properly sign-extended
391        let neg_one = ValueRef::small_int(-1).unwrap();
392        assert_eq!(neg_one.as_small_int(), Some(-1));
393
394        let large_neg = ValueRef::small_int(-1000000).unwrap();
395        assert_eq!(large_neg.as_small_int(), Some(-1000000));
396
397        // Test edge case near sign bit
398        let near_boundary = ValueRef::small_int((1 << 26) - 1).unwrap();
399        assert_eq!(near_boundary.as_small_int(), Some((1 << 26) - 1));
400    }
401
402    #[test]
403    #[should_panic(expected = "Array index overflow")]
404    fn test_value_ref_index_overflow() {
405        ValueRef::array(0x10000000); // 28 bits + 1
406    }
407}