1use crate::content::ContentNode;
34use crate::datatable::DataTable;
35use crate::enums::EnumValue;
36use crate::heap_value::{
37 ChannelData, DequeData, HashMapData, HeapValue, NativeScalar, NativeTypeLayout, NativeViewData,
38 PriorityQueueData, SetData,
39};
40use crate::slot::ValueSlot;
41use crate::value::{FilterNode, HostCallable, PrintResult, VMArray, VTable};
42use chrono::{DateTime, FixedOffset, Utc};
43use shape_ast::ast::{DataDateTimeRef, DateTimeExpr, Duration, TimeReference, TypeAnnotation};
44use shape_ast::data::Timeframe;
45use std::collections::HashMap;
46use std::sync::Arc;
47
48use crate::tags::{
50 CANONICAL_NAN, I48_MAX, I48_MIN, PAYLOAD_MASK, TAG_BOOL, TAG_FUNCTION, TAG_HEAP, TAG_INT,
51 TAG_MODULE_FN, TAG_NONE, TAG_REF, TAG_UNIT, get_payload, get_tag, is_tagged, make_tagged,
52 sign_extend_i48,
53};
54
55macro_rules! define_nan_tag_types {
65 () => {
66 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
70 pub enum NanTag {
71 F64,
73 I48,
75 Bool,
77 None,
79 Unit,
81 Function,
83 ModuleFunction,
85 Heap,
87 Ref,
89 }
90
91 #[inline]
95 fn nan_tag_type_name(tag: u64) -> &'static str {
96 match tag {
97 TAG_INT => "int",
98 TAG_BOOL => "bool",
99 TAG_NONE => "option",
100 TAG_UNIT => "unit",
101 TAG_FUNCTION => "function",
102 TAG_MODULE_FN => "module_function",
103 TAG_REF => "reference",
104 _ => "unknown",
105 }
106 }
107
108 #[inline]
112 fn nan_tag_is_truthy(tag: u64, payload: u64) -> bool {
113 match tag {
114 TAG_INT => sign_extend_i48(payload) != 0,
115 TAG_BOOL => payload != 0,
116 TAG_NONE => false,
117 TAG_UNIT => false,
118 TAG_FUNCTION | TAG_MODULE_FN | TAG_REF => true,
119 _ => true,
120 }
121 }
122 };
123}
124
125define_nan_tag_types!();
126
127#[derive(Debug)]
135pub enum ArrayView<'a> {
136 Generic(&'a Arc<Vec<ValueWord>>),
137 Int(&'a Arc<crate::typed_buffer::TypedBuffer<i64>>),
138 Float(&'a Arc<crate::typed_buffer::AlignedTypedBuffer>),
139 Bool(&'a Arc<crate::typed_buffer::TypedBuffer<u8>>),
140 I8(&'a Arc<crate::typed_buffer::TypedBuffer<i8>>),
141 I16(&'a Arc<crate::typed_buffer::TypedBuffer<i16>>),
142 I32(&'a Arc<crate::typed_buffer::TypedBuffer<i32>>),
143 U8(&'a Arc<crate::typed_buffer::TypedBuffer<u8>>),
144 U16(&'a Arc<crate::typed_buffer::TypedBuffer<u16>>),
145 U32(&'a Arc<crate::typed_buffer::TypedBuffer<u32>>),
146 U64(&'a Arc<crate::typed_buffer::TypedBuffer<u64>>),
147 F32(&'a Arc<crate::typed_buffer::TypedBuffer<f32>>),
148}
149
150impl<'a> ArrayView<'a> {
151 #[inline]
152 pub fn len(&self) -> usize {
153 match self {
154 ArrayView::Generic(a) => a.len(),
155 ArrayView::Int(a) => a.len(),
156 ArrayView::Float(a) => a.len(),
157 ArrayView::Bool(a) => a.len(),
158 ArrayView::I8(a) => a.len(),
159 ArrayView::I16(a) => a.len(),
160 ArrayView::I32(a) => a.len(),
161 ArrayView::U8(a) => a.len(),
162 ArrayView::U16(a) => a.len(),
163 ArrayView::U32(a) => a.len(),
164 ArrayView::U64(a) => a.len(),
165 ArrayView::F32(a) => a.len(),
166 }
167 }
168
169 #[inline]
170 pub fn is_empty(&self) -> bool {
171 self.len() == 0
172 }
173
174 #[inline]
176 pub fn get_nb(&self, idx: usize) -> Option<ValueWord> {
177 match self {
178 ArrayView::Generic(a) => a.get(idx).cloned(),
179 ArrayView::Int(a) => a.get(idx).map(|&i| ValueWord::from_i64(i)),
180 ArrayView::Float(a) => a.get(idx).map(|&f| ValueWord::from_f64(f)),
181 ArrayView::Bool(a) => a.get(idx).map(|&b| ValueWord::from_bool(b != 0)),
182 ArrayView::I8(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
183 ArrayView::I16(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
184 ArrayView::I32(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
185 ArrayView::U8(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
186 ArrayView::U16(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
187 ArrayView::U32(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
188 ArrayView::U64(a) => a.get(idx).map(|&v| {
189 if v <= i64::MAX as u64 {
190 ValueWord::from_i64(v as i64)
191 } else {
192 ValueWord::from_native_u64(v)
193 }
194 }),
195 ArrayView::F32(a) => a.get(idx).map(|&v| ValueWord::from_f64(v as f64)),
196 }
197 }
198
199 #[inline]
200 pub fn first_nb(&self) -> Option<ValueWord> {
201 self.get_nb(0)
202 }
203
204 #[inline]
205 pub fn last_nb(&self) -> Option<ValueWord> {
206 if self.is_empty() {
207 None
208 } else {
209 self.get_nb(self.len() - 1)
210 }
211 }
212
213 pub fn to_generic(&self) -> Arc<Vec<ValueWord>> {
215 match self {
216 ArrayView::Generic(a) => (*a).clone(),
217 ArrayView::Int(a) => Arc::new(a.iter().map(|&i| ValueWord::from_i64(i)).collect()),
218 ArrayView::Float(a) => Arc::new(
219 a.as_slice()
220 .iter()
221 .map(|&f| ValueWord::from_f64(f))
222 .collect(),
223 ),
224 ArrayView::Bool(a) => {
225 Arc::new(a.iter().map(|&b| ValueWord::from_bool(b != 0)).collect())
226 }
227 ArrayView::I8(a) => {
228 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
229 }
230 ArrayView::I16(a) => {
231 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
232 }
233 ArrayView::I32(a) => {
234 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
235 }
236 ArrayView::U8(a) => {
237 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
238 }
239 ArrayView::U16(a) => {
240 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
241 }
242 ArrayView::U32(a) => {
243 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
244 }
245 ArrayView::U64(a) => Arc::new(
246 a.iter()
247 .map(|&v| {
248 if v <= i64::MAX as u64 {
249 ValueWord::from_i64(v as i64)
250 } else {
251 ValueWord::from_native_u64(v)
252 }
253 })
254 .collect(),
255 ),
256 ArrayView::F32(a) => {
257 Arc::new(a.iter().map(|&v| ValueWord::from_f64(v as f64)).collect())
258 }
259 }
260 }
261
262 #[inline]
263 pub fn as_i64_slice(&self) -> Option<&[i64]> {
264 if let ArrayView::Int(a) = self {
265 Some(a.as_slice())
266 } else {
267 None
268 }
269 }
270
271 #[inline]
272 pub fn as_f64_slice(&self) -> Option<&[f64]> {
273 if let ArrayView::Float(a) = self {
274 Some(a.as_slice())
275 } else {
276 None
277 }
278 }
279
280 #[inline]
281 pub fn as_bool_slice(&self) -> Option<&[u8]> {
282 if let ArrayView::Bool(a) = self {
283 Some(a.as_slice())
284 } else {
285 None
286 }
287 }
288
289 #[inline]
290 pub fn as_generic(&self) -> Option<&Arc<Vec<ValueWord>>> {
291 if let ArrayView::Generic(a) = self {
292 Some(a)
293 } else {
294 None
295 }
296 }
297
298 #[inline]
299 pub fn iter_i64(&self) -> Option<std::slice::Iter<'_, i64>> {
300 if let ArrayView::Int(a) = self {
301 Some(a.iter())
302 } else {
303 None
304 }
305 }
306
307 #[inline]
308 pub fn iter_f64(&self) -> Option<std::slice::Iter<'_, f64>> {
309 if let ArrayView::Float(a) = self {
310 Some(a.as_slice().iter())
311 } else {
312 None
313 }
314 }
315}
316
317pub enum ArrayViewMut<'a> {
319 Generic(&'a mut Arc<Vec<ValueWord>>),
320 Int(&'a mut Arc<crate::typed_buffer::TypedBuffer<i64>>),
321 Float(&'a mut Arc<crate::typed_buffer::AlignedTypedBuffer>),
322 Bool(&'a mut Arc<crate::typed_buffer::TypedBuffer<u8>>),
323}
324
325impl ArrayViewMut<'_> {
326 #[inline]
327 pub fn len(&self) -> usize {
328 match self {
329 ArrayViewMut::Generic(a) => a.len(),
330 ArrayViewMut::Int(a) => a.len(),
331 ArrayViewMut::Float(a) => a.len(),
332 ArrayViewMut::Bool(a) => a.len(),
333 }
334 }
335
336 pub fn pop_vw(&mut self) -> Option<ValueWord> {
337 match self {
338 ArrayViewMut::Generic(a) => Arc::make_mut(a).pop(),
339 ArrayViewMut::Int(a) => Arc::make_mut(a).data.pop().map(ValueWord::from_i64),
340 ArrayViewMut::Float(a) => Arc::make_mut(a).pop().map(ValueWord::from_f64),
341 ArrayViewMut::Bool(a) => Arc::make_mut(a)
342 .data
343 .pop()
344 .map(|b| ValueWord::from_bool(b != 0)),
345 }
346 }
347
348 pub fn push_vw(&mut self, val: ValueWord) -> Result<(), crate::context::VMError> {
349 match self {
350 ArrayViewMut::Generic(a) => {
351 Arc::make_mut(a).push(val);
352 Ok(())
353 }
354 ArrayViewMut::Int(a) => {
355 if let Some(i) = val.as_i64() {
356 Arc::make_mut(a).push(i);
357 Ok(())
358 } else {
359 Err(crate::context::VMError::TypeError {
360 expected: "int",
361 got: val.type_name(),
362 })
363 }
364 }
365 ArrayViewMut::Float(a) => {
366 if let Some(f) = val.as_number_coerce() {
367 Arc::make_mut(a).push(f);
368 Ok(())
369 } else {
370 Err(crate::context::VMError::TypeError {
371 expected: "number",
372 got: val.type_name(),
373 })
374 }
375 }
376 ArrayViewMut::Bool(a) => {
377 if let Some(b) = val.as_bool() {
378 Arc::make_mut(a).push(if b { 1 } else { 0 });
379 Ok(())
380 } else {
381 Err(crate::context::VMError::TypeError {
382 expected: "bool",
383 got: val.type_name(),
384 })
385 }
386 }
387 }
388 }
389}
390
391#[repr(transparent)]
397pub struct ValueWord(u64);
398
399impl ValueWord {
400 #[inline]
407 pub fn from_f64(v: f64) -> Self {
408 let bits = v.to_bits();
409 if v.is_nan() {
410 Self(CANONICAL_NAN)
412 } else if is_tagged(bits) {
413 Self(CANONICAL_NAN)
418 } else {
419 Self(bits)
420 }
421 }
422
423 #[inline]
428 pub fn from_i64(v: i64) -> Self {
429 if v >= I48_MIN && v <= I48_MAX {
430 let payload = (v as u64) & PAYLOAD_MASK;
433 Self(make_tagged(TAG_INT, payload))
434 } else {
435 Self::heap_box(HeapValue::BigInt(v))
437 }
438 }
439
440 #[inline]
442 pub fn from_native_scalar(value: NativeScalar) -> Self {
443 Self::heap_box(HeapValue::NativeScalar(value))
444 }
445
446 #[inline]
447 pub fn from_native_i8(v: i8) -> Self {
448 Self::from_native_scalar(NativeScalar::I8(v))
449 }
450
451 #[inline]
452 pub fn from_native_u8(v: u8) -> Self {
453 Self::from_native_scalar(NativeScalar::U8(v))
454 }
455
456 #[inline]
457 pub fn from_native_i16(v: i16) -> Self {
458 Self::from_native_scalar(NativeScalar::I16(v))
459 }
460
461 #[inline]
462 pub fn from_native_u16(v: u16) -> Self {
463 Self::from_native_scalar(NativeScalar::U16(v))
464 }
465
466 #[inline]
467 pub fn from_native_i32(v: i32) -> Self {
468 Self::from_native_scalar(NativeScalar::I32(v))
469 }
470
471 #[inline]
472 pub fn from_native_u32(v: u32) -> Self {
473 Self::from_native_scalar(NativeScalar::U32(v))
474 }
475
476 #[inline]
477 pub fn from_native_u64(v: u64) -> Self {
478 Self::from_native_scalar(NativeScalar::U64(v))
479 }
480
481 #[inline]
482 pub fn from_native_isize(v: isize) -> Self {
483 Self::from_native_scalar(NativeScalar::Isize(v))
484 }
485
486 #[inline]
487 pub fn from_native_usize(v: usize) -> Self {
488 Self::from_native_scalar(NativeScalar::Usize(v))
489 }
490
491 #[inline]
492 pub fn from_native_ptr(v: usize) -> Self {
493 Self::from_native_scalar(NativeScalar::Ptr(v))
494 }
495
496 #[inline]
497 pub fn from_native_f32(v: f32) -> Self {
498 Self::from_native_scalar(NativeScalar::F32(v))
499 }
500
501 #[inline]
503 pub fn from_c_view(ptr: usize, layout: Arc<NativeTypeLayout>) -> Self {
504 Self::heap_box(HeapValue::NativeView(Box::new(NativeViewData {
505 ptr,
506 layout,
507 mutable: false,
508 })))
509 }
510
511 #[inline]
513 pub fn from_c_mut(ptr: usize, layout: Arc<NativeTypeLayout>) -> Self {
514 Self::heap_box(HeapValue::NativeView(Box::new(NativeViewData {
515 ptr,
516 layout,
517 mutable: true,
518 })))
519 }
520
521 #[inline]
523 pub fn from_bool(v: bool) -> Self {
524 Self(make_tagged(TAG_BOOL, v as u64))
525 }
526
527 #[inline]
529 pub fn none() -> Self {
530 Self(make_tagged(TAG_NONE, 0))
531 }
532
533 #[inline]
535 pub fn unit() -> Self {
536 Self(make_tagged(TAG_UNIT, 0))
537 }
538
539 #[inline]
544 pub fn from_function(id: u16) -> Self {
545 Self(make_tagged(TAG_FUNCTION, id as u64))
546 }
547
548 #[inline]
550 pub fn from_module_function(index: u32) -> Self {
551 Self(make_tagged(TAG_MODULE_FN, index as u64))
552 }
553
554 #[inline]
560 pub fn from_ref(absolute_slot: usize) -> Self {
561 Self(make_tagged(TAG_REF, absolute_slot as u64))
562 }
563
564 #[inline]
569 #[cfg(not(feature = "gc"))]
570 pub(crate) fn heap_box(v: HeapValue) -> Self {
571 let arc = Arc::new(v);
572 let ptr = Arc::into_raw(arc) as u64;
573 debug_assert!(
574 ptr & !PAYLOAD_MASK == 0,
575 "pointer exceeds 48 bits — platform not supported"
576 );
577 Self(make_tagged(TAG_HEAP, ptr & PAYLOAD_MASK))
578 }
579
580 #[inline]
584 #[cfg(feature = "gc")]
585 pub(crate) fn heap_box(v: HeapValue) -> Self {
586 let heap = shape_gc::thread_gc_heap();
587 let ptr = heap.alloc(v) as u64;
588 debug_assert!(
589 ptr & !PAYLOAD_MASK == 0,
590 "GC pointer exceeds 48 bits — platform not supported"
591 );
592 Self(make_tagged(TAG_HEAP, ptr & PAYLOAD_MASK))
593 }
594
595 #[inline]
599 pub fn from_string(s: Arc<String>) -> Self {
600 Self::heap_box(HeapValue::String(s))
601 }
602
603 #[inline]
605 pub fn from_array(a: crate::value::VMArray) -> Self {
606 Self::heap_box(HeapValue::Array(a))
607 }
608
609 #[inline]
611 pub fn from_decimal(d: rust_decimal::Decimal) -> Self {
612 Self::heap_box(HeapValue::Decimal(d))
613 }
614
615 #[inline]
620 pub fn from_heap_value(v: HeapValue) -> Self {
621 match v {
622 HeapValue::BigInt(i) => Self::from_i64(i),
623 other => Self::heap_box(other),
624 }
625 }
626
627 #[inline]
631 pub fn from_datatable(dt: Arc<DataTable>) -> Self {
632 Self::heap_box(HeapValue::DataTable(dt))
633 }
634
635 #[inline]
637 pub fn from_typed_table(schema_id: u64, table: Arc<DataTable>) -> Self {
638 Self::heap_box(HeapValue::TypedTable { schema_id, table })
639 }
640
641 #[inline]
643 pub fn from_row_view(schema_id: u64, table: Arc<DataTable>, row_idx: usize) -> Self {
644 Self::heap_box(HeapValue::RowView {
645 schema_id,
646 table,
647 row_idx,
648 })
649 }
650
651 #[inline]
653 pub fn from_column_ref(schema_id: u64, table: Arc<DataTable>, col_id: u32) -> Self {
654 Self::heap_box(HeapValue::ColumnRef {
655 schema_id,
656 table,
657 col_id,
658 })
659 }
660
661 #[inline]
663 pub fn from_indexed_table(schema_id: u64, table: Arc<DataTable>, index_col: u32) -> Self {
664 Self::heap_box(HeapValue::IndexedTable {
665 schema_id,
666 table,
667 index_col,
668 })
669 }
670
671 #[inline]
675 pub fn from_range(start: Option<ValueWord>, end: Option<ValueWord>, inclusive: bool) -> Self {
676 Self::heap_box(HeapValue::Range {
677 start: start.map(Box::new),
678 end: end.map(Box::new),
679 inclusive,
680 })
681 }
682
683 #[inline]
685 pub fn from_enum(e: EnumValue) -> Self {
686 Self::heap_box(HeapValue::Enum(Box::new(e)))
687 }
688
689 #[inline]
691 pub fn from_some(inner: ValueWord) -> Self {
692 Self::heap_box(HeapValue::Some(Box::new(inner)))
693 }
694
695 #[inline]
697 pub fn from_ok(inner: ValueWord) -> Self {
698 Self::heap_box(HeapValue::Ok(Box::new(inner)))
699 }
700
701 #[inline]
703 pub fn from_err(inner: ValueWord) -> Self {
704 Self::heap_box(HeapValue::Err(Box::new(inner)))
705 }
706
707 #[inline]
711 pub fn from_hashmap(
712 keys: Vec<ValueWord>,
713 values: Vec<ValueWord>,
714 index: HashMap<u64, Vec<usize>>,
715 ) -> ValueWord {
716 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
717 keys,
718 values,
719 index,
720 shape_id: None,
721 })))
722 }
723
724 #[inline]
726 pub fn empty_hashmap() -> ValueWord {
727 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
728 keys: Vec::new(),
729 values: Vec::new(),
730 index: HashMap::new(),
731 shape_id: None,
732 })))
733 }
734
735 #[inline]
738 pub fn from_hashmap_pairs(keys: Vec<ValueWord>, values: Vec<ValueWord>) -> ValueWord {
739 let index = HashMapData::rebuild_index(&keys);
740 let shape_id = HashMapData::compute_shape(&keys);
741 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
742 keys,
743 values,
744 index,
745 shape_id,
746 })))
747 }
748
749 #[inline]
753 pub fn from_set(items: Vec<ValueWord>) -> ValueWord {
754 ValueWord::heap_box(HeapValue::Set(Box::new(SetData::from_items(items))))
755 }
756
757 #[inline]
759 pub fn empty_set() -> ValueWord {
760 ValueWord::heap_box(HeapValue::Set(Box::new(SetData {
761 items: Vec::new(),
762 index: HashMap::new(),
763 })))
764 }
765
766 #[inline]
770 pub fn from_deque(items: Vec<ValueWord>) -> ValueWord {
771 ValueWord::heap_box(HeapValue::Deque(Box::new(DequeData::from_items(items))))
772 }
773
774 #[inline]
776 pub fn empty_deque() -> ValueWord {
777 ValueWord::heap_box(HeapValue::Deque(Box::new(DequeData::new())))
778 }
779
780 #[inline]
784 pub fn from_priority_queue(items: Vec<ValueWord>) -> ValueWord {
785 ValueWord::heap_box(HeapValue::PriorityQueue(Box::new(
786 PriorityQueueData::from_items(items),
787 )))
788 }
789
790 #[inline]
792 pub fn empty_priority_queue() -> ValueWord {
793 ValueWord::heap_box(HeapValue::PriorityQueue(Box::new(PriorityQueueData::new())))
794 }
795
796 #[inline]
800 pub fn from_content(node: ContentNode) -> ValueWord {
801 ValueWord::heap_box(HeapValue::Content(Box::new(node)))
802 }
803
804 #[inline]
808 pub fn from_int_array(a: Arc<crate::typed_buffer::TypedBuffer<i64>>) -> Self {
809 Self::heap_box(HeapValue::IntArray(a))
810 }
811
812 #[inline]
814 pub fn from_float_array(a: Arc<crate::typed_buffer::AlignedTypedBuffer>) -> Self {
815 Self::heap_box(HeapValue::FloatArray(a))
816 }
817
818 #[inline]
820 pub fn from_bool_array(a: Arc<crate::typed_buffer::TypedBuffer<u8>>) -> Self {
821 Self::heap_box(HeapValue::BoolArray(a))
822 }
823
824 #[inline]
826 pub fn from_i8_array(a: Arc<crate::typed_buffer::TypedBuffer<i8>>) -> Self {
827 Self::heap_box(HeapValue::I8Array(a))
828 }
829
830 #[inline]
832 pub fn from_i16_array(a: Arc<crate::typed_buffer::TypedBuffer<i16>>) -> Self {
833 Self::heap_box(HeapValue::I16Array(a))
834 }
835
836 #[inline]
838 pub fn from_i32_array(a: Arc<crate::typed_buffer::TypedBuffer<i32>>) -> Self {
839 Self::heap_box(HeapValue::I32Array(a))
840 }
841
842 #[inline]
844 pub fn from_u8_array(a: Arc<crate::typed_buffer::TypedBuffer<u8>>) -> Self {
845 Self::heap_box(HeapValue::U8Array(a))
846 }
847
848 #[inline]
850 pub fn from_u16_array(a: Arc<crate::typed_buffer::TypedBuffer<u16>>) -> Self {
851 Self::heap_box(HeapValue::U16Array(a))
852 }
853
854 #[inline]
856 pub fn from_u32_array(a: Arc<crate::typed_buffer::TypedBuffer<u32>>) -> Self {
857 Self::heap_box(HeapValue::U32Array(a))
858 }
859
860 #[inline]
862 pub fn from_u64_array(a: Arc<crate::typed_buffer::TypedBuffer<u64>>) -> Self {
863 Self::heap_box(HeapValue::U64Array(a))
864 }
865
866 #[inline]
868 pub fn from_f32_array(a: Arc<crate::typed_buffer::TypedBuffer<f32>>) -> Self {
869 Self::heap_box(HeapValue::F32Array(a))
870 }
871
872 #[inline]
874 pub fn from_matrix(m: Box<crate::heap_value::MatrixData>) -> Self {
875 Self::heap_box(HeapValue::Matrix(m))
876 }
877
878 #[inline]
880 pub fn from_iterator(state: Box<crate::heap_value::IteratorState>) -> Self {
881 Self::heap_box(HeapValue::Iterator(state))
882 }
883
884 #[inline]
886 pub fn from_generator(state: Box<crate::heap_value::GeneratorState>) -> Self {
887 Self::heap_box(HeapValue::Generator(state))
888 }
889
890 #[inline]
894 pub fn from_future(id: u64) -> Self {
895 Self::heap_box(HeapValue::Future(id))
896 }
897
898 #[inline]
900 pub fn from_task_group(kind: u8, task_ids: Vec<u64>) -> Self {
901 Self::heap_box(HeapValue::TaskGroup { kind, task_ids })
902 }
903
904 #[inline]
906 pub fn from_mutex(value: ValueWord) -> Self {
907 Self::heap_box(HeapValue::Mutex(Box::new(
908 crate::heap_value::MutexData::new(value),
909 )))
910 }
911
912 #[inline]
914 pub fn from_atomic(value: i64) -> Self {
915 Self::heap_box(HeapValue::Atomic(Box::new(
916 crate::heap_value::AtomicData::new(value),
917 )))
918 }
919
920 #[inline]
922 pub fn from_lazy(initializer: ValueWord) -> Self {
923 Self::heap_box(HeapValue::Lazy(Box::new(crate::heap_value::LazyData::new(
924 initializer,
925 ))))
926 }
927
928 #[inline]
930 pub fn from_channel(data: ChannelData) -> Self {
931 Self::heap_box(HeapValue::Channel(Box::new(data)))
932 }
933
934 #[inline]
938 pub fn from_trait_object(value: ValueWord, vtable: Arc<VTable>) -> Self {
939 Self::heap_box(HeapValue::TraitObject {
940 value: Box::new(value),
941 vtable,
942 })
943 }
944
945 #[inline]
949 pub fn from_expr_proxy(col_name: Arc<String>) -> Self {
950 Self::heap_box(HeapValue::ExprProxy(col_name))
951 }
952
953 #[inline]
955 pub fn from_filter_expr(node: Arc<FilterNode>) -> Self {
956 Self::heap_box(HeapValue::FilterExpr(node))
957 }
958
959 #[inline]
963 pub fn from_instant(t: std::time::Instant) -> Self {
964 Self::heap_box(HeapValue::Instant(Box::new(t)))
965 }
966
967 #[inline]
971 pub fn from_io_handle(data: crate::heap_value::IoHandleData) -> Self {
972 Self::heap_box(HeapValue::IoHandle(Box::new(data)))
973 }
974
975 #[inline]
979 pub fn from_time(t: DateTime<FixedOffset>) -> Self {
980 Self::heap_box(HeapValue::Time(t))
981 }
982
983 #[inline]
985 pub fn from_time_utc(t: DateTime<Utc>) -> Self {
986 Self::heap_box(HeapValue::Time(t.fixed_offset()))
987 }
988
989 #[inline]
991 pub fn from_duration(d: Duration) -> Self {
992 Self::heap_box(HeapValue::Duration(d))
993 }
994
995 #[inline]
997 pub fn from_timespan(ts: chrono::Duration) -> Self {
998 Self::heap_box(HeapValue::TimeSpan(ts))
999 }
1000
1001 #[inline]
1003 pub fn from_timeframe(tf: Timeframe) -> Self {
1004 Self::heap_box(HeapValue::Timeframe(tf))
1005 }
1006
1007 #[inline]
1011 pub fn from_host_closure(nc: HostCallable) -> Self {
1012 Self::heap_box(HeapValue::HostClosure(nc))
1013 }
1014
1015 #[inline]
1017 pub fn from_print_result(pr: PrintResult) -> Self {
1018 Self::heap_box(HeapValue::PrintResult(Box::new(pr)))
1019 }
1020
1021 #[inline]
1023 pub fn from_simulation_call(name: String, params: HashMap<String, ValueWord>) -> Self {
1024 Self::heap_box(HeapValue::SimulationCall(Box::new(
1025 crate::heap_value::SimulationCallData { name, params },
1026 )))
1027 }
1028
1029 #[inline]
1031 pub fn from_function_ref(name: String, closure: Option<ValueWord>) -> Self {
1032 Self::heap_box(HeapValue::FunctionRef {
1033 name,
1034 closure: closure.map(Box::new),
1035 })
1036 }
1037
1038 #[inline]
1040 pub fn from_data_reference(
1041 datetime: DateTime<FixedOffset>,
1042 id: String,
1043 timeframe: Timeframe,
1044 ) -> Self {
1045 Self::heap_box(HeapValue::DataReference(Box::new(
1046 crate::heap_value::DataReferenceData {
1047 datetime,
1048 id,
1049 timeframe,
1050 },
1051 )))
1052 }
1053
1054 #[inline]
1056 pub fn from_time_reference(tr: TimeReference) -> Self {
1057 Self::heap_box(HeapValue::TimeReference(Box::new(tr)))
1058 }
1059
1060 #[inline]
1062 pub fn from_datetime_expr(de: DateTimeExpr) -> Self {
1063 Self::heap_box(HeapValue::DateTimeExpr(Box::new(de)))
1064 }
1065
1066 #[inline]
1068 pub fn from_data_datetime_ref(dr: DataDateTimeRef) -> Self {
1069 Self::heap_box(HeapValue::DataDateTimeRef(Box::new(dr)))
1070 }
1071
1072 #[inline]
1074 pub fn from_type_annotation(ta: TypeAnnotation) -> Self {
1075 Self::heap_box(HeapValue::TypeAnnotation(Box::new(ta)))
1076 }
1077
1078 #[inline]
1080 pub fn from_type_annotated_value(type_name: String, value: ValueWord) -> Self {
1081 Self::heap_box(HeapValue::TypeAnnotatedValue {
1082 type_name,
1083 value: Box::new(value),
1084 })
1085 }
1086
1087 #[inline(always)]
1097 #[cfg(not(feature = "gc"))]
1098 pub unsafe fn clone_from_bits(bits: u64) -> Self {
1099 if is_tagged(bits) && get_tag(bits) == TAG_HEAP {
1100 let ptr = get_payload(bits) as *const HeapValue;
1101 unsafe { Arc::increment_strong_count(ptr) };
1102 }
1103 Self(bits)
1104 }
1105
1106 #[inline(always)]
1111 #[cfg(feature = "gc")]
1112 pub unsafe fn clone_from_bits(bits: u64) -> Self {
1113 Self(bits)
1115 }
1116
1117 #[inline(always)]
1121 pub fn is_f64(&self) -> bool {
1122 !is_tagged(self.0)
1123 }
1124
1125 #[inline(always)]
1127 pub fn is_i64(&self) -> bool {
1128 is_tagged(self.0) && get_tag(self.0) == TAG_INT
1129 }
1130
1131 #[inline(always)]
1133 pub fn is_bool(&self) -> bool {
1134 is_tagged(self.0) && get_tag(self.0) == TAG_BOOL
1135 }
1136
1137 #[inline(always)]
1139 pub fn is_none(&self) -> bool {
1140 is_tagged(self.0) && get_tag(self.0) == TAG_NONE
1141 }
1142
1143 #[inline(always)]
1145 pub fn is_unit(&self) -> bool {
1146 is_tagged(self.0) && get_tag(self.0) == TAG_UNIT
1147 }
1148
1149 #[inline(always)]
1151 pub fn is_function(&self) -> bool {
1152 is_tagged(self.0) && get_tag(self.0) == TAG_FUNCTION
1153 }
1154
1155 #[inline(always)]
1157 pub fn is_heap(&self) -> bool {
1158 is_tagged(self.0) && get_tag(self.0) == TAG_HEAP
1159 }
1160
1161 #[inline(always)]
1163 pub fn is_ref(&self) -> bool {
1164 is_tagged(self.0) && get_tag(self.0) == TAG_REF
1165 }
1166
1167 #[inline]
1170 pub fn as_ref_slot(&self) -> Option<usize> {
1171 if self.is_ref() {
1172 Some(get_payload(self.0) as usize)
1173 } else {
1174 None
1175 }
1176 }
1177
1178 #[inline]
1182 pub fn as_f64(&self) -> Option<f64> {
1183 if self.is_f64() {
1184 Some(f64::from_bits(self.0))
1185 } else {
1186 None
1187 }
1188 }
1189
1190 #[inline]
1194 pub fn as_i64(&self) -> Option<i64> {
1195 if self.is_i64() {
1196 Some(sign_extend_i48(get_payload(self.0)))
1197 } else if let Some(HeapValue::BigInt(v)) = self.as_heap_ref() {
1198 Some(*v)
1199 } else if let Some(HeapValue::NativeScalar(v)) = self.as_heap_ref() {
1200 v.as_i64()
1201 } else {
1202 None
1203 }
1204 }
1205
1206 #[inline]
1208 pub fn as_u64(&self) -> Option<u64> {
1209 if self.is_i64() {
1210 let v = sign_extend_i48(get_payload(self.0));
1211 return u64::try_from(v).ok();
1212 }
1213
1214 if let Some(hv) = self.as_heap_ref() {
1215 return match hv {
1216 HeapValue::BigInt(v) => u64::try_from(*v).ok(),
1217 HeapValue::NativeScalar(v) => v.as_u64(),
1218 _ => None,
1219 };
1220 }
1221
1222 None
1223 }
1224
1225 #[inline]
1227 pub fn as_i128_exact(&self) -> Option<i128> {
1228 if self.is_i64() {
1229 return Some(sign_extend_i48(get_payload(self.0)) as i128);
1230 }
1231
1232 if let Some(hv) = self.as_heap_ref() {
1233 return match hv {
1234 HeapValue::BigInt(v) => Some(*v as i128),
1235 HeapValue::NativeScalar(v) => v.as_i128(),
1236 _ => None,
1237 };
1238 }
1239
1240 None
1241 }
1242
1243 #[inline]
1245 pub fn as_number_strict(&self) -> Option<f64> {
1246 if self.is_f64() {
1247 return Some(f64::from_bits(self.0));
1248 }
1249 if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1251 return Some(sign_extend_i48(get_payload(self.0)) as f64);
1252 }
1253 if let Some(hv) = self.as_heap_ref() {
1254 return match hv {
1255 HeapValue::NativeScalar(NativeScalar::F32(v)) => Some(*v as f64),
1256 _ => None,
1257 };
1258 }
1259 None
1260 }
1261
1262 #[inline]
1264 pub fn as_bool(&self) -> Option<bool> {
1265 if self.is_bool() {
1266 Some(get_payload(self.0) != 0)
1267 } else {
1268 None
1269 }
1270 }
1271
1272 #[inline]
1274 pub fn as_function(&self) -> Option<u16> {
1275 if self.is_function() {
1276 Some(get_payload(self.0) as u16)
1277 } else {
1278 None
1279 }
1280 }
1281
1282 #[inline(always)]
1290 pub unsafe fn as_f64_unchecked(&self) -> f64 {
1291 if self.is_f64() {
1292 f64::from_bits(self.0)
1293 } else if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1294 sign_extend_i48(get_payload(self.0)) as f64
1295 } else {
1296 debug_assert!(false, "as_f64_unchecked on non-numeric ValueWord");
1297 0.0
1298 }
1299 }
1300
1301 #[inline(always)]
1307 pub unsafe fn as_i64_unchecked(&self) -> i64 {
1308 if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1309 sign_extend_i48(get_payload(self.0))
1310 } else if self.is_f64() {
1311 f64::from_bits(self.0) as i64
1312 } else {
1313 debug_assert!(false, "as_i64_unchecked on non-numeric ValueWord");
1314 0
1315 }
1316 }
1317
1318 #[inline(always)]
1323 pub unsafe fn as_bool_unchecked(&self) -> bool {
1324 debug_assert!(self.is_bool(), "as_bool_unchecked on non-bool ValueWord");
1325 get_payload(self.0) != 0
1326 }
1327
1328 #[inline(always)]
1333 pub unsafe fn as_function_unchecked(&self) -> u16 {
1334 debug_assert!(
1335 self.is_function(),
1336 "as_function_unchecked on non-function ValueWord"
1337 );
1338 get_payload(self.0) as u16
1339 }
1340
1341 #[inline]
1346 pub fn as_heap_ref(&self) -> Option<&HeapValue> {
1347 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1348 let ptr = get_payload(self.0) as *const HeapValue;
1349 Some(unsafe { &*ptr })
1350 } else {
1351 None
1352 }
1353 }
1354
1355 #[inline]
1361 #[cfg(not(feature = "gc"))]
1362 pub fn as_heap_mut(&mut self) -> Option<&mut HeapValue> {
1363 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1364 let ptr = get_payload(self.0) as *const HeapValue;
1365 let mut arc = unsafe { Arc::from_raw(ptr) };
1367 Arc::make_mut(&mut arc);
1369 let new_ptr = Arc::into_raw(arc) as u64;
1372 self.0 = make_tagged(TAG_HEAP, new_ptr & PAYLOAD_MASK);
1373 let final_ptr = get_payload(self.0) as *mut HeapValue;
1374 Some(unsafe { &mut *final_ptr })
1375 } else {
1376 None
1377 }
1378 }
1379
1380 #[inline]
1385 #[cfg(feature = "gc")]
1386 pub fn as_heap_mut(&mut self) -> Option<&mut HeapValue> {
1387 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1388 let ptr = get_payload(self.0) as *mut HeapValue;
1389 Some(unsafe { &mut *ptr })
1390 } else {
1391 None
1392 }
1393 }
1394
1395 #[inline]
1397 pub fn is_truthy(&self) -> bool {
1398 if !is_tagged(self.0) {
1399 let f = f64::from_bits(self.0);
1401 return f != 0.0 && !f.is_nan();
1402 }
1403 let tag = get_tag(self.0);
1404 if tag == TAG_HEAP {
1405 let ptr = get_payload(self.0) as *const HeapValue;
1406 return unsafe { (*ptr).is_truthy() };
1407 }
1408 nan_tag_is_truthy(tag, get_payload(self.0))
1409 }
1410
1411 #[inline]
1420 pub fn as_number_coerce(&self) -> Option<f64> {
1421 if let Some(n) = self.as_number_strict() {
1422 Some(n)
1423 } else if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1424 Some(sign_extend_i48(get_payload(self.0)) as f64)
1425 } else {
1426 None
1427 }
1428 }
1429
1430 #[inline(always)]
1432 pub fn is_module_function(&self) -> bool {
1433 is_tagged(self.0) && get_tag(self.0) == TAG_MODULE_FN
1434 }
1435
1436 #[inline]
1438 pub fn as_module_function(&self) -> Option<usize> {
1439 if self.is_module_function() {
1440 Some(get_payload(self.0) as usize)
1441 } else {
1442 None
1443 }
1444 }
1445
1446 #[inline]
1451 pub fn heap_kind(&self) -> Option<crate::heap_value::HeapKind> {
1452 if let Some(hv) = self.as_heap_ref() {
1453 Some(hv.kind())
1454 } else {
1455 std::option::Option::None
1456 }
1457 }
1458
1459 #[inline]
1464 pub fn tag(&self) -> NanTag {
1465 if !is_tagged(self.0) {
1466 return NanTag::F64;
1467 }
1468 match get_tag(self.0) {
1469 TAG_INT => NanTag::I48,
1470 TAG_BOOL => NanTag::Bool,
1471 TAG_NONE => NanTag::None,
1472 TAG_UNIT => NanTag::Unit,
1473 TAG_FUNCTION => NanTag::Function,
1474 TAG_MODULE_FN => NanTag::ModuleFunction,
1475 TAG_HEAP => NanTag::Heap,
1476 TAG_REF => NanTag::Ref,
1477 _ => unreachable!("invalid ValueWord tag"),
1478 }
1479 }
1480
1481 #[inline]
1484 pub fn as_str(&self) -> Option<&str> {
1485 if let Some(hv) = self.as_heap_ref() {
1486 match hv {
1487 HeapValue::String(s) => Some(s.as_str()),
1488 _ => std::option::Option::None,
1489 }
1490 } else {
1491 std::option::Option::None
1492 }
1493 }
1494
1495 #[inline]
1498 pub fn as_decimal(&self) -> Option<rust_decimal::Decimal> {
1499 if let Some(hv) = self.as_heap_ref() {
1500 match hv {
1501 HeapValue::Decimal(d) => Some(*d),
1502 _ => std::option::Option::None,
1503 }
1504 } else {
1505 std::option::Option::None
1506 }
1507 }
1508
1509 #[inline(always)]
1514 pub unsafe fn as_decimal_unchecked(&self) -> rust_decimal::Decimal {
1515 debug_assert!(matches!(self.as_heap_ref(), Some(HeapValue::Decimal(_))));
1516 match unsafe { self.as_heap_ref().unwrap_unchecked() } {
1517 HeapValue::Decimal(d) => *d,
1518 _ => unsafe { std::hint::unreachable_unchecked() },
1519 }
1520 }
1521
1522 #[inline]
1525 #[deprecated(note = "Use as_any_array() instead for unified typed array dispatch")]
1526 pub fn as_array(&self) -> Option<&VMArray> {
1527 if let Some(hv) = self.as_heap_ref() {
1528 match hv {
1529 HeapValue::Array(arr) => Some(arr),
1530 _ => std::option::Option::None,
1531 }
1532 } else {
1533 std::option::Option::None
1534 }
1535 }
1536
1537 #[inline]
1539 pub fn as_any_array(&self) -> Option<ArrayView<'_>> {
1540 match self.as_heap_ref()? {
1541 HeapValue::Array(a) => Some(ArrayView::Generic(a)),
1542 HeapValue::IntArray(a) => Some(ArrayView::Int(a)),
1543 HeapValue::FloatArray(a) => Some(ArrayView::Float(a)),
1544 HeapValue::BoolArray(a) => Some(ArrayView::Bool(a)),
1545 HeapValue::I8Array(a) => Some(ArrayView::I8(a)),
1546 HeapValue::I16Array(a) => Some(ArrayView::I16(a)),
1547 HeapValue::I32Array(a) => Some(ArrayView::I32(a)),
1548 HeapValue::U8Array(a) => Some(ArrayView::U8(a)),
1549 HeapValue::U16Array(a) => Some(ArrayView::U16(a)),
1550 HeapValue::U32Array(a) => Some(ArrayView::U32(a)),
1551 HeapValue::U64Array(a) => Some(ArrayView::U64(a)),
1552 HeapValue::F32Array(a) => Some(ArrayView::F32(a)),
1553 _ => None,
1554 }
1555 }
1556
1557 #[inline]
1559 pub fn as_any_array_mut(&mut self) -> Option<ArrayViewMut<'_>> {
1560 match self.as_heap_mut()? {
1561 HeapValue::Array(a) => Some(ArrayViewMut::Generic(a)),
1562 HeapValue::IntArray(a) => Some(ArrayViewMut::Int(a)),
1563 HeapValue::FloatArray(a) => Some(ArrayViewMut::Float(a)),
1564 HeapValue::BoolArray(a) => Some(ArrayViewMut::Bool(a)),
1565 _ => None,
1566 }
1567 }
1568
1569 #[inline]
1573 pub fn as_datatable(&self) -> Option<&Arc<DataTable>> {
1574 match self.as_heap_ref()? {
1575 HeapValue::DataTable(dt) => Some(dt),
1576 _ => std::option::Option::None,
1577 }
1578 }
1579
1580 #[inline]
1582 pub fn as_typed_table(&self) -> Option<(u64, &Arc<DataTable>)> {
1583 match self.as_heap_ref()? {
1584 HeapValue::TypedTable { schema_id, table } => Some((*schema_id, table)),
1585 _ => std::option::Option::None,
1586 }
1587 }
1588
1589 #[inline]
1591 pub fn as_row_view(&self) -> Option<(u64, &Arc<DataTable>, usize)> {
1592 match self.as_heap_ref()? {
1593 HeapValue::RowView {
1594 schema_id,
1595 table,
1596 row_idx,
1597 } => Some((*schema_id, table, *row_idx)),
1598 _ => std::option::Option::None,
1599 }
1600 }
1601
1602 #[inline]
1604 pub fn as_column_ref(&self) -> Option<(u64, &Arc<DataTable>, u32)> {
1605 match self.as_heap_ref()? {
1606 HeapValue::ColumnRef {
1607 schema_id,
1608 table,
1609 col_id,
1610 } => Some((*schema_id, table, *col_id)),
1611 _ => std::option::Option::None,
1612 }
1613 }
1614
1615 #[inline]
1617 pub fn as_indexed_table(&self) -> Option<(u64, &Arc<DataTable>, u32)> {
1618 match self.as_heap_ref()? {
1619 HeapValue::IndexedTable {
1620 schema_id,
1621 table,
1622 index_col,
1623 } => Some((*schema_id, table, *index_col)),
1624 _ => std::option::Option::None,
1625 }
1626 }
1627
1628 #[inline]
1630 pub fn as_typed_object(&self) -> Option<(u64, &[ValueSlot], u64)> {
1631 match self.as_heap_ref()? {
1632 HeapValue::TypedObject {
1633 schema_id,
1634 slots,
1635 heap_mask,
1636 } => Some((*schema_id, slots, *heap_mask)),
1637 _ => std::option::Option::None,
1638 }
1639 }
1640
1641 #[inline]
1643 pub fn as_closure(&self) -> Option<(u16, &[crate::value::Upvalue])> {
1644 match self.as_heap_ref()? {
1645 HeapValue::Closure {
1646 function_id,
1647 upvalues,
1648 } => Some((*function_id, upvalues)),
1649 _ => std::option::Option::None,
1650 }
1651 }
1652
1653 #[inline]
1655 pub fn as_some_inner(&self) -> Option<&ValueWord> {
1656 match self.as_heap_ref()? {
1657 HeapValue::Some(inner) => Some(inner),
1658 _ => std::option::Option::None,
1659 }
1660 }
1661
1662 #[inline]
1664 pub fn as_ok_inner(&self) -> Option<&ValueWord> {
1665 match self.as_heap_ref()? {
1666 HeapValue::Ok(inner) => Some(inner),
1667 _ => std::option::Option::None,
1668 }
1669 }
1670
1671 #[inline]
1673 pub fn as_err_inner(&self) -> Option<&ValueWord> {
1674 match self.as_heap_ref()? {
1675 HeapValue::Err(inner) => Some(inner),
1676 _ => std::option::Option::None,
1677 }
1678 }
1679
1680 pub fn as_err_payload(&self) -> Option<ValueWord> {
1688 let inner = match self.as_heap_ref()? {
1689 HeapValue::Err(inner) => inner.as_ref(),
1690 _ => return std::option::Option::None,
1691 };
1692 if let Some(HeapValue::TypedObject {
1694 slots, heap_mask, ..
1695 }) = inner.as_heap_ref()
1696 {
1697 const PAYLOAD_SLOT: usize = 1;
1698 if slots.len() >= 6 && *heap_mask & 1 != 0 {
1699 let cat = slots[0].as_heap_value();
1701 if let HeapValue::String(s) = cat {
1702 if s.as_str() == "AnyError" && PAYLOAD_SLOT < slots.len() {
1703 let is_heap = *heap_mask & (1u64 << PAYLOAD_SLOT) != 0;
1704 return Some(slots[PAYLOAD_SLOT].as_value_word(is_heap));
1705 }
1706 }
1707 }
1708 }
1709 Some(inner.clone())
1711 }
1712
1713 #[inline]
1715 pub fn as_future(&self) -> Option<u64> {
1716 match self.as_heap_ref()? {
1717 HeapValue::Future(id) => Some(*id),
1718 _ => std::option::Option::None,
1719 }
1720 }
1721
1722 #[inline]
1724 pub fn as_trait_object(&self) -> Option<(&ValueWord, &Arc<VTable>)> {
1725 match self.as_heap_ref()? {
1726 HeapValue::TraitObject { value, vtable } => Some((value, vtable)),
1727 _ => std::option::Option::None,
1728 }
1729 }
1730
1731 #[inline]
1733 pub fn as_expr_proxy(&self) -> Option<&Arc<String>> {
1734 match self.as_heap_ref()? {
1735 HeapValue::ExprProxy(name) => Some(name),
1736 _ => std::option::Option::None,
1737 }
1738 }
1739
1740 #[inline]
1742 pub fn as_filter_expr(&self) -> Option<&Arc<FilterNode>> {
1743 match self.as_heap_ref()? {
1744 HeapValue::FilterExpr(node) => Some(node),
1745 _ => std::option::Option::None,
1746 }
1747 }
1748
1749 #[inline]
1751 pub fn as_host_closure(&self) -> Option<&HostCallable> {
1752 match self.as_heap_ref()? {
1753 HeapValue::HostClosure(nc) => Some(nc),
1754 _ => std::option::Option::None,
1755 }
1756 }
1757
1758 #[inline]
1760 pub fn as_duration(&self) -> Option<&shape_ast::ast::Duration> {
1761 match self.as_heap_ref()? {
1762 HeapValue::Duration(d) => Some(d),
1763 _ => std::option::Option::None,
1764 }
1765 }
1766
1767 #[inline]
1769 pub fn as_range(&self) -> Option<(Option<&ValueWord>, Option<&ValueWord>, bool)> {
1770 match self.as_heap_ref()? {
1771 HeapValue::Range {
1772 start,
1773 end,
1774 inclusive,
1775 } => Some((
1776 start.as_ref().map(|b| b.as_ref()),
1777 end.as_ref().map(|b| b.as_ref()),
1778 *inclusive,
1779 )),
1780 _ => std::option::Option::None,
1781 }
1782 }
1783
1784 #[inline]
1786 pub fn as_timespan(&self) -> Option<chrono::Duration> {
1787 match self.as_heap_ref()? {
1788 HeapValue::TimeSpan(ts) => Some(*ts),
1789 _ => std::option::Option::None,
1790 }
1791 }
1792
1793 #[inline]
1795 pub fn as_enum(&self) -> Option<&EnumValue> {
1796 match self.as_heap_ref()? {
1797 HeapValue::Enum(e) => Some(e.as_ref()),
1798 _ => std::option::Option::None,
1799 }
1800 }
1801
1802 #[inline]
1804 pub fn as_timeframe(&self) -> Option<&Timeframe> {
1805 match self.as_heap_ref()? {
1806 HeapValue::Timeframe(tf) => Some(tf),
1807 _ => std::option::Option::None,
1808 }
1809 }
1810
1811 #[inline]
1813 pub fn as_hashmap(
1814 &self,
1815 ) -> Option<(&Vec<ValueWord>, &Vec<ValueWord>, &HashMap<u64, Vec<usize>>)> {
1816 match self.as_heap_ref()? {
1817 HeapValue::HashMap(d) => Some((&d.keys, &d.values, &d.index)),
1818 _ => std::option::Option::None,
1819 }
1820 }
1821
1822 #[inline]
1824 pub fn as_hashmap_data(&self) -> Option<&HashMapData> {
1825 match self.as_heap_ref()? {
1826 HeapValue::HashMap(d) => Some(d),
1827 _ => std::option::Option::None,
1828 }
1829 }
1830
1831 #[inline]
1834 pub fn as_hashmap_mut(&mut self) -> Option<&mut HashMapData> {
1835 match self.as_heap_mut()? {
1836 HeapValue::HashMap(d) => Some(d),
1837 _ => std::option::Option::None,
1838 }
1839 }
1840
1841 #[inline]
1843 pub fn as_set(&self) -> Option<&SetData> {
1844 match self.as_heap_ref()? {
1845 HeapValue::Set(d) => Some(d),
1846 _ => std::option::Option::None,
1847 }
1848 }
1849
1850 #[inline]
1852 pub fn as_set_mut(&mut self) -> Option<&mut SetData> {
1853 match self.as_heap_mut()? {
1854 HeapValue::Set(d) => Some(d),
1855 _ => std::option::Option::None,
1856 }
1857 }
1858
1859 #[inline]
1861 pub fn as_deque(&self) -> Option<&DequeData> {
1862 match self.as_heap_ref()? {
1863 HeapValue::Deque(d) => Some(d),
1864 _ => std::option::Option::None,
1865 }
1866 }
1867
1868 #[inline]
1870 pub fn as_deque_mut(&mut self) -> Option<&mut DequeData> {
1871 match self.as_heap_mut()? {
1872 HeapValue::Deque(d) => Some(d),
1873 _ => std::option::Option::None,
1874 }
1875 }
1876
1877 #[inline]
1879 pub fn as_priority_queue(&self) -> Option<&PriorityQueueData> {
1880 match self.as_heap_ref()? {
1881 HeapValue::PriorityQueue(d) => Some(d),
1882 _ => std::option::Option::None,
1883 }
1884 }
1885
1886 #[inline]
1888 pub fn as_priority_queue_mut(&mut self) -> Option<&mut PriorityQueueData> {
1889 match self.as_heap_mut()? {
1890 HeapValue::PriorityQueue(d) => Some(d),
1891 _ => std::option::Option::None,
1892 }
1893 }
1894
1895 #[inline]
1897 pub fn as_content(&self) -> Option<&ContentNode> {
1898 match self.as_heap_ref()? {
1899 HeapValue::Content(node) => Some(node),
1900 _ => std::option::Option::None,
1901 }
1902 }
1903
1904 #[inline]
1906 pub fn as_time(&self) -> Option<DateTime<FixedOffset>> {
1907 match self.as_heap_ref()? {
1908 HeapValue::Time(t) => Some(*t),
1909 _ => std::option::Option::None,
1910 }
1911 }
1912
1913 #[inline]
1915 pub fn as_instant(&self) -> Option<&std::time::Instant> {
1916 match self.as_heap_ref()? {
1917 HeapValue::Instant(t) => Some(t.as_ref()),
1918 _ => std::option::Option::None,
1919 }
1920 }
1921
1922 #[inline]
1924 pub fn as_io_handle(&self) -> Option<&crate::heap_value::IoHandleData> {
1925 match self.as_heap_ref()? {
1926 HeapValue::IoHandle(data) => Some(data.as_ref()),
1927 _ => std::option::Option::None,
1928 }
1929 }
1930
1931 #[inline]
1933 pub fn as_native_scalar(&self) -> Option<NativeScalar> {
1934 match self.as_heap_ref()? {
1935 HeapValue::NativeScalar(v) => Some(*v),
1936 _ => None,
1937 }
1938 }
1939
1940 #[inline]
1942 pub fn as_native_view(&self) -> Option<&NativeViewData> {
1943 match self.as_heap_ref()? {
1944 HeapValue::NativeView(view) => Some(view.as_ref()),
1945 _ => None,
1946 }
1947 }
1948
1949 #[inline]
1951 pub fn as_datetime(&self) -> Option<&DateTime<FixedOffset>> {
1952 match self.as_heap_ref()? {
1953 HeapValue::Time(t) => Some(t),
1954 _ => std::option::Option::None,
1955 }
1956 }
1957
1958 #[inline]
1960 pub fn as_arc_string(&self) -> Option<&Arc<String>> {
1961 match self.as_heap_ref()? {
1962 HeapValue::String(s) => Some(s),
1963 _ => std::option::Option::None,
1964 }
1965 }
1966
1967 #[inline]
1971 pub fn as_int_array(&self) -> Option<&Arc<crate::typed_buffer::TypedBuffer<i64>>> {
1972 match self.as_heap_ref()? {
1973 HeapValue::IntArray(a) => Some(a),
1974 _ => std::option::Option::None,
1975 }
1976 }
1977
1978 #[inline]
1980 pub fn as_float_array(&self) -> Option<&Arc<crate::typed_buffer::AlignedTypedBuffer>> {
1981 match self.as_heap_ref()? {
1982 HeapValue::FloatArray(a) => Some(a),
1983 _ => std::option::Option::None,
1984 }
1985 }
1986
1987 #[inline]
1989 pub fn as_bool_array(&self) -> Option<&Arc<crate::typed_buffer::TypedBuffer<u8>>> {
1990 match self.as_heap_ref()? {
1991 HeapValue::BoolArray(a) => Some(a),
1992 _ => std::option::Option::None,
1993 }
1994 }
1995
1996 #[inline]
1998 pub fn as_matrix(&self) -> Option<&crate::heap_value::MatrixData> {
1999 match self.as_heap_ref()? {
2000 HeapValue::Matrix(m) => Some(m.as_ref()),
2001 _ => std::option::Option::None,
2002 }
2003 }
2004
2005 #[inline]
2007 pub fn as_iterator(&self) -> Option<&crate::heap_value::IteratorState> {
2008 match self.as_heap_ref()? {
2009 HeapValue::Iterator(it) => Some(it.as_ref()),
2010 _ => std::option::Option::None,
2011 }
2012 }
2013
2014 #[inline]
2016 pub fn as_generator(&self) -> Option<&crate::heap_value::GeneratorState> {
2017 match self.as_heap_ref()? {
2018 HeapValue::Generator(g) => Some(g.as_ref()),
2019 _ => std::option::Option::None,
2020 }
2021 }
2022
2023 #[inline]
2026 pub fn typed_array_len(&self) -> Option<usize> {
2027 match self.as_heap_ref()? {
2028 HeapValue::IntArray(a) => Some(a.len()),
2029 HeapValue::FloatArray(a) => Some(a.len()),
2030 HeapValue::BoolArray(a) => Some(a.len()),
2031 HeapValue::I8Array(a) => Some(a.len()),
2032 HeapValue::I16Array(a) => Some(a.len()),
2033 HeapValue::I32Array(a) => Some(a.len()),
2034 HeapValue::U8Array(a) => Some(a.len()),
2035 HeapValue::U16Array(a) => Some(a.len()),
2036 HeapValue::U32Array(a) => Some(a.len()),
2037 HeapValue::U64Array(a) => Some(a.len()),
2038 HeapValue::F32Array(a) => Some(a.len()),
2039 _ => std::option::Option::None,
2040 }
2041 }
2042
2043 pub fn coerce_to_float_array(&self) -> Option<Arc<crate::typed_buffer::AlignedTypedBuffer>> {
2045 match self.as_heap_ref()? {
2046 HeapValue::FloatArray(a) => Some(Arc::clone(a)),
2047 HeapValue::IntArray(a) => {
2048 let mut buf = crate::typed_buffer::AlignedTypedBuffer::with_capacity(a.len());
2049 for &v in a.iter() {
2050 buf.push(v as f64);
2051 }
2052 Some(Arc::new(buf))
2053 }
2054 _ => std::option::Option::None,
2055 }
2056 }
2057
2058 pub fn to_generic_array(&self) -> Option<crate::value::VMArray> {
2060 match self.as_heap_ref()? {
2061 HeapValue::IntArray(a) => Some(Arc::new(
2062 a.iter().map(|&v| ValueWord::from_i64(v)).collect(),
2063 )),
2064 HeapValue::FloatArray(a) => Some(Arc::new(
2065 a.iter().map(|&v| ValueWord::from_f64(v)).collect(),
2066 )),
2067 HeapValue::BoolArray(a) => Some(Arc::new(
2068 a.iter().map(|&v| ValueWord::from_bool(v != 0)).collect(),
2069 )),
2070 _ => std::option::Option::None,
2071 }
2072 }
2073
2074 #[inline]
2078 pub fn vw_equals(&self, other: &ValueWord) -> bool {
2079 if self.0 == other.0 {
2081 if !is_tagged(self.0) {
2083 let f = f64::from_bits(self.0);
2084 return !f.is_nan();
2085 }
2086 return true;
2088 }
2089 if !is_tagged(self.0) || !is_tagged(other.0) {
2091 if let (Some(a), Some(b)) = (self.as_number_coerce(), other.as_number_coerce()) {
2095 return a == b;
2096 }
2097 return false;
2098 }
2099 let tag_a = get_tag(self.0);
2100 let tag_b = get_tag(other.0);
2101 if tag_a != tag_b {
2102 if (tag_a == TAG_INT || !is_tagged(self.0)) && (tag_b == TAG_INT || !is_tagged(other.0))
2104 {
2105 if let (Some(a), Some(b)) = (self.as_number_coerce(), other.as_number_coerce()) {
2106 return a == b;
2107 }
2108 }
2109 return false;
2110 }
2111 if tag_a == TAG_HEAP {
2113 let ptr_a = get_payload(self.0) as *const HeapValue;
2114 let ptr_b = get_payload(other.0) as *const HeapValue;
2115 return unsafe { (*ptr_a).equals(&*ptr_b) };
2116 }
2117 false
2119 }
2120
2121 pub fn vw_hash(&self) -> u64 {
2124 use ahash::AHasher;
2125 use std::hash::{Hash, Hasher};
2126
2127 let tag = self.tag();
2128 match tag {
2129 NanTag::F64 => {
2130 let f = unsafe { self.as_f64_unchecked() };
2131 let bits = if f == 0.0 { 0u64 } else { f.to_bits() };
2132 let mut hasher = AHasher::default();
2133 bits.hash(&mut hasher);
2134 hasher.finish()
2135 }
2136 NanTag::I48 => {
2137 let i = unsafe { self.as_i64_unchecked() };
2138 let mut hasher = AHasher::default();
2139 i.hash(&mut hasher);
2140 hasher.finish()
2141 }
2142 NanTag::Bool => {
2143 if unsafe { self.as_bool_unchecked() } {
2144 1
2145 } else {
2146 0
2147 }
2148 }
2149 NanTag::None => 0x_DEAD_0000,
2150 NanTag::Unit => 0x_DEAD_0001,
2151 NanTag::Heap => {
2152 if let Some(hv) = self.as_heap_ref() {
2153 match hv {
2154 HeapValue::String(s) => {
2155 let mut hasher = AHasher::default();
2156 s.hash(&mut hasher);
2157 hasher.finish()
2158 }
2159 HeapValue::BigInt(i) => {
2160 let mut hasher = AHasher::default();
2161 i.hash(&mut hasher);
2162 hasher.finish()
2163 }
2164 HeapValue::Decimal(d) => {
2165 let mut hasher = AHasher::default();
2166 d.mantissa().hash(&mut hasher);
2167 d.scale().hash(&mut hasher);
2168 hasher.finish()
2169 }
2170 HeapValue::NativeScalar(v) => {
2171 let mut hasher = AHasher::default();
2172 v.type_name().hash(&mut hasher);
2173 v.to_string().hash(&mut hasher);
2174 hasher.finish()
2175 }
2176 HeapValue::NativeView(v) => {
2177 let mut hasher = AHasher::default();
2178 v.ptr.hash(&mut hasher);
2179 v.layout.name.hash(&mut hasher);
2180 v.mutable.hash(&mut hasher);
2181 hasher.finish()
2182 }
2183 _ => {
2184 let mut hasher = AHasher::default();
2185 self.0.hash(&mut hasher);
2186 hasher.finish()
2187 }
2188 }
2189 } else {
2190 let mut hasher = AHasher::default();
2191 self.0.hash(&mut hasher);
2192 hasher.finish()
2193 }
2194 }
2195 _ => {
2196 let mut hasher = AHasher::default();
2197 self.0.hash(&mut hasher);
2198 hasher.finish()
2199 }
2200 }
2201 }
2202
2203 #[inline(always)]
2210 pub unsafe fn add_f64(a: &Self, b: &Self) -> Self {
2211 debug_assert!(a.is_f64() && b.is_f64());
2212 let lhs = unsafe { a.as_f64_unchecked() };
2213 let rhs = unsafe { b.as_f64_unchecked() };
2214 Self::from_f64(lhs + rhs)
2215 }
2216
2217 #[inline(always)]
2222 pub unsafe fn add_i64(a: &Self, b: &Self) -> Self {
2223 debug_assert!(a.is_i64() && b.is_i64());
2224 let lhs = unsafe { a.as_i64_unchecked() };
2225 let rhs = unsafe { b.as_i64_unchecked() };
2226 match lhs.checked_add(rhs) {
2227 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2228 _ => Self::from_f64(lhs as f64 + rhs as f64),
2229 }
2230 }
2231
2232 #[inline(always)]
2237 pub unsafe fn sub_f64(a: &Self, b: &Self) -> Self {
2238 debug_assert!(a.is_f64() && b.is_f64());
2239 let lhs = unsafe { a.as_f64_unchecked() };
2240 let rhs = unsafe { b.as_f64_unchecked() };
2241 Self::from_f64(lhs - rhs)
2242 }
2243
2244 #[inline(always)]
2249 pub unsafe fn sub_i64(a: &Self, b: &Self) -> Self {
2250 debug_assert!(a.is_i64() && b.is_i64());
2251 let lhs = unsafe { a.as_i64_unchecked() };
2252 let rhs = unsafe { b.as_i64_unchecked() };
2253 match lhs.checked_sub(rhs) {
2254 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2255 _ => Self::from_f64(lhs as f64 - rhs as f64),
2256 }
2257 }
2258
2259 #[inline(always)]
2264 pub unsafe fn mul_f64(a: &Self, b: &Self) -> Self {
2265 debug_assert!(a.is_f64() && b.is_f64());
2266 let lhs = unsafe { a.as_f64_unchecked() };
2267 let rhs = unsafe { b.as_f64_unchecked() };
2268 Self::from_f64(lhs * rhs)
2269 }
2270
2271 #[inline(always)]
2276 pub unsafe fn mul_i64(a: &Self, b: &Self) -> Self {
2277 debug_assert!(a.is_i64() && b.is_i64());
2278 let lhs = unsafe { a.as_i64_unchecked() };
2279 let rhs = unsafe { b.as_i64_unchecked() };
2280 match lhs.checked_mul(rhs) {
2281 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2282 _ => Self::from_f64(lhs as f64 * rhs as f64),
2283 }
2284 }
2285
2286 #[inline(always)]
2291 pub unsafe fn div_f64(a: &Self, b: &Self) -> Self {
2292 debug_assert!(a.is_f64() && b.is_f64());
2293 let lhs = unsafe { a.as_f64_unchecked() };
2294 let rhs = unsafe { b.as_f64_unchecked() };
2295 Self::from_f64(lhs / rhs)
2296 }
2297
2298 #[inline(always)]
2306 pub fn binary_int_preserving(
2307 a: &Self,
2308 b: &Self,
2309 a_num: f64,
2310 b_num: f64,
2311 int_op: impl FnOnce(i64, i64) -> Option<i64>,
2312 float_op: impl FnOnce(f64, f64) -> f64,
2313 ) -> Self {
2314 if matches!(a.tag(), NanTag::I48) && matches!(b.tag(), NanTag::I48) {
2315 match int_op(unsafe { a.as_i64_unchecked() }, unsafe {
2316 b.as_i64_unchecked()
2317 }) {
2318 Some(result) => Self::from_i64(result),
2319 None => Self::from_f64(float_op(a_num, b_num)),
2320 }
2321 } else {
2322 Self::from_f64(float_op(a_num, b_num))
2323 }
2324 }
2325
2326 #[inline(always)]
2331 pub unsafe fn gt_i64(a: &Self, b: &Self) -> Self {
2332 debug_assert!(a.is_i64() && b.is_i64());
2333 let lhs = unsafe { a.as_i64_unchecked() };
2334 let rhs = unsafe { b.as_i64_unchecked() };
2335 Self::from_bool(lhs > rhs)
2336 }
2337
2338 #[inline(always)]
2343 pub unsafe fn lt_i64(a: &Self, b: &Self) -> Self {
2344 debug_assert!(a.is_i64() && b.is_i64());
2345 let lhs = unsafe { a.as_i64_unchecked() };
2346 let rhs = unsafe { b.as_i64_unchecked() };
2347 Self::from_bool(lhs < rhs)
2348 }
2349
2350 #[inline(always)]
2352 pub fn raw_bits(&self) -> u64 {
2353 self.0
2354 }
2355
2356 #[inline]
2358 pub fn type_name(&self) -> &'static str {
2359 if !is_tagged(self.0) {
2360 return "number";
2361 }
2362 let tag = get_tag(self.0);
2363 if tag == TAG_HEAP {
2364 let ptr = get_payload(self.0) as *const HeapValue;
2365 return unsafe { (*ptr).type_name() };
2366 }
2367 nan_tag_type_name(tag)
2368 }
2369
2370 #[inline]
2375 pub fn to_number(&self) -> Option<f64> {
2376 self.as_number_coerce()
2377 }
2378
2379 #[inline]
2382 pub fn to_bool(&self) -> Option<bool> {
2383 self.as_bool()
2384 }
2385
2386 pub fn as_usize(&self) -> Option<usize> {
2388 if let Some(i) = self.as_i64() {
2389 if i >= 0 {
2390 return Some(i as usize);
2391 }
2392 } else if let Some(n) = self.as_f64() {
2393 if n >= 0.0 && n.is_finite() {
2394 return Some(n as usize);
2395 }
2396 } else if let Some(d) = self.as_decimal() {
2397 use rust_decimal::prelude::ToPrimitive;
2398 if let Some(n) = d.to_f64() {
2399 if n >= 0.0 {
2400 return Some(n as usize);
2401 }
2402 }
2403 } else if let Some(view) = self.as_native_view() {
2404 return Some(view.ptr);
2405 }
2406 None
2407 }
2408
2409 pub fn to_json_value(&self) -> serde_json::Value {
2411 use crate::heap_value::HeapValue;
2412 if let Some(n) = self.as_f64() {
2413 return serde_json::json!(n);
2414 }
2415 if let Some(i) = self.as_i64() {
2416 return serde_json::json!(i);
2417 }
2418 if let Some(b) = self.as_bool() {
2419 return serde_json::json!(b);
2420 }
2421 if self.is_none() || self.is_unit() {
2422 return serde_json::Value::Null;
2423 }
2424 if self.is_function() || self.is_module_function() {
2425 return serde_json::json!(format!("<{}>", self.type_name()));
2426 }
2427 match self.as_heap_ref() {
2428 Some(HeapValue::String(s)) => serde_json::json!(s.as_str()),
2429 Some(HeapValue::Decimal(d)) => {
2430 use rust_decimal::prelude::ToPrimitive;
2431 if let Some(f) = d.to_f64() {
2432 serde_json::json!(f)
2433 } else {
2434 serde_json::json!(d.to_string())
2435 }
2436 }
2437 Some(HeapValue::Array(arr)) => {
2438 let values: Vec<serde_json::Value> =
2439 arr.iter().map(|v| v.to_json_value()).collect();
2440 serde_json::json!(values)
2441 }
2442 Some(HeapValue::Some(v)) => v.to_json_value(),
2443 Some(HeapValue::Ok(v)) => serde_json::json!({
2444 "status": "ok",
2445 "value": v.to_json_value()
2446 }),
2447 Some(HeapValue::Err(v)) => serde_json::json!({
2448 "status": "error",
2449 "value": v.to_json_value()
2450 }),
2451 Some(HeapValue::DataTable(dt)) => serde_json::json!({
2452 "type": "datatable",
2453 "rows": dt.row_count(),
2454 "columns": dt.column_names(),
2455 }),
2456 Some(HeapValue::TypedTable { table, schema_id }) => serde_json::json!({
2457 "type": "typed_table",
2458 "schema_id": schema_id,
2459 "rows": table.row_count(),
2460 "columns": table.column_names(),
2461 }),
2462 Some(HeapValue::RowView {
2463 schema_id, row_idx, ..
2464 }) => serde_json::json!({
2465 "type": "row",
2466 "schema_id": schema_id,
2467 "row_idx": row_idx,
2468 }),
2469 Some(HeapValue::ColumnRef {
2470 schema_id, col_id, ..
2471 }) => serde_json::json!({
2472 "type": "column_ref",
2473 "schema_id": schema_id,
2474 "col_id": col_id,
2475 }),
2476 Some(HeapValue::IndexedTable {
2477 schema_id,
2478 table,
2479 index_col,
2480 }) => serde_json::json!({
2481 "type": "indexed_table",
2482 "schema_id": schema_id,
2483 "rows": table.row_count(),
2484 "columns": table.column_names(),
2485 "index_col": index_col,
2486 }),
2487 Some(HeapValue::HashMap(d)) => {
2488 let mut map = serde_json::Map::new();
2489 for (k, v) in d.keys.iter().zip(d.values.iter()) {
2490 map.insert(format!("{}", k), v.to_json_value());
2491 }
2492 serde_json::Value::Object(map)
2493 }
2494 Some(HeapValue::Set(d)) => {
2495 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2496 }
2497 Some(HeapValue::Deque(d)) => {
2498 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2499 }
2500 Some(HeapValue::PriorityQueue(d)) => {
2501 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2502 }
2503 Some(HeapValue::NativeScalar(v)) => match v {
2504 NativeScalar::I8(n) => serde_json::json!({ "type": "i8", "value": n }),
2505 NativeScalar::U8(n) => serde_json::json!({ "type": "u8", "value": n }),
2506 NativeScalar::I16(n) => serde_json::json!({ "type": "i16", "value": n }),
2507 NativeScalar::U16(n) => serde_json::json!({ "type": "u16", "value": n }),
2508 NativeScalar::I32(n) => serde_json::json!({ "type": "i32", "value": n }),
2509 NativeScalar::U32(n) => serde_json::json!({ "type": "u32", "value": n }),
2510 NativeScalar::I64(n) => {
2511 serde_json::json!({ "type": "i64", "value": n.to_string() })
2512 }
2513 NativeScalar::U64(n) => {
2514 serde_json::json!({ "type": "u64", "value": n.to_string() })
2515 }
2516 NativeScalar::Isize(n) => {
2517 serde_json::json!({ "type": "isize", "value": n.to_string() })
2518 }
2519 NativeScalar::Usize(n) => {
2520 serde_json::json!({ "type": "usize", "value": n.to_string() })
2521 }
2522 NativeScalar::Ptr(n) => {
2523 serde_json::json!({ "type": "ptr", "value": format!("0x{n:x}") })
2524 }
2525 NativeScalar::F32(n) => serde_json::json!({ "type": "f32", "value": n }),
2526 },
2527 Some(HeapValue::NativeView(v)) => serde_json::json!({
2528 "type": if v.mutable { "cmut" } else { "cview" },
2529 "layout": v.layout.name,
2530 "ptr": v.ptr,
2531 }),
2532 _ => serde_json::json!(format!("<{}>", self.type_name())),
2533 }
2534 }
2535}
2536
2537impl PartialEq for ValueWord {
2544 fn eq(&self, other: &Self) -> bool {
2545 if self.0 == other.0 {
2547 return true;
2548 }
2549 if is_tagged(self.0)
2551 && get_tag(self.0) == TAG_HEAP
2552 && is_tagged(other.0)
2553 && get_tag(other.0) == TAG_HEAP
2554 {
2555 match (self.as_heap_ref(), other.as_heap_ref()) {
2556 (Some(a), Some(b)) => a.structural_eq(b),
2557 _ => false,
2558 }
2559 } else {
2560 false
2561 }
2562 }
2563}
2564
2565impl Eq for ValueWord {}
2566
2567#[cfg(not(feature = "gc"))]
2570impl Clone for ValueWord {
2571 #[inline]
2572 fn clone(&self) -> Self {
2573 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
2574 let ptr = get_payload(self.0) as *const HeapValue;
2576 unsafe { Arc::increment_strong_count(ptr) };
2577 Self(self.0)
2578 } else {
2579 Self(self.0)
2581 }
2582 }
2583}
2584
2585#[cfg(feature = "gc")]
2586impl Clone for ValueWord {
2587 #[inline]
2588 fn clone(&self) -> Self {
2589 Self(self.0)
2592 }
2593}
2594
2595#[cfg(not(feature = "gc"))]
2598impl Drop for ValueWord {
2599 fn drop(&mut self) {
2600 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
2601 let ptr = get_payload(self.0) as *const HeapValue;
2602 if !ptr.is_null() {
2603 unsafe {
2604 Arc::decrement_strong_count(ptr);
2606 }
2607 }
2608 }
2609 }
2610}
2611
2612#[cfg(feature = "gc")]
2613impl Drop for ValueWord {
2614 #[inline]
2615 fn drop(&mut self) {
2616 }
2619}
2620
2621impl std::fmt::Display for ValueWord {
2622 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2623 if self.is_f64() {
2624 let n = unsafe { self.as_f64_unchecked() };
2625 if n == n.trunc() && n.abs() < 1e15 {
2626 write!(f, "{}", n as i64)
2627 } else {
2628 write!(f, "{}", n)
2629 }
2630 } else if self.is_i64() {
2631 write!(f, "{}", unsafe { self.as_i64_unchecked() })
2632 } else if self.is_bool() {
2633 write!(f, "{}", unsafe { self.as_bool_unchecked() })
2634 } else if self.is_none() {
2635 write!(f, "none")
2636 } else if self.is_unit() {
2637 write!(f, "()")
2638 } else if self.is_function() {
2639 write!(f, "<function:{}>", unsafe { self.as_function_unchecked() })
2640 } else if self.is_module_function() {
2641 write!(f, "<module_function>")
2642 } else if self.is_ref() {
2643 write!(f, "&slot_{}", get_payload(self.0))
2644 } else if let Some(hv) = self.as_heap_ref() {
2645 match hv {
2646 HeapValue::String(s) => write!(f, "{}", s),
2647 HeapValue::Array(arr) => {
2648 write!(f, "[")?;
2649 for (i, elem) in arr.iter().enumerate() {
2650 if i > 0 {
2651 write!(f, ", ")?;
2652 }
2653 write!(f, "{}", elem)?;
2654 }
2655 write!(f, "]")
2656 }
2657 HeapValue::TypedObject { .. } => write!(f, "{{...}}"),
2658 HeapValue::Closure { function_id, .. } => write!(f, "<closure:{}>", function_id),
2659 HeapValue::Decimal(d) => write!(f, "{}", d),
2660 HeapValue::BigInt(i) => write!(f, "{}", i),
2661 HeapValue::HostClosure(_) => write!(f, "<host_closure>"),
2662 HeapValue::DataTable(dt) => {
2663 write!(f, "<datatable:{}x{}>", dt.row_count(), dt.column_count())
2664 }
2665 HeapValue::TypedTable { table, .. } => write!(
2666 f,
2667 "<typed_table:{}x{}>",
2668 table.row_count(),
2669 table.column_count()
2670 ),
2671 HeapValue::RowView { row_idx, .. } => write!(f, "<row:{}>", row_idx),
2672 HeapValue::ColumnRef { col_id, .. } => write!(f, "<column:{}>", col_id),
2673 HeapValue::IndexedTable { table, .. } => write!(
2674 f,
2675 "<indexed_table:{}x{}>",
2676 table.row_count(),
2677 table.column_count()
2678 ),
2679 HeapValue::HashMap(d) => {
2680 write!(f, "HashMap{{")?;
2681 for (i, (k, v)) in d.keys.iter().zip(d.values.iter()).enumerate() {
2682 if i > 0 {
2683 write!(f, ", ")?;
2684 }
2685 write!(f, "{}: {}", k, v)?;
2686 }
2687 write!(f, "}}")
2688 }
2689 HeapValue::Set(d) => {
2690 write!(f, "Set{{")?;
2691 for (i, item) in d.items.iter().enumerate() {
2692 if i > 0 {
2693 write!(f, ", ")?;
2694 }
2695 write!(f, "{}", item)?;
2696 }
2697 write!(f, "}}")
2698 }
2699 HeapValue::Deque(d) => {
2700 write!(f, "Deque[")?;
2701 for (i, item) in d.items.iter().enumerate() {
2702 if i > 0 {
2703 write!(f, ", ")?;
2704 }
2705 write!(f, "{}", item)?;
2706 }
2707 write!(f, "]")
2708 }
2709 HeapValue::PriorityQueue(d) => {
2710 write!(f, "PriorityQueue[")?;
2711 for (i, item) in d.items.iter().enumerate() {
2712 if i > 0 {
2713 write!(f, ", ")?;
2714 }
2715 write!(f, "{}", item)?;
2716 }
2717 write!(f, "]")
2718 }
2719 HeapValue::Content(node) => write!(f, "{}", node),
2720 HeapValue::Instant(t) => write!(f, "<instant:{:?}>", t.elapsed()),
2721 HeapValue::IoHandle(data) => {
2722 let status = if data.is_open() { "open" } else { "closed" };
2723 write!(f, "<io_handle:{}:{}>", data.path, status)
2724 }
2725 HeapValue::Range {
2726 start,
2727 end,
2728 inclusive,
2729 } => {
2730 if let Some(s) = start {
2731 write!(f, "{}", s)?;
2732 }
2733 write!(f, "{}", if *inclusive { "..=" } else { ".." })?;
2734 if let Some(e) = end {
2735 write!(f, "{}", e)?;
2736 }
2737 std::fmt::Result::Ok(())
2738 }
2739 HeapValue::Enum(e) => write!(f, "{}.{}", e.enum_name, e.variant),
2740 HeapValue::Some(v) => write!(f, "some({})", v),
2741 HeapValue::Ok(v) => write!(f, "ok({})", v),
2742 HeapValue::Err(v) => write!(f, "err({})", v),
2743 HeapValue::Future(id) => write!(f, "<future:{}>", id),
2744 HeapValue::TaskGroup { task_ids, .. } => {
2745 write!(f, "<task_group:{}>", task_ids.len())
2746 }
2747 HeapValue::TraitObject { value, .. } => write!(f, "{}", value),
2748 HeapValue::ExprProxy(name) => write!(f, "<expr:{}>", name),
2749 HeapValue::FilterExpr(_) => write!(f, "<filter_expr>"),
2750 HeapValue::Time(t) => write!(f, "{}", t),
2751 HeapValue::Duration(d) => write!(f, "{:?}", d),
2752 HeapValue::TimeSpan(ts) => write!(f, "{}", ts),
2753 HeapValue::Timeframe(tf) => write!(f, "{:?}", tf),
2754 HeapValue::TimeReference(_) => write!(f, "<time_ref>"),
2755 HeapValue::DateTimeExpr(_) => write!(f, "<datetime_expr>"),
2756 HeapValue::DataDateTimeRef(_) => write!(f, "<data_datetime_ref>"),
2757 HeapValue::TypeAnnotation(_) => write!(f, "<type_annotation>"),
2758 HeapValue::TypeAnnotatedValue { type_name, value } => {
2759 write!(f, "{}({})", type_name, value)
2760 }
2761 HeapValue::PrintResult(_) => write!(f, "<print_result>"),
2762 HeapValue::SimulationCall(data) => write!(f, "<simulation:{}>", data.name),
2763 HeapValue::FunctionRef { name, .. } => write!(f, "<fn:{}>", name),
2764 HeapValue::DataReference(data) => write!(f, "<data:{}>", data.id),
2765 HeapValue::NativeScalar(v) => write!(f, "{v}"),
2766 HeapValue::NativeView(v) => write!(
2767 f,
2768 "<{}:{}@0x{:x}>",
2769 if v.mutable { "cmut" } else { "cview" },
2770 v.layout.name,
2771 v.ptr
2772 ),
2773 HeapValue::SharedCell(arc) => write!(f, "{}", arc.read().unwrap()),
2774 HeapValue::IntArray(a) => {
2775 write!(f, "Vec<int>[")?;
2776 for (i, v) in a.iter().enumerate() {
2777 if i > 0 {
2778 write!(f, ", ")?;
2779 }
2780 write!(f, "{}", v)?;
2781 }
2782 write!(f, "]")
2783 }
2784 HeapValue::FloatArray(a) => {
2785 write!(f, "Vec<number>[")?;
2786 for (i, v) in a.iter().enumerate() {
2787 if i > 0 {
2788 write!(f, ", ")?;
2789 }
2790 if *v == v.trunc() && v.abs() < 1e15 {
2791 write!(f, "{}", *v as i64)?;
2792 } else {
2793 write!(f, "{}", v)?;
2794 }
2795 }
2796 write!(f, "]")
2797 }
2798 HeapValue::BoolArray(a) => {
2799 write!(f, "Vec<bool>[")?;
2800 for (i, v) in a.iter().enumerate() {
2801 if i > 0 {
2802 write!(f, ", ")?;
2803 }
2804 write!(f, "{}", *v != 0)?;
2805 }
2806 write!(f, "]")
2807 }
2808 HeapValue::Matrix(m) => {
2809 write!(f, "<Mat<number>:{}x{}>", m.rows, m.cols)
2810 }
2811 HeapValue::Iterator(it) => {
2812 write!(
2813 f,
2814 "<iterator:pos={},transforms={}>",
2815 it.position,
2816 it.transforms.len()
2817 )
2818 }
2819 HeapValue::Generator(g) => {
2820 write!(f, "<generator:state={}>", g.state)
2821 }
2822 HeapValue::Mutex(_) => write!(f, "<mutex>"),
2823 HeapValue::Atomic(a) => {
2824 write!(
2825 f,
2826 "<atomic:{}>",
2827 a.inner.load(std::sync::atomic::Ordering::Relaxed)
2828 )
2829 }
2830 HeapValue::Channel(c) => {
2831 if c.is_sender() {
2832 write!(f, "<channel:sender>")
2833 } else {
2834 write!(f, "<channel:receiver>")
2835 }
2836 }
2837 HeapValue::Lazy(l) => {
2838 let initialized = l.value.lock().map(|g| g.is_some()).unwrap_or(false);
2839 if initialized {
2840 write!(f, "<lazy:initialized>")
2841 } else {
2842 write!(f, "<lazy:pending>")
2843 }
2844 }
2845 HeapValue::I8Array(a) => {
2846 write!(f, "Vec<i8>[")?;
2847 for (i, v) in a.iter().enumerate() {
2848 if i > 0 {
2849 write!(f, ", ")?;
2850 }
2851 write!(f, "{}", v)?;
2852 }
2853 write!(f, "]")
2854 }
2855 HeapValue::I16Array(a) => {
2856 write!(f, "Vec<i16>[")?;
2857 for (i, v) in a.iter().enumerate() {
2858 if i > 0 {
2859 write!(f, ", ")?;
2860 }
2861 write!(f, "{}", v)?;
2862 }
2863 write!(f, "]")
2864 }
2865 HeapValue::I32Array(a) => {
2866 write!(f, "Vec<i32>[")?;
2867 for (i, v) in a.iter().enumerate() {
2868 if i > 0 {
2869 write!(f, ", ")?;
2870 }
2871 write!(f, "{}", v)?;
2872 }
2873 write!(f, "]")
2874 }
2875 HeapValue::U8Array(a) => {
2876 write!(f, "Vec<u8>[")?;
2877 for (i, v) in a.iter().enumerate() {
2878 if i > 0 {
2879 write!(f, ", ")?;
2880 }
2881 write!(f, "{}", v)?;
2882 }
2883 write!(f, "]")
2884 }
2885 HeapValue::U16Array(a) => {
2886 write!(f, "Vec<u16>[")?;
2887 for (i, v) in a.iter().enumerate() {
2888 if i > 0 {
2889 write!(f, ", ")?;
2890 }
2891 write!(f, "{}", v)?;
2892 }
2893 write!(f, "]")
2894 }
2895 HeapValue::U32Array(a) => {
2896 write!(f, "Vec<u32>[")?;
2897 for (i, v) in a.iter().enumerate() {
2898 if i > 0 {
2899 write!(f, ", ")?;
2900 }
2901 write!(f, "{}", v)?;
2902 }
2903 write!(f, "]")
2904 }
2905 HeapValue::U64Array(a) => {
2906 write!(f, "Vec<u64>[")?;
2907 for (i, v) in a.iter().enumerate() {
2908 if i > 0 {
2909 write!(f, ", ")?;
2910 }
2911 write!(f, "{}", v)?;
2912 }
2913 write!(f, "]")
2914 }
2915 HeapValue::F32Array(a) => {
2916 write!(f, "Vec<f32>[")?;
2917 for (i, v) in a.iter().enumerate() {
2918 if i > 0 {
2919 write!(f, ", ")?;
2920 }
2921 write!(f, "{}", v)?;
2922 }
2923 write!(f, "]")
2924 }
2925 }
2926 } else {
2927 write!(f, "<unknown>")
2928 }
2929 }
2930}
2931
2932impl std::fmt::Debug for ValueWord {
2933 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2934 if self.is_f64() {
2935 write!(f, "ValueWord(f64: {})", unsafe { self.as_f64_unchecked() })
2936 } else if self.is_i64() {
2937 write!(f, "ValueWord(i64: {})", unsafe { self.as_i64_unchecked() })
2938 } else if self.is_bool() {
2939 write!(f, "ValueWord(bool: {})", unsafe {
2940 self.as_bool_unchecked()
2941 })
2942 } else if self.is_none() {
2943 write!(f, "ValueWord(None)")
2944 } else if self.is_unit() {
2945 write!(f, "ValueWord(Unit)")
2946 } else if self.is_function() {
2947 write!(f, "ValueWord(Function({}))", unsafe {
2948 self.as_function_unchecked()
2949 })
2950 } else if self.is_ref() {
2951 write!(f, "ValueWord(Ref({}))", get_payload(self.0))
2952 } else if self.is_heap() {
2953 let ptr = get_payload(self.0) as *const HeapValue;
2954 let hv = unsafe { &*ptr };
2955 write!(f, "ValueWord(heap: {:?})", hv)
2956 } else {
2957 write!(f, "ValueWord(0x{:016x})", self.0)
2958 }
2959 }
2960}
2961
2962#[cfg(test)]
2963mod tests {
2964 use super::*;
2965 use std::sync::Arc;
2966
2967 #[test]
2970 fn test_f64_roundtrip_positive() {
2971 let v = ValueWord::from_f64(3.14);
2972 assert!(v.is_f64());
2973 assert_eq!(v.as_f64(), Some(3.14));
2974 unsafe { assert_eq!(v.as_f64_unchecked(), 3.14) };
2975 }
2976
2977 #[test]
2978 fn test_f64_roundtrip_negative() {
2979 let v = ValueWord::from_f64(-123.456);
2980 assert!(v.is_f64());
2981 assert_eq!(v.as_f64(), Some(-123.456));
2982 }
2983
2984 #[test]
2985 fn test_f64_zero() {
2986 let v = ValueWord::from_f64(0.0);
2987 assert!(v.is_f64());
2988 assert_eq!(v.as_f64(), Some(0.0));
2989 }
2990
2991 #[test]
2992 fn test_f64_negative_zero() {
2993 let v = ValueWord::from_f64(-0.0);
2994 assert!(v.is_f64());
2995 let extracted = v.as_f64().unwrap();
2996 assert_eq!(extracted, 0.0);
2998 assert!(extracted.is_sign_negative());
3000 }
3001
3002 #[test]
3003 fn test_f64_infinity() {
3004 let pos = ValueWord::from_f64(f64::INFINITY);
3005 assert!(pos.is_f64());
3006 assert_eq!(pos.as_f64(), Some(f64::INFINITY));
3007
3008 let neg = ValueWord::from_f64(f64::NEG_INFINITY);
3009 assert!(neg.is_f64());
3010 assert_eq!(neg.as_f64(), Some(f64::NEG_INFINITY));
3011 }
3012
3013 #[test]
3014 fn test_f64_nan_canonicalized() {
3015 let v = ValueWord::from_f64(f64::NAN);
3016 assert!(v.is_f64());
3018 let extracted = v.as_f64().unwrap();
3019 assert!(extracted.is_nan());
3020 }
3021
3022 #[test]
3023 fn test_f64_subnormal() {
3024 let tiny = f64::MIN_POSITIVE / 2.0; let v = ValueWord::from_f64(tiny);
3026 assert!(v.is_f64());
3027 assert_eq!(v.as_f64(), Some(tiny));
3028 }
3029
3030 #[test]
3031 fn test_f64_max_min() {
3032 let max = ValueWord::from_f64(f64::MAX);
3033 assert!(max.is_f64());
3034 assert_eq!(max.as_f64(), Some(f64::MAX));
3035
3036 let min = ValueWord::from_f64(f64::MIN);
3037 assert!(min.is_f64());
3038 assert_eq!(min.as_f64(), Some(f64::MIN));
3039 }
3040
3041 #[test]
3044 fn test_i64_small_positive() {
3045 let v = ValueWord::from_i64(42);
3046 assert!(v.is_i64());
3047 assert_eq!(v.as_i64(), Some(42));
3048 unsafe { assert_eq!(v.as_i64_unchecked(), 42) };
3049 }
3050
3051 #[test]
3052 fn test_i64_small_negative() {
3053 let v = ValueWord::from_i64(-42);
3054 assert!(v.is_i64());
3055 assert_eq!(v.as_i64(), Some(-42));
3056 }
3057
3058 #[test]
3059 fn test_i64_zero() {
3060 let v = ValueWord::from_i64(0);
3061 assert!(v.is_i64());
3062 assert_eq!(v.as_i64(), Some(0));
3063 }
3064
3065 #[test]
3066 fn test_i64_i48_max() {
3067 let max = I48_MAX;
3068 let v = ValueWord::from_i64(max);
3069 assert!(v.is_i64());
3070 assert_eq!(v.as_i64(), Some(max));
3071 }
3072
3073 #[test]
3074 fn test_i64_i48_min() {
3075 let min = I48_MIN;
3076 let v = ValueWord::from_i64(min);
3077 assert!(v.is_i64());
3078 assert_eq!(v.as_i64(), Some(min));
3079 }
3080
3081 #[test]
3082 fn test_i64_large_needs_heap() {
3083 let v = ValueWord::from_i64(i64::MAX);
3085 assert!(v.is_heap());
3086 assert_eq!(v.as_i64(), Some(i64::MAX));
3087 }
3088
3089 #[test]
3090 fn test_i64_min_needs_heap() {
3091 let v = ValueWord::from_i64(i64::MIN);
3092 assert!(v.is_heap());
3093 assert_eq!(v.as_i64(), Some(i64::MIN));
3094 }
3095
3096 #[test]
3097 fn test_i64_just_outside_i48_positive() {
3098 let val = I48_MAX + 1;
3099 let v = ValueWord::from_i64(val);
3100 assert!(v.is_heap());
3101 assert_eq!(v.as_i64(), Some(val));
3102 }
3103
3104 #[test]
3105 fn test_i64_just_outside_i48_negative() {
3106 let val = I48_MIN - 1;
3107 let v = ValueWord::from_i64(val);
3108 assert!(v.is_heap());
3109 assert_eq!(v.as_i64(), Some(val));
3110 }
3111
3112 #[test]
3115 fn test_bool_true() {
3116 let v = ValueWord::from_bool(true);
3117 assert!(v.is_bool());
3118 assert_eq!(v.as_bool(), Some(true));
3119 unsafe { assert_eq!(v.as_bool_unchecked(), true) };
3120 }
3121
3122 #[test]
3123 fn test_bool_false() {
3124 let v = ValueWord::from_bool(false);
3125 assert!(v.is_bool());
3126 assert_eq!(v.as_bool(), Some(false));
3127 unsafe { assert_eq!(v.as_bool_unchecked(), false) };
3128 }
3129
3130 #[test]
3133 fn test_none() {
3134 let v = ValueWord::none();
3135 assert!(v.is_none());
3136 assert!(!v.is_f64());
3137 assert!(!v.is_i64());
3138 assert!(!v.is_bool());
3139 }
3140
3141 #[test]
3142 fn test_unit() {
3143 let v = ValueWord::unit();
3144 assert!(v.is_unit());
3145 }
3146
3147 #[test]
3150 fn test_function() {
3151 let v = ValueWord::from_function(42);
3152 assert!(v.is_function());
3153 assert_eq!(v.as_function(), Some(42));
3154 unsafe { assert_eq!(v.as_function_unchecked(), 42) };
3155 }
3156
3157 #[test]
3158 fn test_function_max_id() {
3159 let v = ValueWord::from_function(u16::MAX);
3160 assert!(v.is_function());
3161 assert_eq!(v.as_function(), Some(u16::MAX));
3162 }
3163
3164 #[test]
3167 fn test_module_function() {
3168 let v = ValueWord::from_module_function(99);
3169 assert!(is_tagged(v.0));
3170 assert_eq!(get_tag(v.0), TAG_MODULE_FN);
3171 assert_eq!(v.as_module_function(), Some(99));
3172 }
3173
3174 #[test]
3177 fn test_heap_string_roundtrip() {
3178 let v = ValueWord::from_string(Arc::new("hello world".to_string()));
3179 assert!(v.is_heap());
3180 assert_eq!(v.as_arc_string().map(|s| s.as_str()), Some("hello world"));
3181 }
3182
3183 #[test]
3184 fn test_heap_array_roundtrip() {
3185 let arr = Arc::new(vec![
3186 ValueWord::from_i64(1),
3187 ValueWord::from_i64(2),
3188 ValueWord::from_i64(3),
3189 ]);
3190 let v = ValueWord::from_array(arr.clone());
3191 assert!(v.is_heap());
3192 let extracted = v.as_array().expect("should be array");
3193 assert_eq!(extracted.len(), 3);
3194 }
3195
3196 #[test]
3197 fn test_heap_clone() {
3198 let v = ValueWord::from_string(Arc::new("clone me".to_string()));
3199 let cloned = v.clone();
3200
3201 assert_eq!(v.as_arc_string().map(|s| s.as_str()), Some("clone me"));
3203 assert_eq!(cloned.as_arc_string().map(|s| s.as_str()), Some("clone me"));
3204
3205 assert_eq!(
3207 get_payload(v.0),
3208 get_payload(cloned.0),
3209 "cloned heap pointers should be identical (Arc shared)"
3210 );
3211 }
3212
3213 #[test]
3216 fn test_add_f64() {
3217 let a = ValueWord::from_f64(1.5);
3218 let b = ValueWord::from_f64(2.5);
3219 let result = unsafe { ValueWord::add_f64(&a, &b) };
3220 assert_eq!(result.as_f64(), Some(4.0));
3221 }
3222
3223 #[test]
3224 fn test_add_i64() {
3225 let a = ValueWord::from_i64(100);
3226 let b = ValueWord::from_i64(200);
3227 let result = unsafe { ValueWord::add_i64(&a, &b) };
3228 assert_eq!(result.as_i64(), Some(300));
3229 }
3230
3231 #[test]
3232 fn test_add_i64_negative() {
3233 let a = ValueWord::from_i64(-50);
3234 let b = ValueWord::from_i64(30);
3235 let result = unsafe { ValueWord::add_i64(&a, &b) };
3236 assert_eq!(result.as_i64(), Some(-20));
3237 }
3238
3239 #[test]
3240 fn test_sub_f64() {
3241 let a = ValueWord::from_f64(10.0);
3242 let b = ValueWord::from_f64(3.0);
3243 let result = unsafe { ValueWord::sub_f64(&a, &b) };
3244 assert_eq!(result.as_f64(), Some(7.0));
3245 }
3246
3247 #[test]
3248 fn test_sub_i64() {
3249 let a = ValueWord::from_i64(50);
3250 let b = ValueWord::from_i64(80);
3251 let result = unsafe { ValueWord::sub_i64(&a, &b) };
3252 assert_eq!(result.as_i64(), Some(-30));
3253 }
3254
3255 #[test]
3256 fn test_mul_f64() {
3257 let a = ValueWord::from_f64(3.0);
3258 let b = ValueWord::from_f64(4.0);
3259 let result = unsafe { ValueWord::mul_f64(&a, &b) };
3260 assert_eq!(result.as_f64(), Some(12.0));
3261 }
3262
3263 #[test]
3264 fn test_mul_i64() {
3265 let a = ValueWord::from_i64(7);
3266 let b = ValueWord::from_i64(-6);
3267 let result = unsafe { ValueWord::mul_i64(&a, &b) };
3268 assert_eq!(result.as_i64(), Some(-42));
3269 }
3270
3271 #[test]
3272 fn test_div_f64() {
3273 let a = ValueWord::from_f64(10.0);
3274 let b = ValueWord::from_f64(4.0);
3275 let result = unsafe { ValueWord::div_f64(&a, &b) };
3276 assert_eq!(result.as_f64(), Some(2.5));
3277 }
3278
3279 #[test]
3280 fn test_gt_i64() {
3281 let a = ValueWord::from_i64(10);
3282 let b = ValueWord::from_i64(5);
3283 let result = unsafe { ValueWord::gt_i64(&a, &b) };
3284 assert_eq!(result.as_bool(), Some(true));
3285
3286 let result2 = unsafe { ValueWord::gt_i64(&b, &a) };
3287 assert_eq!(result2.as_bool(), Some(false));
3288 }
3289
3290 #[test]
3291 fn test_lt_i64() {
3292 let a = ValueWord::from_i64(3);
3293 let b = ValueWord::from_i64(7);
3294 let result = unsafe { ValueWord::lt_i64(&a, &b) };
3295 assert_eq!(result.as_bool(), Some(true));
3296
3297 let result2 = unsafe { ValueWord::lt_i64(&b, &a) };
3298 assert_eq!(result2.as_bool(), Some(false));
3299 }
3300
3301 #[test]
3304 fn test_add_i64_overflow_to_heap() {
3305 let a = ValueWord::from_i64(I48_MAX);
3308 let b = ValueWord::from_i64(1);
3309 let result = unsafe { ValueWord::add_i64(&a, &b) };
3310 assert!(result.is_f64());
3311 let expected = (I48_MAX + 1) as f64;
3312 assert_eq!(result.as_f64(), Some(expected));
3313 }
3314
3315 #[test]
3318 fn test_type_checks_exclusive() {
3319 let f = ValueWord::from_f64(1.0);
3320 assert!(f.is_f64());
3321 assert!(!f.is_i64());
3322 assert!(!f.is_bool());
3323 assert!(!f.is_none());
3324 assert!(!f.is_unit());
3325 assert!(!f.is_function());
3326 assert!(!f.is_heap());
3327
3328 let i = ValueWord::from_i64(1);
3329 assert!(!i.is_f64());
3330 assert!(i.is_i64());
3331 assert!(!i.is_bool());
3332 assert!(!i.is_none());
3333 assert!(!i.is_unit());
3334 assert!(!i.is_function());
3335 assert!(!i.is_heap());
3336
3337 let b = ValueWord::from_bool(true);
3338 assert!(!b.is_f64());
3339 assert!(!b.is_i64());
3340 assert!(b.is_bool());
3341 assert!(!b.is_none());
3342
3343 let n = ValueWord::none();
3344 assert!(!n.is_f64());
3345 assert!(!n.is_i64());
3346 assert!(!n.is_bool());
3347 assert!(n.is_none());
3348
3349 let u = ValueWord::unit();
3350 assert!(u.is_unit());
3351 assert!(!u.is_none());
3352
3353 let func = ValueWord::from_function(0);
3354 assert!(func.is_function());
3355 assert!(!func.is_f64());
3356 }
3357
3358 #[test]
3361 fn test_size_is_8_bytes() {
3362 assert_eq!(std::mem::size_of::<ValueWord>(), 8);
3363 }
3364
3365 #[test]
3366 fn test_heap_value_size() {
3367 use crate::heap_value::HeapValue;
3368 let hv_size = std::mem::size_of::<HeapValue>();
3369 assert!(
3372 hv_size <= 48,
3373 "HeapValue grew beyond expected 48 bytes: {} bytes",
3374 hv_size
3375 );
3376 }
3377
3378 #[test]
3381 fn test_debug_format() {
3382 let v = ValueWord::from_f64(3.14);
3383 let dbg = format!("{:?}", v);
3384 assert!(dbg.contains("f64"));
3385 assert!(dbg.contains("3.14"));
3386
3387 let v = ValueWord::from_i64(42);
3388 let dbg = format!("{:?}", v);
3389 assert!(dbg.contains("i64"));
3390 assert!(dbg.contains("42"));
3391
3392 let v = ValueWord::none();
3393 let dbg = format!("{:?}", v);
3394 assert!(dbg.contains("None"));
3395 }
3396
3397 #[test]
3400 fn test_sign_extension_negative_one() {
3401 let v = ValueWord::from_i64(-1);
3402 assert!(v.is_i64());
3403 assert_eq!(v.as_i64(), Some(-1));
3404 }
3405
3406 #[test]
3407 fn test_sign_extension_boundary() {
3408 let v = ValueWord::from_i64(-1);
3410 let payload = get_payload(v.0);
3411 assert_eq!(payload, 0x0000_FFFF_FFFF_FFFF);
3412 assert_eq!(sign_extend_i48(payload), -1);
3413
3414 let v = ValueWord::from_i64(I48_MIN);
3416 let payload = get_payload(v.0);
3417 assert_eq!(payload, 0x0000_8000_0000_0000);
3419 assert_eq!(sign_extend_i48(payload), I48_MIN);
3420 }
3421
3422 #[test]
3425 fn test_drop_non_heap_is_noop() {
3426 let _ = ValueWord::from_f64(1.0);
3428 let _ = ValueWord::from_i64(1);
3429 let _ = ValueWord::from_bool(true);
3430 let _ = ValueWord::none();
3431 let _ = ValueWord::unit();
3432 let _ = ValueWord::from_function(0);
3433 }
3434
3435 #[test]
3436 fn test_drop_heap_frees_memory() {
3437 let _v = ValueWord::from_string(Arc::new("drop test".to_string()));
3439 }
3441
3442 #[test]
3443 fn test_multiple_clones_and_drops() {
3444 let v1 = ValueWord::from_string(Arc::new("multi clone".to_string()));
3445 let v2 = v1.clone();
3446 let v3 = v2.clone();
3447
3448 assert_eq!(v1.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3449 assert_eq!(v2.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3450 assert_eq!(v3.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3451
3452 drop(v2);
3454 assert_eq!(v1.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3455 assert_eq!(v3.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3456 }
3457
3458 #[test]
3461 fn test_datetime_fixed_offset_roundtrip() {
3462 use chrono::TimeZone;
3463 let offset = chrono::FixedOffset::east_opt(5 * 3600 + 30 * 60).unwrap(); let dt = offset.with_ymd_and_hms(2024, 6, 15, 14, 30, 0).unwrap();
3465 let v = ValueWord::from_time(dt);
3466 let extracted = v.as_time().unwrap();
3467 assert_eq!(extracted, dt);
3468 assert_eq!(extracted.offset().local_minus_utc(), 5 * 3600 + 30 * 60);
3469 }
3470
3471 #[test]
3472 fn test_datetime_utc_convenience() {
3473 use chrono::TimeZone;
3474 let utc_dt = chrono::Utc.with_ymd_and_hms(2024, 1, 15, 10, 0, 0).unwrap();
3475 let v = ValueWord::from_time_utc(utc_dt);
3476 let extracted = v.as_time().unwrap();
3477 assert_eq!(extracted.offset().local_minus_utc(), 0);
3478 assert_eq!(extracted.timestamp(), utc_dt.timestamp());
3479 }
3480
3481 #[test]
3482 fn test_as_datetime_returns_ref() {
3483 use chrono::TimeZone;
3484 let offset = chrono::FixedOffset::west_opt(4 * 3600).unwrap(); let dt = offset.with_ymd_and_hms(2024, 12, 25, 8, 0, 0).unwrap();
3486 let v = ValueWord::from_time(dt);
3487 let dt_ref = v.as_datetime().unwrap();
3488 assert_eq!(*dt_ref, dt);
3489 assert_eq!(dt_ref.offset().local_minus_utc(), -4 * 3600);
3490 }
3491
3492 #[test]
3493 fn test_datetime_display() {
3494 use chrono::TimeZone;
3495 let utc_dt = chrono::Utc.with_ymd_and_hms(2024, 3, 1, 12, 0, 0).unwrap();
3496 let v = ValueWord::from_time_utc(utc_dt);
3497 let display = format!("{}", v);
3498 assert!(display.contains("2024-03-01"));
3499 }
3500
3501 #[test]
3502 fn test_as_number_coerce_rejects_native_i64_u64() {
3503 let i64_nb = ValueWord::from_native_scalar(NativeScalar::I64(42));
3504 let u64_nb = ValueWord::from_native_u64(u64::MAX);
3505 assert_eq!(i64_nb.as_number_coerce(), None);
3506 assert_eq!(u64_nb.as_number_coerce(), None);
3507 }
3508
3509 #[test]
3510 fn test_as_number_coerce_accepts_native_f32() {
3511 let v = ValueWord::from_native_f32(12.5);
3512 assert_eq!(v.as_number_coerce(), Some(12.5));
3513 }
3514
3515 #[test]
3516 fn test_exact_integer_extractors_cover_u64() {
3517 let v = ValueWord::from_native_u64(u64::MAX);
3518 assert_eq!(v.as_u64(), Some(u64::MAX));
3519 assert_eq!(v.as_i128_exact(), Some(u64::MAX as i128));
3520 }
3521
3522 #[test]
3525 fn test_int_array_construction_and_roundtrip() {
3526 let data = vec![1i64, 2, 3, -100, 0];
3527 let nb = ValueWord::from_int_array(Arc::new(data.clone().into()));
3528 assert!(nb.is_heap());
3529 let arr = nb.as_int_array().unwrap();
3530 assert_eq!(arr.as_slice(), &data);
3531 }
3532
3533 #[test]
3534 fn test_float_array_construction_and_roundtrip() {
3535 use crate::aligned_vec::AlignedVec;
3536 let mut aligned = AlignedVec::with_capacity(4);
3537 aligned.push(1.0);
3538 aligned.push(2.5);
3539 aligned.push(-3.14);
3540 aligned.push(0.0);
3541 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3542 assert!(nb.is_heap());
3543 let arr = nb.as_float_array().unwrap();
3544 assert_eq!(arr.len(), 4);
3545 assert_eq!(arr[0], 1.0);
3546 assert_eq!(arr[2], -3.14);
3547 }
3548
3549 #[test]
3550 fn test_bool_array_construction_and_roundtrip() {
3551 let data = vec![1u8, 0, 1, 1, 0];
3552 let nb = ValueWord::from_bool_array(Arc::new(data.clone().into()));
3553 assert!(nb.is_heap());
3554 let arr = nb.as_bool_array().unwrap();
3555 assert_eq!(arr.as_slice(), &data);
3556 }
3557
3558 #[test]
3559 fn test_int_array_type_name() {
3560 let nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3561 assert_eq!(nb.type_name(), "Vec<int>");
3562 }
3563
3564 #[test]
3565 fn test_float_array_type_name() {
3566 use crate::aligned_vec::AlignedVec;
3567 let mut aligned = AlignedVec::with_capacity(1);
3568 aligned.push(1.0);
3569 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3570 assert_eq!(nb.type_name(), "Vec<number>");
3571 }
3572
3573 #[test]
3574 fn test_bool_array_type_name() {
3575 let nb = ValueWord::from_bool_array(Arc::new(vec![0u8, 1].into()));
3576 assert_eq!(nb.type_name(), "Vec<bool>");
3577 }
3578
3579 #[test]
3580 fn test_int_array_is_truthy_nonempty() {
3581 let nb = ValueWord::from_int_array(Arc::new(vec![42i64].into()));
3582 assert!(nb.is_truthy());
3583 }
3584
3585 #[test]
3586 fn test_int_array_is_truthy_empty() {
3587 let nb = ValueWord::from_int_array(Arc::new(Vec::<i64>::new().into()));
3588 assert!(!nb.is_truthy());
3589 }
3590
3591 #[test]
3592 fn test_float_array_is_truthy_nonempty() {
3593 use crate::aligned_vec::AlignedVec;
3594 let mut aligned = AlignedVec::with_capacity(1);
3595 aligned.push(0.0);
3596 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3597 assert!(nb.is_truthy());
3598 }
3599
3600 #[test]
3601 fn test_float_array_is_truthy_empty() {
3602 use crate::aligned_vec::AlignedVec;
3603 let nb = ValueWord::from_float_array(Arc::new(AlignedVec::new().into()));
3604 assert!(!nb.is_truthy());
3605 }
3606
3607 #[test]
3608 fn test_bool_array_is_truthy_nonempty() {
3609 let nb = ValueWord::from_bool_array(Arc::new(vec![0u8].into()));
3610 assert!(nb.is_truthy());
3611 }
3612
3613 #[test]
3614 fn test_bool_array_is_truthy_empty() {
3615 let nb = ValueWord::from_bool_array(Arc::new(Vec::<u8>::new().into()));
3616 assert!(!nb.is_truthy());
3617 }
3618
3619 #[test]
3620 fn test_int_array_clone_arc_refcount() {
3621 let data: Arc<crate::typed_buffer::TypedBuffer<i64>> = Arc::new(vec![10i64, 20, 30].into());
3622 let nb1 = ValueWord::from_int_array(data.clone());
3623 let nb2 = nb1.clone();
3624 let arr1 = nb1.as_int_array().unwrap();
3625 let arr2 = nb2.as_int_array().unwrap();
3626 assert_eq!(arr1.as_ref(), arr2.as_ref());
3627 assert!(Arc::ptr_eq(arr1, arr2));
3628 }
3629
3630 #[test]
3631 fn test_float_array_clone_arc_refcount() {
3632 use crate::aligned_vec::AlignedVec;
3633 let mut aligned = AlignedVec::with_capacity(2);
3634 aligned.push(1.0);
3635 aligned.push(2.0);
3636 let data: Arc<crate::typed_buffer::AlignedTypedBuffer> = Arc::new(aligned.into());
3637 let nb1 = ValueWord::from_float_array(data.clone());
3638 let nb2 = nb1.clone();
3639 let arr1 = nb1.as_float_array().unwrap();
3640 let arr2 = nb2.as_float_array().unwrap();
3641 assert!(Arc::ptr_eq(arr1, arr2));
3642 }
3643
3644 #[test]
3645 fn test_typed_array_len() {
3646 let int_nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3647 assert_eq!(int_nb.typed_array_len(), Some(3));
3648
3649 use crate::aligned_vec::AlignedVec;
3650 let mut aligned = AlignedVec::with_capacity(2);
3651 aligned.push(1.0);
3652 aligned.push(2.0);
3653 let float_nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3654 assert_eq!(float_nb.typed_array_len(), Some(2));
3655
3656 let bool_nb = ValueWord::from_bool_array(Arc::new(vec![0u8, 1, 1, 0].into()));
3657 assert_eq!(bool_nb.typed_array_len(), Some(4));
3658
3659 let number_nb = ValueWord::from_f64(42.0);
3660 assert_eq!(number_nb.typed_array_len(), None);
3661 }
3662
3663 #[test]
3664 fn test_coerce_to_float_array_from_float() {
3665 use crate::aligned_vec::AlignedVec;
3666 let mut aligned = AlignedVec::with_capacity(3);
3667 aligned.push(1.0);
3668 aligned.push(2.0);
3669 aligned.push(3.0);
3670 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3671 let result = nb.coerce_to_float_array().unwrap();
3672 assert_eq!(result.len(), 3);
3673 assert_eq!(result[0], 1.0);
3674 }
3675
3676 #[test]
3677 fn test_coerce_to_float_array_from_int() {
3678 let nb = ValueWord::from_int_array(Arc::new(vec![10i64, 20, 30].into()));
3679 let result = nb.coerce_to_float_array().unwrap();
3680 assert_eq!(result.len(), 3);
3681 assert_eq!(result[0], 10.0);
3682 assert_eq!(result[1], 20.0);
3683 assert_eq!(result[2], 30.0);
3684 }
3685
3686 #[test]
3687 fn test_to_generic_array_int() {
3688 let nb = ValueWord::from_int_array(Arc::new(vec![5i64, 10].into()));
3689 let generic = nb.to_generic_array().unwrap();
3690 assert_eq!(generic.len(), 2);
3691 assert_eq!(generic[0].as_i64(), Some(5));
3692 assert_eq!(generic[1].as_i64(), Some(10));
3693 }
3694
3695 #[test]
3696 fn test_to_generic_array_float() {
3697 use crate::aligned_vec::AlignedVec;
3698 let mut aligned = AlignedVec::with_capacity(2);
3699 aligned.push(1.5);
3700 aligned.push(2.5);
3701 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3702 let generic = nb.to_generic_array().unwrap();
3703 assert_eq!(generic.len(), 2);
3704 assert_eq!(generic[0].as_f64(), Some(1.5));
3705 assert_eq!(generic[1].as_f64(), Some(2.5));
3706 }
3707
3708 #[test]
3709 fn test_to_generic_array_bool() {
3710 let nb = ValueWord::from_bool_array(Arc::new(vec![1u8, 0, 1].into()));
3711 let generic = nb.to_generic_array().unwrap();
3712 assert_eq!(generic.len(), 3);
3713 assert_eq!(generic[0].as_bool(), Some(true));
3714 assert_eq!(generic[1].as_bool(), Some(false));
3715 assert_eq!(generic[2].as_bool(), Some(true));
3716 }
3717
3718 #[test]
3719 fn test_int_array_nb_equals() {
3720 let a = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3721 let b = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3722 let c = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 4].into()));
3723 assert!(a.vw_equals(&b));
3724 assert!(!a.vw_equals(&c));
3725 }
3726
3727 #[test]
3728 fn test_float_array_nb_equals() {
3729 use crate::aligned_vec::AlignedVec;
3730 let mut a_data = AlignedVec::with_capacity(2);
3731 a_data.push(1.0);
3732 a_data.push(2.0);
3733 let mut b_data = AlignedVec::with_capacity(2);
3734 b_data.push(1.0);
3735 b_data.push(2.0);
3736 let a = ValueWord::from_float_array(Arc::new(a_data.into()));
3737 let b = ValueWord::from_float_array(Arc::new(b_data.into()));
3738 assert!(a.vw_equals(&b));
3739 }
3740
3741 #[test]
3742 fn test_cross_type_accessor_returns_none() {
3743 let int_nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2].into()));
3744 assert!(int_nb.as_float_array().is_none());
3745 assert!(int_nb.as_bool_array().is_none());
3746 assert!(int_nb.as_array().is_none());
3747
3748 use crate::aligned_vec::AlignedVec;
3749 let float_nb = ValueWord::from_float_array(Arc::new(AlignedVec::new().into()));
3750 assert!(float_nb.as_int_array().is_none());
3751
3752 let bool_nb = ValueWord::from_bool_array(Arc::new(Vec::<u8>::new().into()));
3753 assert!(bool_nb.as_int_array().is_none());
3754 assert!(bool_nb.as_float_array().is_none());
3755 }
3756}