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, ProjectedRefData, RefProjection, 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
48const REF_TARGET_MODULE_FLAG: u64 = 1 << 47;
49const REF_TARGET_INDEX_MASK: u64 = REF_TARGET_MODULE_FLAG - 1;
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum RefTarget {
53 Stack(usize),
54 ModuleBinding(usize),
55 Projected(ProjectedRefData),
56}
57
58use crate::tags::{
60 CANONICAL_NAN, I48_MAX, I48_MIN, PAYLOAD_MASK, TAG_BOOL, TAG_FUNCTION, TAG_HEAP, TAG_INT,
61 TAG_MODULE_FN, TAG_NONE, TAG_REF, TAG_UNIT, get_payload, get_tag, is_tagged, make_tagged,
62 sign_extend_i48,
63};
64
65macro_rules! define_nan_tag_types {
75 () => {
76 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
80 pub enum NanTag {
81 F64,
83 I48,
85 Bool,
87 None,
89 Unit,
91 Function,
93 ModuleFunction,
95 Heap,
97 Ref,
99 }
100
101 #[inline]
105 fn nan_tag_type_name(tag: u64) -> &'static str {
106 match tag {
107 TAG_INT => "int",
108 TAG_BOOL => "bool",
109 TAG_NONE => "option",
110 TAG_UNIT => "unit",
111 TAG_FUNCTION => "function",
112 TAG_MODULE_FN => "module_function",
113 TAG_REF => "reference",
114 _ => "unknown",
115 }
116 }
117
118 #[inline]
122 fn nan_tag_is_truthy(tag: u64, payload: u64) -> bool {
123 match tag {
124 TAG_INT => sign_extend_i48(payload) != 0,
125 TAG_BOOL => payload != 0,
126 TAG_NONE => false,
127 TAG_UNIT => false,
128 TAG_FUNCTION | TAG_MODULE_FN | TAG_REF => true,
129 _ => true,
130 }
131 }
132 };
133}
134
135define_nan_tag_types!();
136
137#[derive(Debug)]
145pub enum ArrayView<'a> {
146 Generic(&'a Arc<Vec<ValueWord>>),
147 Int(&'a Arc<crate::typed_buffer::TypedBuffer<i64>>),
148 Float(&'a Arc<crate::typed_buffer::AlignedTypedBuffer>),
149 Bool(&'a Arc<crate::typed_buffer::TypedBuffer<u8>>),
150 I8(&'a Arc<crate::typed_buffer::TypedBuffer<i8>>),
151 I16(&'a Arc<crate::typed_buffer::TypedBuffer<i16>>),
152 I32(&'a Arc<crate::typed_buffer::TypedBuffer<i32>>),
153 U8(&'a Arc<crate::typed_buffer::TypedBuffer<u8>>),
154 U16(&'a Arc<crate::typed_buffer::TypedBuffer<u16>>),
155 U32(&'a Arc<crate::typed_buffer::TypedBuffer<u32>>),
156 U64(&'a Arc<crate::typed_buffer::TypedBuffer<u64>>),
157 F32(&'a Arc<crate::typed_buffer::TypedBuffer<f32>>),
158}
159
160impl<'a> ArrayView<'a> {
161 #[inline]
162 pub fn len(&self) -> usize {
163 match self {
164 ArrayView::Generic(a) => a.len(),
165 ArrayView::Int(a) => a.len(),
166 ArrayView::Float(a) => a.len(),
167 ArrayView::Bool(a) => a.len(),
168 ArrayView::I8(a) => a.len(),
169 ArrayView::I16(a) => a.len(),
170 ArrayView::I32(a) => a.len(),
171 ArrayView::U8(a) => a.len(),
172 ArrayView::U16(a) => a.len(),
173 ArrayView::U32(a) => a.len(),
174 ArrayView::U64(a) => a.len(),
175 ArrayView::F32(a) => a.len(),
176 }
177 }
178
179 #[inline]
180 pub fn is_empty(&self) -> bool {
181 self.len() == 0
182 }
183
184 #[inline]
186 pub fn get_nb(&self, idx: usize) -> Option<ValueWord> {
187 match self {
188 ArrayView::Generic(a) => a.get(idx).cloned(),
189 ArrayView::Int(a) => a.get(idx).map(|&i| ValueWord::from_i64(i)),
190 ArrayView::Float(a) => a.get(idx).map(|&f| ValueWord::from_f64(f)),
191 ArrayView::Bool(a) => a.get(idx).map(|&b| ValueWord::from_bool(b != 0)),
192 ArrayView::I8(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
193 ArrayView::I16(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
194 ArrayView::I32(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
195 ArrayView::U8(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
196 ArrayView::U16(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
197 ArrayView::U32(a) => a.get(idx).map(|&v| ValueWord::from_i64(v as i64)),
198 ArrayView::U64(a) => a.get(idx).map(|&v| {
199 if v <= i64::MAX as u64 {
200 ValueWord::from_i64(v as i64)
201 } else {
202 ValueWord::from_native_u64(v)
203 }
204 }),
205 ArrayView::F32(a) => a.get(idx).map(|&v| ValueWord::from_f64(v as f64)),
206 }
207 }
208
209 #[inline]
210 pub fn first_nb(&self) -> Option<ValueWord> {
211 self.get_nb(0)
212 }
213
214 #[inline]
215 pub fn last_nb(&self) -> Option<ValueWord> {
216 if self.is_empty() {
217 None
218 } else {
219 self.get_nb(self.len() - 1)
220 }
221 }
222
223 pub fn to_generic(&self) -> Arc<Vec<ValueWord>> {
225 match self {
226 ArrayView::Generic(a) => (*a).clone(),
227 ArrayView::Int(a) => Arc::new(a.iter().map(|&i| ValueWord::from_i64(i)).collect()),
228 ArrayView::Float(a) => Arc::new(
229 a.as_slice()
230 .iter()
231 .map(|&f| ValueWord::from_f64(f))
232 .collect(),
233 ),
234 ArrayView::Bool(a) => {
235 Arc::new(a.iter().map(|&b| ValueWord::from_bool(b != 0)).collect())
236 }
237 ArrayView::I8(a) => {
238 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
239 }
240 ArrayView::I16(a) => {
241 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
242 }
243 ArrayView::I32(a) => {
244 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
245 }
246 ArrayView::U8(a) => {
247 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
248 }
249 ArrayView::U16(a) => {
250 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
251 }
252 ArrayView::U32(a) => {
253 Arc::new(a.iter().map(|&v| ValueWord::from_i64(v as i64)).collect())
254 }
255 ArrayView::U64(a) => Arc::new(
256 a.iter()
257 .map(|&v| {
258 if v <= i64::MAX as u64 {
259 ValueWord::from_i64(v as i64)
260 } else {
261 ValueWord::from_native_u64(v)
262 }
263 })
264 .collect(),
265 ),
266 ArrayView::F32(a) => {
267 Arc::new(a.iter().map(|&v| ValueWord::from_f64(v as f64)).collect())
268 }
269 }
270 }
271
272 #[inline]
273 pub fn as_i64_slice(&self) -> Option<&[i64]> {
274 if let ArrayView::Int(a) = self {
275 Some(a.as_slice())
276 } else {
277 None
278 }
279 }
280
281 #[inline]
282 pub fn as_f64_slice(&self) -> Option<&[f64]> {
283 if let ArrayView::Float(a) = self {
284 Some(a.as_slice())
285 } else {
286 None
287 }
288 }
289
290 #[inline]
291 pub fn as_bool_slice(&self) -> Option<&[u8]> {
292 if let ArrayView::Bool(a) = self {
293 Some(a.as_slice())
294 } else {
295 None
296 }
297 }
298
299 #[inline]
300 pub fn as_generic(&self) -> Option<&Arc<Vec<ValueWord>>> {
301 if let ArrayView::Generic(a) = self {
302 Some(a)
303 } else {
304 None
305 }
306 }
307
308 #[inline]
309 pub fn iter_i64(&self) -> Option<std::slice::Iter<'_, i64>> {
310 if let ArrayView::Int(a) = self {
311 Some(a.iter())
312 } else {
313 None
314 }
315 }
316
317 #[inline]
318 pub fn iter_f64(&self) -> Option<std::slice::Iter<'_, f64>> {
319 if let ArrayView::Float(a) = self {
320 Some(a.as_slice().iter())
321 } else {
322 None
323 }
324 }
325}
326
327pub enum ArrayViewMut<'a> {
329 Generic(&'a mut Arc<Vec<ValueWord>>),
330 Int(&'a mut Arc<crate::typed_buffer::TypedBuffer<i64>>),
331 Float(&'a mut Arc<crate::typed_buffer::AlignedTypedBuffer>),
332 Bool(&'a mut Arc<crate::typed_buffer::TypedBuffer<u8>>),
333}
334
335impl ArrayViewMut<'_> {
336 #[inline]
337 pub fn len(&self) -> usize {
338 match self {
339 ArrayViewMut::Generic(a) => a.len(),
340 ArrayViewMut::Int(a) => a.len(),
341 ArrayViewMut::Float(a) => a.len(),
342 ArrayViewMut::Bool(a) => a.len(),
343 }
344 }
345
346 pub fn pop_vw(&mut self) -> Option<ValueWord> {
347 match self {
348 ArrayViewMut::Generic(a) => Arc::make_mut(a).pop(),
349 ArrayViewMut::Int(a) => Arc::make_mut(a).data.pop().map(ValueWord::from_i64),
350 ArrayViewMut::Float(a) => Arc::make_mut(a).pop().map(ValueWord::from_f64),
351 ArrayViewMut::Bool(a) => Arc::make_mut(a)
352 .data
353 .pop()
354 .map(|b| ValueWord::from_bool(b != 0)),
355 }
356 }
357
358 pub fn push_vw(&mut self, val: ValueWord) -> Result<(), crate::context::VMError> {
359 match self {
360 ArrayViewMut::Generic(a) => {
361 Arc::make_mut(a).push(val);
362 Ok(())
363 }
364 ArrayViewMut::Int(a) => {
365 if let Some(i) = val.as_i64() {
366 Arc::make_mut(a).push(i);
367 Ok(())
368 } else {
369 Err(crate::context::VMError::TypeError {
370 expected: "int",
371 got: val.type_name(),
372 })
373 }
374 }
375 ArrayViewMut::Float(a) => {
376 if let Some(f) = val.as_number_coerce() {
377 Arc::make_mut(a).push(f);
378 Ok(())
379 } else {
380 Err(crate::context::VMError::TypeError {
381 expected: "number",
382 got: val.type_name(),
383 })
384 }
385 }
386 ArrayViewMut::Bool(a) => {
387 if let Some(b) = val.as_bool() {
388 Arc::make_mut(a).push(if b { 1 } else { 0 });
389 Ok(())
390 } else {
391 Err(crate::context::VMError::TypeError {
392 expected: "bool",
393 got: val.type_name(),
394 })
395 }
396 }
397 }
398 }
399}
400
401#[repr(transparent)]
407pub struct ValueWord(u64);
408
409impl ValueWord {
410 #[inline]
417 pub fn from_f64(v: f64) -> Self {
418 let bits = v.to_bits();
419 if v.is_nan() {
420 Self(CANONICAL_NAN)
422 } else if is_tagged(bits) {
423 Self(CANONICAL_NAN)
428 } else {
429 Self(bits)
430 }
431 }
432
433 #[inline]
438 pub fn from_i64(v: i64) -> Self {
439 if v >= I48_MIN && v <= I48_MAX {
440 let payload = (v as u64) & PAYLOAD_MASK;
443 Self(make_tagged(TAG_INT, payload))
444 } else {
445 Self::heap_box(HeapValue::BigInt(v))
447 }
448 }
449
450 #[inline]
452 pub fn from_native_scalar(value: NativeScalar) -> Self {
453 Self::heap_box(HeapValue::NativeScalar(value))
454 }
455
456 #[inline]
457 pub fn from_native_i8(v: i8) -> Self {
458 Self::from_native_scalar(NativeScalar::I8(v))
459 }
460
461 #[inline]
462 pub fn from_native_u8(v: u8) -> Self {
463 Self::from_native_scalar(NativeScalar::U8(v))
464 }
465
466 #[inline]
467 pub fn from_native_i16(v: i16) -> Self {
468 Self::from_native_scalar(NativeScalar::I16(v))
469 }
470
471 #[inline]
472 pub fn from_native_u16(v: u16) -> Self {
473 Self::from_native_scalar(NativeScalar::U16(v))
474 }
475
476 #[inline]
477 pub fn from_native_i32(v: i32) -> Self {
478 Self::from_native_scalar(NativeScalar::I32(v))
479 }
480
481 #[inline]
482 pub fn from_native_u32(v: u32) -> Self {
483 Self::from_native_scalar(NativeScalar::U32(v))
484 }
485
486 #[inline]
487 pub fn from_native_u64(v: u64) -> Self {
488 Self::from_native_scalar(NativeScalar::U64(v))
489 }
490
491 #[inline]
492 pub fn from_native_isize(v: isize) -> Self {
493 Self::from_native_scalar(NativeScalar::Isize(v))
494 }
495
496 #[inline]
497 pub fn from_native_usize(v: usize) -> Self {
498 Self::from_native_scalar(NativeScalar::Usize(v))
499 }
500
501 #[inline]
502 pub fn from_native_ptr(v: usize) -> Self {
503 Self::from_native_scalar(NativeScalar::Ptr(v))
504 }
505
506 #[inline]
507 pub fn from_native_f32(v: f32) -> Self {
508 Self::from_native_scalar(NativeScalar::F32(v))
509 }
510
511 #[inline]
513 pub fn from_c_view(ptr: usize, layout: Arc<NativeTypeLayout>) -> Self {
514 Self::heap_box(HeapValue::NativeView(Box::new(NativeViewData {
515 ptr,
516 layout,
517 mutable: false,
518 })))
519 }
520
521 #[inline]
523 pub fn from_c_mut(ptr: usize, layout: Arc<NativeTypeLayout>) -> Self {
524 Self::heap_box(HeapValue::NativeView(Box::new(NativeViewData {
525 ptr,
526 layout,
527 mutable: true,
528 })))
529 }
530
531 #[inline]
533 pub fn from_bool(v: bool) -> Self {
534 Self(make_tagged(TAG_BOOL, v as u64))
535 }
536
537 #[inline]
539 pub fn none() -> Self {
540 Self(make_tagged(TAG_NONE, 0))
541 }
542
543 #[inline]
545 pub fn unit() -> Self {
546 Self(make_tagged(TAG_UNIT, 0))
547 }
548
549 #[inline]
554 pub fn from_function(id: u16) -> Self {
555 Self(make_tagged(TAG_FUNCTION, id as u64))
556 }
557
558 #[inline]
560 pub fn from_module_function(index: u32) -> Self {
561 Self(make_tagged(TAG_MODULE_FN, index as u64))
562 }
563
564 #[inline]
566 pub fn from_ref(absolute_slot: usize) -> Self {
567 Self(make_tagged(TAG_REF, absolute_slot as u64))
568 }
569
570 #[inline]
572 pub fn from_module_binding_ref(binding_idx: usize) -> Self {
573 Self(make_tagged(
574 TAG_REF,
575 REF_TARGET_MODULE_FLAG | (binding_idx as u64 & REF_TARGET_INDEX_MASK),
576 ))
577 }
578
579 #[inline]
581 pub fn from_projected_ref(base: ValueWord, projection: RefProjection) -> Self {
582 Self::heap_box(HeapValue::ProjectedRef(Box::new(ProjectedRefData {
583 base,
584 projection,
585 })))
586 }
587
588 #[inline]
593 #[cfg(not(feature = "gc"))]
594 pub(crate) fn heap_box(v: HeapValue) -> Self {
595 let arc = Arc::new(v);
596 let ptr = Arc::into_raw(arc) as u64;
597 debug_assert!(
598 ptr & !PAYLOAD_MASK == 0,
599 "pointer exceeds 48 bits — platform not supported"
600 );
601 Self(make_tagged(TAG_HEAP, ptr & PAYLOAD_MASK))
602 }
603
604 #[inline]
608 #[cfg(feature = "gc")]
609 pub(crate) fn heap_box(v: HeapValue) -> Self {
610 let heap = shape_gc::thread_gc_heap();
611 let ptr = heap.alloc(v) as u64;
612 debug_assert!(
613 ptr & !PAYLOAD_MASK == 0,
614 "GC pointer exceeds 48 bits — platform not supported"
615 );
616 Self(make_tagged(TAG_HEAP, ptr & PAYLOAD_MASK))
617 }
618
619 #[inline]
623 pub fn from_string(s: Arc<String>) -> Self {
624 Self::heap_box(HeapValue::String(s))
625 }
626
627 #[inline]
629 pub fn from_char(c: char) -> Self {
630 Self::heap_box(HeapValue::Char(c))
631 }
632
633 #[inline]
635 pub fn as_char(&self) -> Option<char> {
636 if let Some(HeapValue::Char(c)) = self.as_heap_ref() {
637 Some(*c)
638 } else {
639 std::option::Option::None
640 }
641 }
642
643 #[inline]
645 pub fn from_array(a: crate::value::VMArray) -> Self {
646 Self::heap_box(HeapValue::Array(a))
647 }
648
649 #[inline]
651 pub fn from_decimal(d: rust_decimal::Decimal) -> Self {
652 Self::heap_box(HeapValue::Decimal(d))
653 }
654
655 #[inline]
660 pub fn from_heap_value(v: HeapValue) -> Self {
661 match v {
662 HeapValue::BigInt(i) => Self::from_i64(i),
663 other => Self::heap_box(other),
664 }
665 }
666
667 #[inline]
671 pub fn from_datatable(dt: Arc<DataTable>) -> Self {
672 Self::heap_box(HeapValue::DataTable(dt))
673 }
674
675 #[inline]
677 pub fn from_typed_table(schema_id: u64, table: Arc<DataTable>) -> Self {
678 Self::heap_box(HeapValue::TypedTable { schema_id, table })
679 }
680
681 #[inline]
683 pub fn from_row_view(schema_id: u64, table: Arc<DataTable>, row_idx: usize) -> Self {
684 Self::heap_box(HeapValue::RowView {
685 schema_id,
686 table,
687 row_idx,
688 })
689 }
690
691 #[inline]
693 pub fn from_column_ref(schema_id: u64, table: Arc<DataTable>, col_id: u32) -> Self {
694 Self::heap_box(HeapValue::ColumnRef {
695 schema_id,
696 table,
697 col_id,
698 })
699 }
700
701 #[inline]
703 pub fn from_indexed_table(schema_id: u64, table: Arc<DataTable>, index_col: u32) -> Self {
704 Self::heap_box(HeapValue::IndexedTable {
705 schema_id,
706 table,
707 index_col,
708 })
709 }
710
711 #[inline]
715 pub fn from_range(start: Option<ValueWord>, end: Option<ValueWord>, inclusive: bool) -> Self {
716 Self::heap_box(HeapValue::Range {
717 start: start.map(Box::new),
718 end: end.map(Box::new),
719 inclusive,
720 })
721 }
722
723 #[inline]
725 pub fn from_enum(e: EnumValue) -> Self {
726 Self::heap_box(HeapValue::Enum(Box::new(e)))
727 }
728
729 #[inline]
731 pub fn from_some(inner: ValueWord) -> Self {
732 Self::heap_box(HeapValue::Some(Box::new(inner)))
733 }
734
735 #[inline]
737 pub fn from_ok(inner: ValueWord) -> Self {
738 Self::heap_box(HeapValue::Ok(Box::new(inner)))
739 }
740
741 #[inline]
743 pub fn from_err(inner: ValueWord) -> Self {
744 Self::heap_box(HeapValue::Err(Box::new(inner)))
745 }
746
747 #[inline]
751 pub fn from_hashmap(
752 keys: Vec<ValueWord>,
753 values: Vec<ValueWord>,
754 index: HashMap<u64, Vec<usize>>,
755 ) -> ValueWord {
756 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
757 keys,
758 values,
759 index,
760 shape_id: None,
761 })))
762 }
763
764 #[inline]
766 pub fn empty_hashmap() -> ValueWord {
767 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
768 keys: Vec::new(),
769 values: Vec::new(),
770 index: HashMap::new(),
771 shape_id: None,
772 })))
773 }
774
775 #[inline]
778 pub fn from_hashmap_pairs(keys: Vec<ValueWord>, values: Vec<ValueWord>) -> ValueWord {
779 let index = HashMapData::rebuild_index(&keys);
780 let shape_id = HashMapData::compute_shape(&keys);
781 ValueWord::heap_box(HeapValue::HashMap(Box::new(HashMapData {
782 keys,
783 values,
784 index,
785 shape_id,
786 })))
787 }
788
789 #[inline]
793 pub fn from_set(items: Vec<ValueWord>) -> ValueWord {
794 ValueWord::heap_box(HeapValue::Set(Box::new(SetData::from_items(items))))
795 }
796
797 #[inline]
799 pub fn empty_set() -> ValueWord {
800 ValueWord::heap_box(HeapValue::Set(Box::new(SetData {
801 items: Vec::new(),
802 index: HashMap::new(),
803 })))
804 }
805
806 #[inline]
810 pub fn from_deque(items: Vec<ValueWord>) -> ValueWord {
811 ValueWord::heap_box(HeapValue::Deque(Box::new(DequeData::from_items(items))))
812 }
813
814 #[inline]
816 pub fn empty_deque() -> ValueWord {
817 ValueWord::heap_box(HeapValue::Deque(Box::new(DequeData::new())))
818 }
819
820 #[inline]
824 pub fn from_priority_queue(items: Vec<ValueWord>) -> ValueWord {
825 ValueWord::heap_box(HeapValue::PriorityQueue(Box::new(
826 PriorityQueueData::from_items(items),
827 )))
828 }
829
830 #[inline]
832 pub fn empty_priority_queue() -> ValueWord {
833 ValueWord::heap_box(HeapValue::PriorityQueue(Box::new(PriorityQueueData::new())))
834 }
835
836 #[inline]
840 pub fn from_content(node: ContentNode) -> ValueWord {
841 ValueWord::heap_box(HeapValue::Content(Box::new(node)))
842 }
843
844 #[inline]
848 pub fn from_int_array(a: Arc<crate::typed_buffer::TypedBuffer<i64>>) -> Self {
849 Self::heap_box(HeapValue::IntArray(a))
850 }
851
852 #[inline]
854 pub fn from_float_array(a: Arc<crate::typed_buffer::AlignedTypedBuffer>) -> Self {
855 Self::heap_box(HeapValue::FloatArray(a))
856 }
857
858 #[inline]
860 pub fn from_bool_array(a: Arc<crate::typed_buffer::TypedBuffer<u8>>) -> Self {
861 Self::heap_box(HeapValue::BoolArray(a))
862 }
863
864 #[inline]
866 pub fn from_i8_array(a: Arc<crate::typed_buffer::TypedBuffer<i8>>) -> Self {
867 Self::heap_box(HeapValue::I8Array(a))
868 }
869
870 #[inline]
872 pub fn from_i16_array(a: Arc<crate::typed_buffer::TypedBuffer<i16>>) -> Self {
873 Self::heap_box(HeapValue::I16Array(a))
874 }
875
876 #[inline]
878 pub fn from_i32_array(a: Arc<crate::typed_buffer::TypedBuffer<i32>>) -> Self {
879 Self::heap_box(HeapValue::I32Array(a))
880 }
881
882 #[inline]
884 pub fn from_u8_array(a: Arc<crate::typed_buffer::TypedBuffer<u8>>) -> Self {
885 Self::heap_box(HeapValue::U8Array(a))
886 }
887
888 #[inline]
890 pub fn from_u16_array(a: Arc<crate::typed_buffer::TypedBuffer<u16>>) -> Self {
891 Self::heap_box(HeapValue::U16Array(a))
892 }
893
894 #[inline]
896 pub fn from_u32_array(a: Arc<crate::typed_buffer::TypedBuffer<u32>>) -> Self {
897 Self::heap_box(HeapValue::U32Array(a))
898 }
899
900 #[inline]
902 pub fn from_u64_array(a: Arc<crate::typed_buffer::TypedBuffer<u64>>) -> Self {
903 Self::heap_box(HeapValue::U64Array(a))
904 }
905
906 #[inline]
908 pub fn from_f32_array(a: Arc<crate::typed_buffer::TypedBuffer<f32>>) -> Self {
909 Self::heap_box(HeapValue::F32Array(a))
910 }
911
912 #[inline]
914 pub fn from_matrix(m: Arc<crate::heap_value::MatrixData>) -> Self {
915 Self::heap_box(HeapValue::Matrix(m))
916 }
917
918 #[inline]
920 pub fn from_float_array_slice(
921 parent: Arc<crate::heap_value::MatrixData>,
922 offset: u32,
923 len: u32,
924 ) -> Self {
925 Self::heap_box(HeapValue::FloatArraySlice {
926 parent,
927 offset,
928 len,
929 })
930 }
931
932 #[inline]
934 pub fn from_iterator(state: Box<crate::heap_value::IteratorState>) -> Self {
935 Self::heap_box(HeapValue::Iterator(state))
936 }
937
938 #[inline]
940 pub fn from_generator(state: Box<crate::heap_value::GeneratorState>) -> Self {
941 Self::heap_box(HeapValue::Generator(state))
942 }
943
944 #[inline]
948 pub fn from_future(id: u64) -> Self {
949 Self::heap_box(HeapValue::Future(id))
950 }
951
952 #[inline]
954 pub fn from_task_group(kind: u8, task_ids: Vec<u64>) -> Self {
955 Self::heap_box(HeapValue::TaskGroup { kind, task_ids })
956 }
957
958 #[inline]
960 pub fn from_mutex(value: ValueWord) -> Self {
961 Self::heap_box(HeapValue::Mutex(Box::new(
962 crate::heap_value::MutexData::new(value),
963 )))
964 }
965
966 #[inline]
968 pub fn from_atomic(value: i64) -> Self {
969 Self::heap_box(HeapValue::Atomic(Box::new(
970 crate::heap_value::AtomicData::new(value),
971 )))
972 }
973
974 #[inline]
976 pub fn from_lazy(initializer: ValueWord) -> Self {
977 Self::heap_box(HeapValue::Lazy(Box::new(crate::heap_value::LazyData::new(
978 initializer,
979 ))))
980 }
981
982 #[inline]
984 pub fn from_channel(data: ChannelData) -> Self {
985 Self::heap_box(HeapValue::Channel(Box::new(data)))
986 }
987
988 #[inline]
992 pub fn from_trait_object(value: ValueWord, vtable: Arc<VTable>) -> Self {
993 Self::heap_box(HeapValue::TraitObject {
994 value: Box::new(value),
995 vtable,
996 })
997 }
998
999 #[inline]
1003 pub fn from_expr_proxy(col_name: Arc<String>) -> Self {
1004 Self::heap_box(HeapValue::ExprProxy(col_name))
1005 }
1006
1007 #[inline]
1009 pub fn from_filter_expr(node: Arc<FilterNode>) -> Self {
1010 Self::heap_box(HeapValue::FilterExpr(node))
1011 }
1012
1013 #[inline]
1017 pub fn from_instant(t: std::time::Instant) -> Self {
1018 Self::heap_box(HeapValue::Instant(Box::new(t)))
1019 }
1020
1021 #[inline]
1025 pub fn from_io_handle(data: crate::heap_value::IoHandleData) -> Self {
1026 Self::heap_box(HeapValue::IoHandle(Box::new(data)))
1027 }
1028
1029 #[inline]
1033 pub fn from_time(t: DateTime<FixedOffset>) -> Self {
1034 Self::heap_box(HeapValue::Time(t))
1035 }
1036
1037 #[inline]
1039 pub fn from_time_utc(t: DateTime<Utc>) -> Self {
1040 Self::heap_box(HeapValue::Time(t.fixed_offset()))
1041 }
1042
1043 #[inline]
1045 pub fn from_duration(d: Duration) -> Self {
1046 Self::heap_box(HeapValue::Duration(d))
1047 }
1048
1049 #[inline]
1051 pub fn from_timespan(ts: chrono::Duration) -> Self {
1052 Self::heap_box(HeapValue::TimeSpan(ts))
1053 }
1054
1055 #[inline]
1057 pub fn from_timeframe(tf: Timeframe) -> Self {
1058 Self::heap_box(HeapValue::Timeframe(tf))
1059 }
1060
1061 #[inline]
1065 pub fn from_host_closure(nc: HostCallable) -> Self {
1066 Self::heap_box(HeapValue::HostClosure(nc))
1067 }
1068
1069 #[inline]
1071 pub fn from_print_result(pr: PrintResult) -> Self {
1072 Self::heap_box(HeapValue::PrintResult(Box::new(pr)))
1073 }
1074
1075 #[inline]
1077 pub fn from_simulation_call(name: String, params: HashMap<String, ValueWord>) -> Self {
1078 Self::heap_box(HeapValue::SimulationCall(Box::new(
1079 crate::heap_value::SimulationCallData { name, params },
1080 )))
1081 }
1082
1083 #[inline]
1085 pub fn from_function_ref(name: String, closure: Option<ValueWord>) -> Self {
1086 Self::heap_box(HeapValue::FunctionRef {
1087 name,
1088 closure: closure.map(Box::new),
1089 })
1090 }
1091
1092 #[inline]
1094 pub fn from_data_reference(
1095 datetime: DateTime<FixedOffset>,
1096 id: String,
1097 timeframe: Timeframe,
1098 ) -> Self {
1099 Self::heap_box(HeapValue::DataReference(Box::new(
1100 crate::heap_value::DataReferenceData {
1101 datetime,
1102 id,
1103 timeframe,
1104 },
1105 )))
1106 }
1107
1108 #[inline]
1110 pub fn from_time_reference(tr: TimeReference) -> Self {
1111 Self::heap_box(HeapValue::TimeReference(Box::new(tr)))
1112 }
1113
1114 #[inline]
1116 pub fn from_datetime_expr(de: DateTimeExpr) -> Self {
1117 Self::heap_box(HeapValue::DateTimeExpr(Box::new(de)))
1118 }
1119
1120 #[inline]
1122 pub fn from_data_datetime_ref(dr: DataDateTimeRef) -> Self {
1123 Self::heap_box(HeapValue::DataDateTimeRef(Box::new(dr)))
1124 }
1125
1126 #[inline]
1128 pub fn from_type_annotation(ta: TypeAnnotation) -> Self {
1129 Self::heap_box(HeapValue::TypeAnnotation(Box::new(ta)))
1130 }
1131
1132 #[inline]
1134 pub fn from_type_annotated_value(type_name: String, value: ValueWord) -> Self {
1135 Self::heap_box(HeapValue::TypeAnnotatedValue {
1136 type_name,
1137 value: Box::new(value),
1138 })
1139 }
1140
1141 #[inline(always)]
1151 #[cfg(not(feature = "gc"))]
1152 pub unsafe fn clone_from_bits(bits: u64) -> Self {
1153 if is_tagged(bits) && get_tag(bits) == TAG_HEAP {
1154 let ptr = get_payload(bits) as *const HeapValue;
1155 unsafe { Arc::increment_strong_count(ptr) };
1156 }
1157 Self(bits)
1158 }
1159
1160 #[inline(always)]
1165 #[cfg(feature = "gc")]
1166 pub unsafe fn clone_from_bits(bits: u64) -> Self {
1167 Self(bits)
1169 }
1170
1171 #[inline(always)]
1175 pub fn is_f64(&self) -> bool {
1176 !is_tagged(self.0)
1177 }
1178
1179 #[inline(always)]
1181 pub fn is_i64(&self) -> bool {
1182 is_tagged(self.0) && get_tag(self.0) == TAG_INT
1183 }
1184
1185 #[inline(always)]
1187 pub fn is_bool(&self) -> bool {
1188 is_tagged(self.0) && get_tag(self.0) == TAG_BOOL
1189 }
1190
1191 #[inline(always)]
1193 pub fn is_none(&self) -> bool {
1194 is_tagged(self.0) && get_tag(self.0) == TAG_NONE
1195 }
1196
1197 #[inline(always)]
1199 pub fn is_unit(&self) -> bool {
1200 is_tagged(self.0) && get_tag(self.0) == TAG_UNIT
1201 }
1202
1203 #[inline(always)]
1205 pub fn is_function(&self) -> bool {
1206 is_tagged(self.0) && get_tag(self.0) == TAG_FUNCTION
1207 }
1208
1209 #[inline(always)]
1211 pub fn is_heap(&self) -> bool {
1212 is_tagged(self.0) && get_tag(self.0) == TAG_HEAP
1213 }
1214
1215 #[inline(always)]
1217 pub fn is_ref(&self) -> bool {
1218 if is_tagged(self.0) {
1219 return get_tag(self.0) == TAG_REF;
1220 }
1221 matches!(self.as_heap_ref(), Some(HeapValue::ProjectedRef(_)))
1222 }
1223
1224 #[inline]
1226 pub fn as_ref_target(&self) -> Option<RefTarget> {
1227 if is_tagged(self.0) && get_tag(self.0) == TAG_REF {
1228 let payload = get_payload(self.0);
1229 let idx = (payload & REF_TARGET_INDEX_MASK) as usize;
1230 if payload & REF_TARGET_MODULE_FLAG != 0 {
1231 return Some(RefTarget::ModuleBinding(idx));
1232 }
1233 return Some(RefTarget::Stack(idx));
1234 }
1235 if let Some(HeapValue::ProjectedRef(data)) = self.as_heap_ref() {
1236 return Some(RefTarget::Projected((**data).clone()));
1237 }
1238 None
1239 }
1240
1241 #[inline]
1243 pub fn as_ref_slot(&self) -> Option<usize> {
1244 match self.as_ref_target() {
1245 Some(RefTarget::Stack(slot)) => Some(slot),
1246 _ => None,
1247 }
1248 }
1249
1250 #[inline]
1254 pub fn as_f64(&self) -> Option<f64> {
1255 if self.is_f64() {
1256 Some(f64::from_bits(self.0))
1257 } else {
1258 None
1259 }
1260 }
1261
1262 #[inline]
1266 pub fn as_i64(&self) -> Option<i64> {
1267 if self.is_i64() {
1268 Some(sign_extend_i48(get_payload(self.0)))
1269 } else if let Some(HeapValue::BigInt(v)) = self.as_heap_ref() {
1270 Some(*v)
1271 } else if let Some(HeapValue::NativeScalar(v)) = self.as_heap_ref() {
1272 v.as_i64()
1273 } else {
1274 None
1275 }
1276 }
1277
1278 #[inline]
1280 pub fn as_u64(&self) -> Option<u64> {
1281 if self.is_i64() {
1282 let v = sign_extend_i48(get_payload(self.0));
1283 return u64::try_from(v).ok();
1284 }
1285
1286 if let Some(hv) = self.as_heap_ref() {
1287 return match hv {
1288 HeapValue::BigInt(v) => u64::try_from(*v).ok(),
1289 HeapValue::NativeScalar(v) => v.as_u64(),
1290 _ => None,
1291 };
1292 }
1293
1294 None
1295 }
1296
1297 #[inline]
1299 pub fn as_i128_exact(&self) -> Option<i128> {
1300 if self.is_i64() {
1301 return Some(sign_extend_i48(get_payload(self.0)) as i128);
1302 }
1303
1304 if let Some(hv) = self.as_heap_ref() {
1305 return match hv {
1306 HeapValue::BigInt(v) => Some(*v as i128),
1307 HeapValue::NativeScalar(v) => v.as_i128(),
1308 _ => None,
1309 };
1310 }
1311
1312 None
1313 }
1314
1315 #[inline]
1317 pub fn as_number_strict(&self) -> Option<f64> {
1318 if self.is_f64() {
1319 return Some(f64::from_bits(self.0));
1320 }
1321 if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1323 return Some(sign_extend_i48(get_payload(self.0)) as f64);
1324 }
1325 if let Some(hv) = self.as_heap_ref() {
1326 return match hv {
1327 HeapValue::NativeScalar(NativeScalar::F32(v)) => Some(*v as f64),
1328 _ => None,
1329 };
1330 }
1331 None
1332 }
1333
1334 #[inline]
1336 pub fn as_bool(&self) -> Option<bool> {
1337 if self.is_bool() {
1338 Some(get_payload(self.0) != 0)
1339 } else {
1340 None
1341 }
1342 }
1343
1344 #[inline]
1346 pub fn as_function(&self) -> Option<u16> {
1347 if self.is_function() {
1348 Some(get_payload(self.0) as u16)
1349 } else {
1350 None
1351 }
1352 }
1353
1354 #[inline(always)]
1362 pub unsafe fn as_f64_unchecked(&self) -> f64 {
1363 if self.is_f64() {
1364 f64::from_bits(self.0)
1365 } else if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1366 sign_extend_i48(get_payload(self.0)) as f64
1367 } else {
1368 debug_assert!(false, "as_f64_unchecked on non-numeric ValueWord");
1369 0.0
1370 }
1371 }
1372
1373 #[inline(always)]
1379 pub unsafe fn as_i64_unchecked(&self) -> i64 {
1380 if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1381 sign_extend_i48(get_payload(self.0))
1382 } else if self.is_f64() {
1383 f64::from_bits(self.0) as i64
1384 } else {
1385 debug_assert!(false, "as_i64_unchecked on non-numeric ValueWord");
1386 0
1387 }
1388 }
1389
1390 #[inline(always)]
1395 pub unsafe fn as_bool_unchecked(&self) -> bool {
1396 debug_assert!(self.is_bool(), "as_bool_unchecked on non-bool ValueWord");
1397 get_payload(self.0) != 0
1398 }
1399
1400 #[inline(always)]
1405 pub unsafe fn as_function_unchecked(&self) -> u16 {
1406 debug_assert!(
1407 self.is_function(),
1408 "as_function_unchecked on non-function ValueWord"
1409 );
1410 get_payload(self.0) as u16
1411 }
1412
1413 #[inline]
1418 pub fn as_heap_ref(&self) -> Option<&HeapValue> {
1419 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1420 let ptr = get_payload(self.0) as *const HeapValue;
1421 Some(unsafe { &*ptr })
1422 } else {
1423 None
1424 }
1425 }
1426
1427 #[inline]
1433 #[cfg(not(feature = "gc"))]
1434 pub fn as_heap_mut(&mut self) -> Option<&mut HeapValue> {
1435 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1436 let ptr = get_payload(self.0) as *const HeapValue;
1437 let mut arc = unsafe { Arc::from_raw(ptr) };
1439 Arc::make_mut(&mut arc);
1441 let new_ptr = Arc::into_raw(arc) as u64;
1444 self.0 = make_tagged(TAG_HEAP, new_ptr & PAYLOAD_MASK);
1445 let final_ptr = get_payload(self.0) as *mut HeapValue;
1446 Some(unsafe { &mut *final_ptr })
1447 } else {
1448 None
1449 }
1450 }
1451
1452 #[inline]
1457 #[cfg(feature = "gc")]
1458 pub fn as_heap_mut(&mut self) -> Option<&mut HeapValue> {
1459 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
1460 let ptr = get_payload(self.0) as *mut HeapValue;
1461 Some(unsafe { &mut *ptr })
1462 } else {
1463 None
1464 }
1465 }
1466
1467 #[inline]
1469 pub fn is_truthy(&self) -> bool {
1470 if !is_tagged(self.0) {
1471 let f = f64::from_bits(self.0);
1473 return f != 0.0 && !f.is_nan();
1474 }
1475 let tag = get_tag(self.0);
1476 if tag == TAG_HEAP {
1477 let ptr = get_payload(self.0) as *const HeapValue;
1478 return unsafe { (*ptr).is_truthy() };
1479 }
1480 nan_tag_is_truthy(tag, get_payload(self.0))
1481 }
1482
1483 #[inline]
1492 pub fn as_number_coerce(&self) -> Option<f64> {
1493 if let Some(n) = self.as_number_strict() {
1494 Some(n)
1495 } else if is_tagged(self.0) && get_tag(self.0) == TAG_INT {
1496 Some(sign_extend_i48(get_payload(self.0)) as f64)
1497 } else {
1498 None
1499 }
1500 }
1501
1502 #[inline(always)]
1504 pub fn is_module_function(&self) -> bool {
1505 is_tagged(self.0) && get_tag(self.0) == TAG_MODULE_FN
1506 }
1507
1508 #[inline]
1510 pub fn as_module_function(&self) -> Option<usize> {
1511 if self.is_module_function() {
1512 Some(get_payload(self.0) as usize)
1513 } else {
1514 None
1515 }
1516 }
1517
1518 #[inline]
1523 pub fn heap_kind(&self) -> Option<crate::heap_value::HeapKind> {
1524 if let Some(hv) = self.as_heap_ref() {
1525 Some(hv.kind())
1526 } else {
1527 std::option::Option::None
1528 }
1529 }
1530
1531 #[inline]
1536 pub fn tag(&self) -> NanTag {
1537 if !is_tagged(self.0) {
1538 return NanTag::F64;
1539 }
1540 match get_tag(self.0) {
1541 TAG_INT => NanTag::I48,
1542 TAG_BOOL => NanTag::Bool,
1543 TAG_NONE => NanTag::None,
1544 TAG_UNIT => NanTag::Unit,
1545 TAG_FUNCTION => NanTag::Function,
1546 TAG_MODULE_FN => NanTag::ModuleFunction,
1547 TAG_HEAP => NanTag::Heap,
1548 TAG_REF => NanTag::Ref,
1549 _ => unreachable!("invalid ValueWord tag"),
1550 }
1551 }
1552
1553 #[inline]
1556 pub fn as_str(&self) -> Option<&str> {
1557 if let Some(hv) = self.as_heap_ref() {
1558 match hv {
1559 HeapValue::String(s) => Some(s.as_str()),
1560 _ => std::option::Option::None,
1561 }
1562 } else {
1563 std::option::Option::None
1564 }
1565 }
1566
1567 #[inline]
1570 pub fn as_decimal(&self) -> Option<rust_decimal::Decimal> {
1571 if let Some(hv) = self.as_heap_ref() {
1572 match hv {
1573 HeapValue::Decimal(d) => Some(*d),
1574 _ => std::option::Option::None,
1575 }
1576 } else {
1577 std::option::Option::None
1578 }
1579 }
1580
1581 #[inline(always)]
1586 pub unsafe fn as_decimal_unchecked(&self) -> rust_decimal::Decimal {
1587 debug_assert!(matches!(self.as_heap_ref(), Some(HeapValue::Decimal(_))));
1588 match unsafe { self.as_heap_ref().unwrap_unchecked() } {
1589 HeapValue::Decimal(d) => *d,
1590 _ => unsafe { std::hint::unreachable_unchecked() },
1591 }
1592 }
1593
1594 #[inline]
1597 #[deprecated(note = "Use as_any_array() instead for unified typed array dispatch")]
1598 pub fn as_array(&self) -> Option<&VMArray> {
1599 if let Some(hv) = self.as_heap_ref() {
1600 match hv {
1601 HeapValue::Array(arr) => Some(arr),
1602 _ => std::option::Option::None,
1603 }
1604 } else {
1605 std::option::Option::None
1606 }
1607 }
1608
1609 #[inline]
1611 pub fn as_any_array(&self) -> Option<ArrayView<'_>> {
1612 match self.as_heap_ref()? {
1613 HeapValue::Array(a) => Some(ArrayView::Generic(a)),
1614 HeapValue::IntArray(a) => Some(ArrayView::Int(a)),
1615 HeapValue::FloatArray(a) => Some(ArrayView::Float(a)),
1616 HeapValue::BoolArray(a) => Some(ArrayView::Bool(a)),
1617 HeapValue::I8Array(a) => Some(ArrayView::I8(a)),
1618 HeapValue::I16Array(a) => Some(ArrayView::I16(a)),
1619 HeapValue::I32Array(a) => Some(ArrayView::I32(a)),
1620 HeapValue::U8Array(a) => Some(ArrayView::U8(a)),
1621 HeapValue::U16Array(a) => Some(ArrayView::U16(a)),
1622 HeapValue::U32Array(a) => Some(ArrayView::U32(a)),
1623 HeapValue::U64Array(a) => Some(ArrayView::U64(a)),
1624 HeapValue::F32Array(a) => Some(ArrayView::F32(a)),
1625 _ => None,
1626 }
1627 }
1628
1629 #[inline]
1631 pub fn as_any_array_mut(&mut self) -> Option<ArrayViewMut<'_>> {
1632 match self.as_heap_mut()? {
1633 HeapValue::Array(a) => Some(ArrayViewMut::Generic(a)),
1634 HeapValue::IntArray(a) => Some(ArrayViewMut::Int(a)),
1635 HeapValue::FloatArray(a) => Some(ArrayViewMut::Float(a)),
1636 HeapValue::BoolArray(a) => Some(ArrayViewMut::Bool(a)),
1637 _ => None,
1638 }
1639 }
1640
1641 #[inline]
1645 pub fn as_datatable(&self) -> Option<&Arc<DataTable>> {
1646 match self.as_heap_ref()? {
1647 HeapValue::DataTable(dt) => Some(dt),
1648 _ => std::option::Option::None,
1649 }
1650 }
1651
1652 #[inline]
1654 pub fn as_typed_table(&self) -> Option<(u64, &Arc<DataTable>)> {
1655 match self.as_heap_ref()? {
1656 HeapValue::TypedTable { schema_id, table } => Some((*schema_id, table)),
1657 _ => std::option::Option::None,
1658 }
1659 }
1660
1661 #[inline]
1663 pub fn as_row_view(&self) -> Option<(u64, &Arc<DataTable>, usize)> {
1664 match self.as_heap_ref()? {
1665 HeapValue::RowView {
1666 schema_id,
1667 table,
1668 row_idx,
1669 } => Some((*schema_id, table, *row_idx)),
1670 _ => std::option::Option::None,
1671 }
1672 }
1673
1674 #[inline]
1676 pub fn as_column_ref(&self) -> Option<(u64, &Arc<DataTable>, u32)> {
1677 match self.as_heap_ref()? {
1678 HeapValue::ColumnRef {
1679 schema_id,
1680 table,
1681 col_id,
1682 } => Some((*schema_id, table, *col_id)),
1683 _ => std::option::Option::None,
1684 }
1685 }
1686
1687 #[inline]
1689 pub fn as_indexed_table(&self) -> Option<(u64, &Arc<DataTable>, u32)> {
1690 match self.as_heap_ref()? {
1691 HeapValue::IndexedTable {
1692 schema_id,
1693 table,
1694 index_col,
1695 } => Some((*schema_id, table, *index_col)),
1696 _ => std::option::Option::None,
1697 }
1698 }
1699
1700 #[inline]
1702 pub fn as_typed_object(&self) -> Option<(u64, &[ValueSlot], u64)> {
1703 match self.as_heap_ref()? {
1704 HeapValue::TypedObject {
1705 schema_id,
1706 slots,
1707 heap_mask,
1708 } => Some((*schema_id, slots, *heap_mask)),
1709 _ => std::option::Option::None,
1710 }
1711 }
1712
1713 #[inline]
1715 pub fn as_closure(&self) -> Option<(u16, &[crate::value::Upvalue])> {
1716 match self.as_heap_ref()? {
1717 HeapValue::Closure {
1718 function_id,
1719 upvalues,
1720 } => Some((*function_id, upvalues)),
1721 _ => std::option::Option::None,
1722 }
1723 }
1724
1725 #[inline]
1727 pub fn as_some_inner(&self) -> Option<&ValueWord> {
1728 match self.as_heap_ref()? {
1729 HeapValue::Some(inner) => Some(inner),
1730 _ => std::option::Option::None,
1731 }
1732 }
1733
1734 #[inline]
1736 pub fn as_ok_inner(&self) -> Option<&ValueWord> {
1737 match self.as_heap_ref()? {
1738 HeapValue::Ok(inner) => Some(inner),
1739 _ => std::option::Option::None,
1740 }
1741 }
1742
1743 #[inline]
1745 pub fn as_err_inner(&self) -> Option<&ValueWord> {
1746 match self.as_heap_ref()? {
1747 HeapValue::Err(inner) => Some(inner),
1748 _ => std::option::Option::None,
1749 }
1750 }
1751
1752 pub fn as_err_payload(&self) -> Option<ValueWord> {
1760 let inner = match self.as_heap_ref()? {
1761 HeapValue::Err(inner) => inner.as_ref(),
1762 _ => return std::option::Option::None,
1763 };
1764 if let Some(HeapValue::TypedObject {
1766 slots, heap_mask, ..
1767 }) = inner.as_heap_ref()
1768 {
1769 const PAYLOAD_SLOT: usize = 1;
1770 if slots.len() >= 6 && *heap_mask & 1 != 0 {
1771 let cat = slots[0].as_heap_value();
1773 if let HeapValue::String(s) = cat {
1774 if s.as_str() == "AnyError" && PAYLOAD_SLOT < slots.len() {
1775 let is_heap = *heap_mask & (1u64 << PAYLOAD_SLOT) != 0;
1776 return Some(slots[PAYLOAD_SLOT].as_value_word(is_heap));
1777 }
1778 }
1779 }
1780 }
1781 Some(inner.clone())
1783 }
1784
1785 #[inline]
1787 pub fn as_future(&self) -> Option<u64> {
1788 match self.as_heap_ref()? {
1789 HeapValue::Future(id) => Some(*id),
1790 _ => std::option::Option::None,
1791 }
1792 }
1793
1794 #[inline]
1796 pub fn as_trait_object(&self) -> Option<(&ValueWord, &Arc<VTable>)> {
1797 match self.as_heap_ref()? {
1798 HeapValue::TraitObject { value, vtable } => Some((value, vtable)),
1799 _ => std::option::Option::None,
1800 }
1801 }
1802
1803 #[inline]
1805 pub fn as_expr_proxy(&self) -> Option<&Arc<String>> {
1806 match self.as_heap_ref()? {
1807 HeapValue::ExprProxy(name) => Some(name),
1808 _ => std::option::Option::None,
1809 }
1810 }
1811
1812 #[inline]
1814 pub fn as_filter_expr(&self) -> Option<&Arc<FilterNode>> {
1815 match self.as_heap_ref()? {
1816 HeapValue::FilterExpr(node) => Some(node),
1817 _ => std::option::Option::None,
1818 }
1819 }
1820
1821 #[inline]
1823 pub fn as_host_closure(&self) -> Option<&HostCallable> {
1824 match self.as_heap_ref()? {
1825 HeapValue::HostClosure(nc) => Some(nc),
1826 _ => std::option::Option::None,
1827 }
1828 }
1829
1830 #[inline]
1832 pub fn as_duration(&self) -> Option<&shape_ast::ast::Duration> {
1833 match self.as_heap_ref()? {
1834 HeapValue::Duration(d) => Some(d),
1835 _ => std::option::Option::None,
1836 }
1837 }
1838
1839 #[inline]
1841 pub fn as_range(&self) -> Option<(Option<&ValueWord>, Option<&ValueWord>, bool)> {
1842 match self.as_heap_ref()? {
1843 HeapValue::Range {
1844 start,
1845 end,
1846 inclusive,
1847 } => Some((
1848 start.as_ref().map(|b| b.as_ref()),
1849 end.as_ref().map(|b| b.as_ref()),
1850 *inclusive,
1851 )),
1852 _ => std::option::Option::None,
1853 }
1854 }
1855
1856 #[inline]
1858 pub fn as_timespan(&self) -> Option<chrono::Duration> {
1859 match self.as_heap_ref()? {
1860 HeapValue::TimeSpan(ts) => Some(*ts),
1861 _ => std::option::Option::None,
1862 }
1863 }
1864
1865 #[inline]
1867 pub fn as_enum(&self) -> Option<&EnumValue> {
1868 match self.as_heap_ref()? {
1869 HeapValue::Enum(e) => Some(e.as_ref()),
1870 _ => std::option::Option::None,
1871 }
1872 }
1873
1874 #[inline]
1876 pub fn as_timeframe(&self) -> Option<&Timeframe> {
1877 match self.as_heap_ref()? {
1878 HeapValue::Timeframe(tf) => Some(tf),
1879 _ => std::option::Option::None,
1880 }
1881 }
1882
1883 #[inline]
1885 pub fn as_hashmap(
1886 &self,
1887 ) -> Option<(&Vec<ValueWord>, &Vec<ValueWord>, &HashMap<u64, Vec<usize>>)> {
1888 match self.as_heap_ref()? {
1889 HeapValue::HashMap(d) => Some((&d.keys, &d.values, &d.index)),
1890 _ => std::option::Option::None,
1891 }
1892 }
1893
1894 #[inline]
1896 pub fn as_hashmap_data(&self) -> Option<&HashMapData> {
1897 match self.as_heap_ref()? {
1898 HeapValue::HashMap(d) => Some(d),
1899 _ => std::option::Option::None,
1900 }
1901 }
1902
1903 #[inline]
1906 pub fn as_hashmap_mut(&mut self) -> Option<&mut HashMapData> {
1907 match self.as_heap_mut()? {
1908 HeapValue::HashMap(d) => Some(d),
1909 _ => std::option::Option::None,
1910 }
1911 }
1912
1913 #[inline]
1915 pub fn as_set(&self) -> Option<&SetData> {
1916 match self.as_heap_ref()? {
1917 HeapValue::Set(d) => Some(d),
1918 _ => std::option::Option::None,
1919 }
1920 }
1921
1922 #[inline]
1924 pub fn as_set_mut(&mut self) -> Option<&mut SetData> {
1925 match self.as_heap_mut()? {
1926 HeapValue::Set(d) => Some(d),
1927 _ => std::option::Option::None,
1928 }
1929 }
1930
1931 #[inline]
1933 pub fn as_deque(&self) -> Option<&DequeData> {
1934 match self.as_heap_ref()? {
1935 HeapValue::Deque(d) => Some(d),
1936 _ => std::option::Option::None,
1937 }
1938 }
1939
1940 #[inline]
1942 pub fn as_deque_mut(&mut self) -> Option<&mut DequeData> {
1943 match self.as_heap_mut()? {
1944 HeapValue::Deque(d) => Some(d),
1945 _ => std::option::Option::None,
1946 }
1947 }
1948
1949 #[inline]
1951 pub fn as_priority_queue(&self) -> Option<&PriorityQueueData> {
1952 match self.as_heap_ref()? {
1953 HeapValue::PriorityQueue(d) => Some(d),
1954 _ => std::option::Option::None,
1955 }
1956 }
1957
1958 #[inline]
1960 pub fn as_priority_queue_mut(&mut self) -> Option<&mut PriorityQueueData> {
1961 match self.as_heap_mut()? {
1962 HeapValue::PriorityQueue(d) => Some(d),
1963 _ => std::option::Option::None,
1964 }
1965 }
1966
1967 #[inline]
1969 pub fn as_content(&self) -> Option<&ContentNode> {
1970 match self.as_heap_ref()? {
1971 HeapValue::Content(node) => Some(node),
1972 _ => std::option::Option::None,
1973 }
1974 }
1975
1976 #[inline]
1978 pub fn as_time(&self) -> Option<DateTime<FixedOffset>> {
1979 match self.as_heap_ref()? {
1980 HeapValue::Time(t) => Some(*t),
1981 _ => std::option::Option::None,
1982 }
1983 }
1984
1985 #[inline]
1987 pub fn as_instant(&self) -> Option<&std::time::Instant> {
1988 match self.as_heap_ref()? {
1989 HeapValue::Instant(t) => Some(t.as_ref()),
1990 _ => std::option::Option::None,
1991 }
1992 }
1993
1994 #[inline]
1996 pub fn as_io_handle(&self) -> Option<&crate::heap_value::IoHandleData> {
1997 match self.as_heap_ref()? {
1998 HeapValue::IoHandle(data) => Some(data.as_ref()),
1999 _ => std::option::Option::None,
2000 }
2001 }
2002
2003 #[inline]
2005 pub fn as_native_scalar(&self) -> Option<NativeScalar> {
2006 match self.as_heap_ref()? {
2007 HeapValue::NativeScalar(v) => Some(*v),
2008 _ => None,
2009 }
2010 }
2011
2012 #[inline]
2014 pub fn as_native_view(&self) -> Option<&NativeViewData> {
2015 match self.as_heap_ref()? {
2016 HeapValue::NativeView(view) => Some(view.as_ref()),
2017 _ => None,
2018 }
2019 }
2020
2021 #[inline]
2023 pub fn as_datetime(&self) -> Option<&DateTime<FixedOffset>> {
2024 match self.as_heap_ref()? {
2025 HeapValue::Time(t) => Some(t),
2026 _ => std::option::Option::None,
2027 }
2028 }
2029
2030 #[inline]
2032 pub fn as_arc_string(&self) -> Option<&Arc<String>> {
2033 match self.as_heap_ref()? {
2034 HeapValue::String(s) => Some(s),
2035 _ => std::option::Option::None,
2036 }
2037 }
2038
2039 #[inline]
2043 pub fn as_int_array(&self) -> Option<&Arc<crate::typed_buffer::TypedBuffer<i64>>> {
2044 match self.as_heap_ref()? {
2045 HeapValue::IntArray(a) => Some(a),
2046 _ => std::option::Option::None,
2047 }
2048 }
2049
2050 #[inline]
2052 pub fn as_float_array(&self) -> Option<&Arc<crate::typed_buffer::AlignedTypedBuffer>> {
2053 match self.as_heap_ref()? {
2054 HeapValue::FloatArray(a) => Some(a),
2055 _ => std::option::Option::None,
2056 }
2057 }
2058
2059 #[inline]
2061 pub fn as_bool_array(&self) -> Option<&Arc<crate::typed_buffer::TypedBuffer<u8>>> {
2062 match self.as_heap_ref()? {
2063 HeapValue::BoolArray(a) => Some(a),
2064 _ => std::option::Option::None,
2065 }
2066 }
2067
2068 #[inline]
2070 pub fn as_matrix(&self) -> Option<&crate::heap_value::MatrixData> {
2071 match self.as_heap_ref()? {
2072 HeapValue::Matrix(m) => Some(m.as_ref()),
2073 _ => std::option::Option::None,
2074 }
2075 }
2076
2077 #[inline]
2079 pub fn as_iterator(&self) -> Option<&crate::heap_value::IteratorState> {
2080 match self.as_heap_ref()? {
2081 HeapValue::Iterator(it) => Some(it.as_ref()),
2082 _ => std::option::Option::None,
2083 }
2084 }
2085
2086 #[inline]
2088 pub fn as_generator(&self) -> Option<&crate::heap_value::GeneratorState> {
2089 match self.as_heap_ref()? {
2090 HeapValue::Generator(g) => Some(g.as_ref()),
2091 _ => std::option::Option::None,
2092 }
2093 }
2094
2095 #[inline]
2098 pub fn typed_array_len(&self) -> Option<usize> {
2099 match self.as_heap_ref()? {
2100 HeapValue::IntArray(a) => Some(a.len()),
2101 HeapValue::FloatArray(a) => Some(a.len()),
2102 HeapValue::BoolArray(a) => Some(a.len()),
2103 HeapValue::I8Array(a) => Some(a.len()),
2104 HeapValue::I16Array(a) => Some(a.len()),
2105 HeapValue::I32Array(a) => Some(a.len()),
2106 HeapValue::U8Array(a) => Some(a.len()),
2107 HeapValue::U16Array(a) => Some(a.len()),
2108 HeapValue::U32Array(a) => Some(a.len()),
2109 HeapValue::U64Array(a) => Some(a.len()),
2110 HeapValue::F32Array(a) => Some(a.len()),
2111 _ => std::option::Option::None,
2112 }
2113 }
2114
2115 pub fn coerce_to_float_array(&self) -> Option<Arc<crate::typed_buffer::AlignedTypedBuffer>> {
2117 match self.as_heap_ref()? {
2118 HeapValue::FloatArray(a) => Some(Arc::clone(a)),
2119 HeapValue::IntArray(a) => {
2120 let mut buf = crate::typed_buffer::AlignedTypedBuffer::with_capacity(a.len());
2121 for &v in a.iter() {
2122 buf.push(v as f64);
2123 }
2124 Some(Arc::new(buf))
2125 }
2126 _ => std::option::Option::None,
2127 }
2128 }
2129
2130 pub fn to_generic_array(&self) -> Option<crate::value::VMArray> {
2132 match self.as_heap_ref()? {
2133 HeapValue::IntArray(a) => Some(Arc::new(
2134 a.iter().map(|&v| ValueWord::from_i64(v)).collect(),
2135 )),
2136 HeapValue::FloatArray(a) => Some(Arc::new(
2137 a.iter().map(|&v| ValueWord::from_f64(v)).collect(),
2138 )),
2139 HeapValue::BoolArray(a) => Some(Arc::new(
2140 a.iter().map(|&v| ValueWord::from_bool(v != 0)).collect(),
2141 )),
2142 _ => std::option::Option::None,
2143 }
2144 }
2145
2146 #[inline]
2150 pub fn vw_equals(&self, other: &ValueWord) -> bool {
2151 if self.0 == other.0 {
2153 if !is_tagged(self.0) {
2155 let f = f64::from_bits(self.0);
2156 return !f.is_nan();
2157 }
2158 return true;
2160 }
2161 if !is_tagged(self.0) || !is_tagged(other.0) {
2163 if let (Some(a), Some(b)) = (self.as_number_coerce(), other.as_number_coerce()) {
2167 return a == b;
2168 }
2169 return false;
2170 }
2171 let tag_a = get_tag(self.0);
2172 let tag_b = get_tag(other.0);
2173 if tag_a != tag_b {
2174 if (tag_a == TAG_INT || !is_tagged(self.0)) && (tag_b == TAG_INT || !is_tagged(other.0))
2176 {
2177 if let (Some(a), Some(b)) = (self.as_number_coerce(), other.as_number_coerce()) {
2178 return a == b;
2179 }
2180 }
2181 return false;
2182 }
2183 if tag_a == TAG_HEAP {
2185 let ptr_a = get_payload(self.0) as *const HeapValue;
2186 let ptr_b = get_payload(other.0) as *const HeapValue;
2187 return unsafe { (*ptr_a).equals(&*ptr_b) };
2188 }
2189 false
2191 }
2192
2193 pub fn vw_hash(&self) -> u64 {
2196 use ahash::AHasher;
2197 use std::hash::{Hash, Hasher};
2198
2199 let tag = self.tag();
2200 match tag {
2201 NanTag::F64 => {
2202 let f = unsafe { self.as_f64_unchecked() };
2203 let bits = if f == 0.0 { 0u64 } else { f.to_bits() };
2204 let mut hasher = AHasher::default();
2205 bits.hash(&mut hasher);
2206 hasher.finish()
2207 }
2208 NanTag::I48 => {
2209 let i = unsafe { self.as_i64_unchecked() };
2210 let mut hasher = AHasher::default();
2211 i.hash(&mut hasher);
2212 hasher.finish()
2213 }
2214 NanTag::Bool => {
2215 if unsafe { self.as_bool_unchecked() } {
2216 1
2217 } else {
2218 0
2219 }
2220 }
2221 NanTag::None => 0x_DEAD_0000,
2222 NanTag::Unit => 0x_DEAD_0001,
2223 NanTag::Heap => {
2224 if let Some(hv) = self.as_heap_ref() {
2225 match hv {
2226 HeapValue::String(s) => {
2227 let mut hasher = AHasher::default();
2228 s.hash(&mut hasher);
2229 hasher.finish()
2230 }
2231 HeapValue::BigInt(i) => {
2232 let mut hasher = AHasher::default();
2233 i.hash(&mut hasher);
2234 hasher.finish()
2235 }
2236 HeapValue::Decimal(d) => {
2237 let mut hasher = AHasher::default();
2238 d.mantissa().hash(&mut hasher);
2239 d.scale().hash(&mut hasher);
2240 hasher.finish()
2241 }
2242 HeapValue::NativeScalar(v) => {
2243 let mut hasher = AHasher::default();
2244 v.type_name().hash(&mut hasher);
2245 v.to_string().hash(&mut hasher);
2246 hasher.finish()
2247 }
2248 HeapValue::NativeView(v) => {
2249 let mut hasher = AHasher::default();
2250 v.ptr.hash(&mut hasher);
2251 v.layout.name.hash(&mut hasher);
2252 v.mutable.hash(&mut hasher);
2253 hasher.finish()
2254 }
2255 _ => {
2256 let mut hasher = AHasher::default();
2257 self.0.hash(&mut hasher);
2258 hasher.finish()
2259 }
2260 }
2261 } else {
2262 let mut hasher = AHasher::default();
2263 self.0.hash(&mut hasher);
2264 hasher.finish()
2265 }
2266 }
2267 _ => {
2268 let mut hasher = AHasher::default();
2269 self.0.hash(&mut hasher);
2270 hasher.finish()
2271 }
2272 }
2273 }
2274
2275 #[inline(always)]
2282 pub unsafe fn add_f64(a: &Self, b: &Self) -> Self {
2283 debug_assert!(a.is_f64() && b.is_f64());
2284 let lhs = unsafe { a.as_f64_unchecked() };
2285 let rhs = unsafe { b.as_f64_unchecked() };
2286 Self::from_f64(lhs + rhs)
2287 }
2288
2289 #[inline(always)]
2294 pub unsafe fn add_i64(a: &Self, b: &Self) -> Self {
2295 debug_assert!(a.is_i64() && b.is_i64());
2296 let lhs = unsafe { a.as_i64_unchecked() };
2297 let rhs = unsafe { b.as_i64_unchecked() };
2298 match lhs.checked_add(rhs) {
2299 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2300 _ => Self::from_f64(lhs as f64 + rhs as f64),
2301 }
2302 }
2303
2304 #[inline(always)]
2309 pub unsafe fn sub_f64(a: &Self, b: &Self) -> Self {
2310 debug_assert!(a.is_f64() && b.is_f64());
2311 let lhs = unsafe { a.as_f64_unchecked() };
2312 let rhs = unsafe { b.as_f64_unchecked() };
2313 Self::from_f64(lhs - rhs)
2314 }
2315
2316 #[inline(always)]
2321 pub unsafe fn sub_i64(a: &Self, b: &Self) -> Self {
2322 debug_assert!(a.is_i64() && b.is_i64());
2323 let lhs = unsafe { a.as_i64_unchecked() };
2324 let rhs = unsafe { b.as_i64_unchecked() };
2325 match lhs.checked_sub(rhs) {
2326 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2327 _ => Self::from_f64(lhs as f64 - rhs as f64),
2328 }
2329 }
2330
2331 #[inline(always)]
2336 pub unsafe fn mul_f64(a: &Self, b: &Self) -> Self {
2337 debug_assert!(a.is_f64() && b.is_f64());
2338 let lhs = unsafe { a.as_f64_unchecked() };
2339 let rhs = unsafe { b.as_f64_unchecked() };
2340 Self::from_f64(lhs * rhs)
2341 }
2342
2343 #[inline(always)]
2348 pub unsafe fn mul_i64(a: &Self, b: &Self) -> Self {
2349 debug_assert!(a.is_i64() && b.is_i64());
2350 let lhs = unsafe { a.as_i64_unchecked() };
2351 let rhs = unsafe { b.as_i64_unchecked() };
2352 match lhs.checked_mul(rhs) {
2353 Some(result) if result >= I48_MIN && result <= I48_MAX => Self::from_i64(result),
2354 _ => Self::from_f64(lhs as f64 * rhs as f64),
2355 }
2356 }
2357
2358 #[inline(always)]
2363 pub unsafe fn div_f64(a: &Self, b: &Self) -> Self {
2364 debug_assert!(a.is_f64() && b.is_f64());
2365 let lhs = unsafe { a.as_f64_unchecked() };
2366 let rhs = unsafe { b.as_f64_unchecked() };
2367 Self::from_f64(lhs / rhs)
2368 }
2369
2370 #[inline(always)]
2378 pub fn binary_int_preserving(
2379 a: &Self,
2380 b: &Self,
2381 a_num: f64,
2382 b_num: f64,
2383 int_op: impl FnOnce(i64, i64) -> Option<i64>,
2384 float_op: impl FnOnce(f64, f64) -> f64,
2385 ) -> Self {
2386 if matches!(a.tag(), NanTag::I48) && matches!(b.tag(), NanTag::I48) {
2387 match int_op(unsafe { a.as_i64_unchecked() }, unsafe {
2388 b.as_i64_unchecked()
2389 }) {
2390 Some(result) => Self::from_i64(result),
2391 None => Self::from_f64(float_op(a_num, b_num)),
2392 }
2393 } else {
2394 Self::from_f64(float_op(a_num, b_num))
2395 }
2396 }
2397
2398 #[inline(always)]
2403 pub unsafe fn gt_i64(a: &Self, b: &Self) -> Self {
2404 debug_assert!(a.is_i64() && b.is_i64());
2405 let lhs = unsafe { a.as_i64_unchecked() };
2406 let rhs = unsafe { b.as_i64_unchecked() };
2407 Self::from_bool(lhs > rhs)
2408 }
2409
2410 #[inline(always)]
2415 pub unsafe fn lt_i64(a: &Self, b: &Self) -> Self {
2416 debug_assert!(a.is_i64() && b.is_i64());
2417 let lhs = unsafe { a.as_i64_unchecked() };
2418 let rhs = unsafe { b.as_i64_unchecked() };
2419 Self::from_bool(lhs < rhs)
2420 }
2421
2422 #[inline(always)]
2424 pub fn raw_bits(&self) -> u64 {
2425 self.0
2426 }
2427
2428 #[inline]
2430 pub fn type_name(&self) -> &'static str {
2431 if !is_tagged(self.0) {
2432 return "number";
2433 }
2434 let tag = get_tag(self.0);
2435 if tag == TAG_HEAP {
2436 let ptr = get_payload(self.0) as *const HeapValue;
2437 return unsafe { (*ptr).type_name() };
2438 }
2439 nan_tag_type_name(tag)
2440 }
2441
2442 #[inline]
2447 pub fn to_number(&self) -> Option<f64> {
2448 self.as_number_coerce()
2449 }
2450
2451 #[inline]
2454 pub fn to_bool(&self) -> Option<bool> {
2455 self.as_bool()
2456 }
2457
2458 pub fn as_usize(&self) -> Option<usize> {
2460 if let Some(i) = self.as_i64() {
2461 if i >= 0 {
2462 return Some(i as usize);
2463 }
2464 } else if let Some(n) = self.as_f64() {
2465 if n >= 0.0 && n.is_finite() {
2466 return Some(n as usize);
2467 }
2468 } else if let Some(d) = self.as_decimal() {
2469 use rust_decimal::prelude::ToPrimitive;
2470 if let Some(n) = d.to_f64() {
2471 if n >= 0.0 {
2472 return Some(n as usize);
2473 }
2474 }
2475 } else if let Some(view) = self.as_native_view() {
2476 return Some(view.ptr);
2477 }
2478 None
2479 }
2480
2481 pub fn to_json_value(&self) -> serde_json::Value {
2483 use crate::heap_value::HeapValue;
2484 if let Some(n) = self.as_f64() {
2485 return serde_json::json!(n);
2486 }
2487 if let Some(i) = self.as_i64() {
2488 return serde_json::json!(i);
2489 }
2490 if let Some(b) = self.as_bool() {
2491 return serde_json::json!(b);
2492 }
2493 if self.is_none() || self.is_unit() {
2494 return serde_json::Value::Null;
2495 }
2496 if self.is_function() || self.is_module_function() {
2497 return serde_json::json!(format!("<{}>", self.type_name()));
2498 }
2499 match self.as_heap_ref() {
2500 Some(HeapValue::String(s)) => serde_json::json!(s.as_str()),
2501 Some(HeapValue::Decimal(d)) => {
2502 use rust_decimal::prelude::ToPrimitive;
2503 if let Some(f) = d.to_f64() {
2504 serde_json::json!(f)
2505 } else {
2506 serde_json::json!(d.to_string())
2507 }
2508 }
2509 Some(HeapValue::Array(arr)) => {
2510 let values: Vec<serde_json::Value> =
2511 arr.iter().map(|v| v.to_json_value()).collect();
2512 serde_json::json!(values)
2513 }
2514 Some(HeapValue::Some(v)) => v.to_json_value(),
2515 Some(HeapValue::Ok(v)) => serde_json::json!({
2516 "status": "ok",
2517 "value": v.to_json_value()
2518 }),
2519 Some(HeapValue::Err(v)) => serde_json::json!({
2520 "status": "error",
2521 "value": v.to_json_value()
2522 }),
2523 Some(HeapValue::DataTable(dt)) => serde_json::json!({
2524 "type": "datatable",
2525 "rows": dt.row_count(),
2526 "columns": dt.column_names(),
2527 }),
2528 Some(HeapValue::TypedTable { table, schema_id }) => serde_json::json!({
2529 "type": "typed_table",
2530 "schema_id": schema_id,
2531 "rows": table.row_count(),
2532 "columns": table.column_names(),
2533 }),
2534 Some(HeapValue::RowView {
2535 schema_id, row_idx, ..
2536 }) => serde_json::json!({
2537 "type": "row",
2538 "schema_id": schema_id,
2539 "row_idx": row_idx,
2540 }),
2541 Some(HeapValue::ColumnRef {
2542 schema_id, col_id, ..
2543 }) => serde_json::json!({
2544 "type": "column_ref",
2545 "schema_id": schema_id,
2546 "col_id": col_id,
2547 }),
2548 Some(HeapValue::IndexedTable {
2549 schema_id,
2550 table,
2551 index_col,
2552 }) => serde_json::json!({
2553 "type": "indexed_table",
2554 "schema_id": schema_id,
2555 "rows": table.row_count(),
2556 "columns": table.column_names(),
2557 "index_col": index_col,
2558 }),
2559 Some(HeapValue::HashMap(d)) => {
2560 let mut map = serde_json::Map::new();
2561 for (k, v) in d.keys.iter().zip(d.values.iter()) {
2562 map.insert(format!("{}", k), v.to_json_value());
2563 }
2564 serde_json::Value::Object(map)
2565 }
2566 Some(HeapValue::Set(d)) => {
2567 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2568 }
2569 Some(HeapValue::Deque(d)) => {
2570 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2571 }
2572 Some(HeapValue::PriorityQueue(d)) => {
2573 serde_json::Value::Array(d.items.iter().map(|v| v.to_json_value()).collect())
2574 }
2575 Some(HeapValue::NativeScalar(v)) => match v {
2576 NativeScalar::I8(n) => serde_json::json!({ "type": "i8", "value": n }),
2577 NativeScalar::U8(n) => serde_json::json!({ "type": "u8", "value": n }),
2578 NativeScalar::I16(n) => serde_json::json!({ "type": "i16", "value": n }),
2579 NativeScalar::U16(n) => serde_json::json!({ "type": "u16", "value": n }),
2580 NativeScalar::I32(n) => serde_json::json!({ "type": "i32", "value": n }),
2581 NativeScalar::U32(n) => serde_json::json!({ "type": "u32", "value": n }),
2582 NativeScalar::I64(n) => {
2583 serde_json::json!({ "type": "i64", "value": n.to_string() })
2584 }
2585 NativeScalar::U64(n) => {
2586 serde_json::json!({ "type": "u64", "value": n.to_string() })
2587 }
2588 NativeScalar::Isize(n) => {
2589 serde_json::json!({ "type": "isize", "value": n.to_string() })
2590 }
2591 NativeScalar::Usize(n) => {
2592 serde_json::json!({ "type": "usize", "value": n.to_string() })
2593 }
2594 NativeScalar::Ptr(n) => {
2595 serde_json::json!({ "type": "ptr", "value": format!("0x{n:x}") })
2596 }
2597 NativeScalar::F32(n) => serde_json::json!({ "type": "f32", "value": n }),
2598 },
2599 Some(HeapValue::NativeView(v)) => serde_json::json!({
2600 "type": if v.mutable { "cmut" } else { "cview" },
2601 "layout": v.layout.name,
2602 "ptr": v.ptr,
2603 }),
2604 Some(HeapValue::IntArray(buf)) => {
2606 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2607 }
2608 Some(HeapValue::FloatArray(buf)) => {
2609 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2610 }
2611 Some(HeapValue::BoolArray(buf)) => serde_json::Value::Array(
2612 buf.data
2613 .iter()
2614 .map(|&v| serde_json::json!(v != 0))
2615 .collect(),
2616 ),
2617 Some(HeapValue::I8Array(buf)) => {
2618 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2619 }
2620 Some(HeapValue::I16Array(buf)) => {
2621 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2622 }
2623 Some(HeapValue::I32Array(buf)) => {
2624 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2625 }
2626 Some(HeapValue::U8Array(buf)) => {
2627 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2628 }
2629 Some(HeapValue::U16Array(buf)) => {
2630 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2631 }
2632 Some(HeapValue::U32Array(buf)) => {
2633 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2634 }
2635 Some(HeapValue::U64Array(buf)) => {
2636 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2637 }
2638 Some(HeapValue::F32Array(buf)) => {
2639 serde_json::Value::Array(buf.data.iter().map(|&v| serde_json::json!(v)).collect())
2640 }
2641 _ => serde_json::json!(format!("<{}>", self.type_name())),
2642 }
2643 }
2644}
2645
2646impl PartialEq for ValueWord {
2653 fn eq(&self, other: &Self) -> bool {
2654 if self.0 == other.0 {
2656 return true;
2657 }
2658 if is_tagged(self.0)
2660 && get_tag(self.0) == TAG_HEAP
2661 && is_tagged(other.0)
2662 && get_tag(other.0) == TAG_HEAP
2663 {
2664 match (self.as_heap_ref(), other.as_heap_ref()) {
2665 (Some(a), Some(b)) => a.structural_eq(b),
2666 _ => false,
2667 }
2668 } else {
2669 false
2670 }
2671 }
2672}
2673
2674impl Eq for ValueWord {}
2675
2676#[cfg(not(feature = "gc"))]
2679impl Clone for ValueWord {
2680 #[inline]
2681 fn clone(&self) -> Self {
2682 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
2683 let ptr = get_payload(self.0) as *const HeapValue;
2685 unsafe { Arc::increment_strong_count(ptr) };
2686 Self(self.0)
2687 } else {
2688 Self(self.0)
2690 }
2691 }
2692}
2693
2694#[cfg(feature = "gc")]
2695impl Clone for ValueWord {
2696 #[inline]
2697 fn clone(&self) -> Self {
2698 Self(self.0)
2701 }
2702}
2703
2704#[cfg(not(feature = "gc"))]
2707impl Drop for ValueWord {
2708 fn drop(&mut self) {
2709 if is_tagged(self.0) && get_tag(self.0) == TAG_HEAP {
2710 let ptr = get_payload(self.0) as *const HeapValue;
2711 if !ptr.is_null() {
2712 unsafe {
2713 Arc::decrement_strong_count(ptr);
2715 }
2716 }
2717 }
2718 }
2719}
2720
2721#[cfg(feature = "gc")]
2722impl Drop for ValueWord {
2723 #[inline]
2724 fn drop(&mut self) {
2725 }
2728}
2729
2730impl std::fmt::Display for ValueWord {
2731 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2732 if self.is_f64() {
2733 let n = unsafe { self.as_f64_unchecked() };
2734 if n == n.trunc() && n.abs() < 1e15 {
2735 write!(f, "{}.0", n as i64)
2736 } else {
2737 write!(f, "{}", n)
2738 }
2739 } else if self.is_i64() {
2740 write!(f, "{}", unsafe { self.as_i64_unchecked() })
2741 } else if self.is_bool() {
2742 write!(f, "{}", unsafe { self.as_bool_unchecked() })
2743 } else if self.is_none() {
2744 write!(f, "none")
2745 } else if self.is_unit() {
2746 write!(f, "()")
2747 } else if self.is_function() {
2748 write!(f, "<function:{}>", unsafe { self.as_function_unchecked() })
2749 } else if self.is_module_function() {
2750 write!(f, "<module_function>")
2751 } else if let Some(target) = self.as_ref_target() {
2752 match target {
2753 RefTarget::Stack(slot) => write!(f, "&slot_{}", slot),
2754 RefTarget::ModuleBinding(slot) => write!(f, "&module_{}", slot),
2755 RefTarget::Projected(_) => write!(f, "&ref"),
2756 }
2757 } else if let Some(hv) = self.as_heap_ref() {
2758 match hv {
2759 HeapValue::Char(c) => write!(f, "{}", c),
2760 HeapValue::String(s) => write!(f, "{}", s),
2761 HeapValue::Array(arr) => {
2762 write!(f, "[")?;
2763 for (i, elem) in arr.iter().enumerate() {
2764 if i > 0 {
2765 write!(f, ", ")?;
2766 }
2767 write!(f, "{}", elem)?;
2768 }
2769 write!(f, "]")
2770 }
2771 HeapValue::TypedObject { .. } => write!(f, "{{...}}"),
2772 HeapValue::Closure { function_id, .. } => write!(f, "<closure:{}>", function_id),
2773 HeapValue::Decimal(d) => write!(f, "{}", d),
2774 HeapValue::BigInt(i) => write!(f, "{}", i),
2775 HeapValue::HostClosure(_) => write!(f, "<host_closure>"),
2776 HeapValue::DataTable(dt) => {
2777 write!(f, "<datatable:{}x{}>", dt.row_count(), dt.column_count())
2778 }
2779 HeapValue::TypedTable { table, .. } => write!(
2780 f,
2781 "<typed_table:{}x{}>",
2782 table.row_count(),
2783 table.column_count()
2784 ),
2785 HeapValue::RowView { row_idx, .. } => write!(f, "<row:{}>", row_idx),
2786 HeapValue::ColumnRef { col_id, .. } => write!(f, "<column:{}>", col_id),
2787 HeapValue::IndexedTable { table, .. } => write!(
2788 f,
2789 "<indexed_table:{}x{}>",
2790 table.row_count(),
2791 table.column_count()
2792 ),
2793 HeapValue::HashMap(d) => {
2794 write!(f, "HashMap{{")?;
2795 for (i, (k, v)) in d.keys.iter().zip(d.values.iter()).enumerate() {
2796 if i > 0 {
2797 write!(f, ", ")?;
2798 }
2799 write!(f, "{}: {}", k, v)?;
2800 }
2801 write!(f, "}}")
2802 }
2803 HeapValue::Set(d) => {
2804 write!(f, "Set{{")?;
2805 for (i, item) in d.items.iter().enumerate() {
2806 if i > 0 {
2807 write!(f, ", ")?;
2808 }
2809 write!(f, "{}", item)?;
2810 }
2811 write!(f, "}}")
2812 }
2813 HeapValue::Deque(d) => {
2814 write!(f, "Deque[")?;
2815 for (i, item) in d.items.iter().enumerate() {
2816 if i > 0 {
2817 write!(f, ", ")?;
2818 }
2819 write!(f, "{}", item)?;
2820 }
2821 write!(f, "]")
2822 }
2823 HeapValue::PriorityQueue(d) => {
2824 write!(f, "PriorityQueue[")?;
2825 for (i, item) in d.items.iter().enumerate() {
2826 if i > 0 {
2827 write!(f, ", ")?;
2828 }
2829 write!(f, "{}", item)?;
2830 }
2831 write!(f, "]")
2832 }
2833 HeapValue::Content(node) => write!(f, "{}", node),
2834 HeapValue::Instant(t) => write!(f, "<instant:{:?}>", t.elapsed()),
2835 HeapValue::IoHandle(data) => {
2836 let status = if data.is_open() { "open" } else { "closed" };
2837 write!(f, "<io_handle:{}:{}>", data.path, status)
2838 }
2839 HeapValue::Range {
2840 start,
2841 end,
2842 inclusive,
2843 } => {
2844 if let Some(s) = start {
2845 write!(f, "{}", s)?;
2846 }
2847 write!(f, "{}", if *inclusive { "..=" } else { ".." })?;
2848 if let Some(e) = end {
2849 write!(f, "{}", e)?;
2850 }
2851 std::fmt::Result::Ok(())
2852 }
2853 HeapValue::Enum(e) => {
2854 write!(f, "{}", e.variant)?;
2855 match &e.payload {
2856 crate::enums::EnumPayload::Unit => Ok(()),
2857 crate::enums::EnumPayload::Tuple(values) => {
2858 write!(f, "(")?;
2859 for (i, v) in values.iter().enumerate() {
2860 if i > 0 {
2861 write!(f, ", ")?;
2862 }
2863 write!(f, "{}", v)?;
2864 }
2865 write!(f, ")")
2866 }
2867 crate::enums::EnumPayload::Struct(fields) => {
2868 let mut pairs: Vec<_> = fields.iter().collect();
2869 pairs.sort_by_key(|(k, _)| (*k).clone());
2870 write!(f, " {{ ")?;
2871 for (i, (k, v)) in pairs.iter().enumerate() {
2872 if i > 0 {
2873 write!(f, ", ")?;
2874 }
2875 write!(f, "{}: {}", k, v)?;
2876 }
2877 write!(f, " }}")
2878 }
2879 }
2880 }
2881 HeapValue::Some(v) => write!(f, "some({})", v),
2882 HeapValue::Ok(v) => write!(f, "ok({})", v),
2883 HeapValue::Err(v) => write!(f, "err({})", v),
2884 HeapValue::Future(id) => write!(f, "<future:{}>", id),
2885 HeapValue::TaskGroup { task_ids, .. } => {
2886 write!(f, "<task_group:{}>", task_ids.len())
2887 }
2888 HeapValue::TraitObject { value, .. } => write!(f, "{}", value),
2889 HeapValue::ExprProxy(name) => write!(f, "<expr:{}>", name),
2890 HeapValue::FilterExpr(_) => write!(f, "<filter_expr>"),
2891 HeapValue::Time(t) => write!(f, "{}", t),
2892 HeapValue::Duration(d) => write!(f, "{:?}", d),
2893 HeapValue::TimeSpan(ts) => write!(f, "{}", ts),
2894 HeapValue::Timeframe(tf) => write!(f, "{:?}", tf),
2895 HeapValue::TimeReference(_) => write!(f, "<time_ref>"),
2896 HeapValue::DateTimeExpr(_) => write!(f, "<datetime_expr>"),
2897 HeapValue::DataDateTimeRef(_) => write!(f, "<data_datetime_ref>"),
2898 HeapValue::TypeAnnotation(_) => write!(f, "<type_annotation>"),
2899 HeapValue::TypeAnnotatedValue { type_name, value } => {
2900 write!(f, "{}({})", type_name, value)
2901 }
2902 HeapValue::PrintResult(_) => write!(f, "<print_result>"),
2903 HeapValue::SimulationCall(data) => write!(f, "<simulation:{}>", data.name),
2904 HeapValue::FunctionRef { name, .. } => write!(f, "<fn:{}>", name),
2905 HeapValue::ProjectedRef(_) => write!(f, "&ref"),
2906 HeapValue::DataReference(data) => write!(f, "<data:{}>", data.id),
2907 HeapValue::NativeScalar(v) => write!(f, "{v}"),
2908 HeapValue::NativeView(v) => write!(
2909 f,
2910 "<{}:{}@0x{:x}>",
2911 if v.mutable { "cmut" } else { "cview" },
2912 v.layout.name,
2913 v.ptr
2914 ),
2915 HeapValue::SharedCell(arc) => write!(f, "{}", arc.read().unwrap()),
2916 HeapValue::IntArray(a) => {
2917 write!(f, "Vec<int>[")?;
2918 for (i, v) in a.iter().enumerate() {
2919 if i > 0 {
2920 write!(f, ", ")?;
2921 }
2922 write!(f, "{}", v)?;
2923 }
2924 write!(f, "]")
2925 }
2926 HeapValue::FloatArray(a) => {
2927 write!(f, "Vec<number>[")?;
2928 for (i, v) in a.iter().enumerate() {
2929 if i > 0 {
2930 write!(f, ", ")?;
2931 }
2932 if *v == v.trunc() && v.abs() < 1e15 {
2933 write!(f, "{}", *v as i64)?;
2934 } else {
2935 write!(f, "{}", v)?;
2936 }
2937 }
2938 write!(f, "]")
2939 }
2940 HeapValue::BoolArray(a) => {
2941 write!(f, "Vec<bool>[")?;
2942 for (i, v) in a.iter().enumerate() {
2943 if i > 0 {
2944 write!(f, ", ")?;
2945 }
2946 write!(f, "{}", *v != 0)?;
2947 }
2948 write!(f, "]")
2949 }
2950 HeapValue::Matrix(m) => {
2951 write!(f, "<Mat<number>:{}x{}>", m.rows, m.cols)
2952 }
2953 HeapValue::Iterator(it) => {
2954 write!(
2955 f,
2956 "<iterator:pos={},transforms={}>",
2957 it.position,
2958 it.transforms.len()
2959 )
2960 }
2961 HeapValue::Generator(g) => {
2962 write!(f, "<generator:state={}>", g.state)
2963 }
2964 HeapValue::Mutex(_) => write!(f, "<mutex>"),
2965 HeapValue::Atomic(a) => {
2966 write!(
2967 f,
2968 "<atomic:{}>",
2969 a.inner.load(std::sync::atomic::Ordering::Relaxed)
2970 )
2971 }
2972 HeapValue::Channel(c) => {
2973 if c.is_sender() {
2974 write!(f, "<channel:sender>")
2975 } else {
2976 write!(f, "<channel:receiver>")
2977 }
2978 }
2979 HeapValue::Lazy(l) => {
2980 let initialized = l.value.lock().map(|g| g.is_some()).unwrap_or(false);
2981 if initialized {
2982 write!(f, "<lazy:initialized>")
2983 } else {
2984 write!(f, "<lazy:pending>")
2985 }
2986 }
2987 HeapValue::I8Array(a) => {
2988 write!(f, "Vec<i8>[")?;
2989 for (i, v) in a.iter().enumerate() {
2990 if i > 0 {
2991 write!(f, ", ")?;
2992 }
2993 write!(f, "{}", v)?;
2994 }
2995 write!(f, "]")
2996 }
2997 HeapValue::I16Array(a) => {
2998 write!(f, "Vec<i16>[")?;
2999 for (i, v) in a.iter().enumerate() {
3000 if i > 0 {
3001 write!(f, ", ")?;
3002 }
3003 write!(f, "{}", v)?;
3004 }
3005 write!(f, "]")
3006 }
3007 HeapValue::I32Array(a) => {
3008 write!(f, "Vec<i32>[")?;
3009 for (i, v) in a.iter().enumerate() {
3010 if i > 0 {
3011 write!(f, ", ")?;
3012 }
3013 write!(f, "{}", v)?;
3014 }
3015 write!(f, "]")
3016 }
3017 HeapValue::U8Array(a) => {
3018 write!(f, "Vec<u8>[")?;
3019 for (i, v) in a.iter().enumerate() {
3020 if i > 0 {
3021 write!(f, ", ")?;
3022 }
3023 write!(f, "{}", v)?;
3024 }
3025 write!(f, "]")
3026 }
3027 HeapValue::U16Array(a) => {
3028 write!(f, "Vec<u16>[")?;
3029 for (i, v) in a.iter().enumerate() {
3030 if i > 0 {
3031 write!(f, ", ")?;
3032 }
3033 write!(f, "{}", v)?;
3034 }
3035 write!(f, "]")
3036 }
3037 HeapValue::U32Array(a) => {
3038 write!(f, "Vec<u32>[")?;
3039 for (i, v) in a.iter().enumerate() {
3040 if i > 0 {
3041 write!(f, ", ")?;
3042 }
3043 write!(f, "{}", v)?;
3044 }
3045 write!(f, "]")
3046 }
3047 HeapValue::U64Array(a) => {
3048 write!(f, "Vec<u64>[")?;
3049 for (i, v) in a.iter().enumerate() {
3050 if i > 0 {
3051 write!(f, ", ")?;
3052 }
3053 write!(f, "{}", v)?;
3054 }
3055 write!(f, "]")
3056 }
3057 HeapValue::F32Array(a) => {
3058 write!(f, "Vec<f32>[")?;
3059 for (i, v) in a.iter().enumerate() {
3060 if i > 0 {
3061 write!(f, ", ")?;
3062 }
3063 write!(f, "{}", v)?;
3064 }
3065 write!(f, "]")
3066 }
3067 HeapValue::FloatArraySlice {
3068 parent,
3069 offset,
3070 len,
3071 } => {
3072 let slice =
3073 &parent.data[*offset as usize..(*offset + *len) as usize];
3074 write!(f, "Vec<number>[")?;
3075 for (i, v) in slice.iter().enumerate() {
3076 if i > 0 {
3077 write!(f, ", ")?;
3078 }
3079 if *v == v.trunc() && v.abs() < 1e15 {
3080 write!(f, "{}", *v as i64)?;
3081 } else {
3082 write!(f, "{}", v)?;
3083 }
3084 }
3085 write!(f, "]")
3086 }
3087 }
3088 } else {
3089 write!(f, "<unknown>")
3090 }
3091 }
3092}
3093
3094impl std::fmt::Debug for ValueWord {
3095 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3096 if self.is_f64() {
3097 write!(f, "ValueWord(f64: {})", unsafe { self.as_f64_unchecked() })
3098 } else if self.is_i64() {
3099 write!(f, "ValueWord(i64: {})", unsafe { self.as_i64_unchecked() })
3100 } else if self.is_bool() {
3101 write!(f, "ValueWord(bool: {})", unsafe {
3102 self.as_bool_unchecked()
3103 })
3104 } else if self.is_none() {
3105 write!(f, "ValueWord(None)")
3106 } else if self.is_unit() {
3107 write!(f, "ValueWord(Unit)")
3108 } else if self.is_function() {
3109 write!(f, "ValueWord(Function({}))", unsafe {
3110 self.as_function_unchecked()
3111 })
3112 } else if let Some(target) = self.as_ref_target() {
3113 write!(f, "ValueWord(Ref({:?}))", target)
3114 } else if self.is_heap() {
3115 let ptr = get_payload(self.0) as *const HeapValue;
3116 let hv = unsafe { &*ptr };
3117 write!(f, "ValueWord(heap: {:?})", hv)
3118 } else {
3119 write!(f, "ValueWord(0x{:016x})", self.0)
3120 }
3121 }
3122}
3123
3124#[cfg(test)]
3125mod tests {
3126 use super::*;
3127 use std::sync::Arc;
3128
3129 #[test]
3132 fn test_f64_roundtrip_positive() {
3133 let v = ValueWord::from_f64(3.14);
3134 assert!(v.is_f64());
3135 assert_eq!(v.as_f64(), Some(3.14));
3136 unsafe { assert_eq!(v.as_f64_unchecked(), 3.14) };
3137 }
3138
3139 #[test]
3140 fn test_f64_roundtrip_negative() {
3141 let v = ValueWord::from_f64(-123.456);
3142 assert!(v.is_f64());
3143 assert_eq!(v.as_f64(), Some(-123.456));
3144 }
3145
3146 #[test]
3147 fn test_f64_zero() {
3148 let v = ValueWord::from_f64(0.0);
3149 assert!(v.is_f64());
3150 assert_eq!(v.as_f64(), Some(0.0));
3151 }
3152
3153 #[test]
3154 fn test_f64_negative_zero() {
3155 let v = ValueWord::from_f64(-0.0);
3156 assert!(v.is_f64());
3157 let extracted = v.as_f64().unwrap();
3158 assert_eq!(extracted, 0.0);
3160 assert!(extracted.is_sign_negative());
3162 }
3163
3164 #[test]
3165 fn test_f64_infinity() {
3166 let pos = ValueWord::from_f64(f64::INFINITY);
3167 assert!(pos.is_f64());
3168 assert_eq!(pos.as_f64(), Some(f64::INFINITY));
3169
3170 let neg = ValueWord::from_f64(f64::NEG_INFINITY);
3171 assert!(neg.is_f64());
3172 assert_eq!(neg.as_f64(), Some(f64::NEG_INFINITY));
3173 }
3174
3175 #[test]
3176 fn test_f64_nan_canonicalized() {
3177 let v = ValueWord::from_f64(f64::NAN);
3178 assert!(v.is_f64());
3180 let extracted = v.as_f64().unwrap();
3181 assert!(extracted.is_nan());
3182 }
3183
3184 #[test]
3185 fn test_f64_subnormal() {
3186 let tiny = f64::MIN_POSITIVE / 2.0; let v = ValueWord::from_f64(tiny);
3188 assert!(v.is_f64());
3189 assert_eq!(v.as_f64(), Some(tiny));
3190 }
3191
3192 #[test]
3193 fn test_f64_max_min() {
3194 let max = ValueWord::from_f64(f64::MAX);
3195 assert!(max.is_f64());
3196 assert_eq!(max.as_f64(), Some(f64::MAX));
3197
3198 let min = ValueWord::from_f64(f64::MIN);
3199 assert!(min.is_f64());
3200 assert_eq!(min.as_f64(), Some(f64::MIN));
3201 }
3202
3203 #[test]
3206 fn test_i64_small_positive() {
3207 let v = ValueWord::from_i64(42);
3208 assert!(v.is_i64());
3209 assert_eq!(v.as_i64(), Some(42));
3210 unsafe { assert_eq!(v.as_i64_unchecked(), 42) };
3211 }
3212
3213 #[test]
3214 fn test_i64_small_negative() {
3215 let v = ValueWord::from_i64(-42);
3216 assert!(v.is_i64());
3217 assert_eq!(v.as_i64(), Some(-42));
3218 }
3219
3220 #[test]
3221 fn test_i64_zero() {
3222 let v = ValueWord::from_i64(0);
3223 assert!(v.is_i64());
3224 assert_eq!(v.as_i64(), Some(0));
3225 }
3226
3227 #[test]
3228 fn test_i64_i48_max() {
3229 let max = I48_MAX;
3230 let v = ValueWord::from_i64(max);
3231 assert!(v.is_i64());
3232 assert_eq!(v.as_i64(), Some(max));
3233 }
3234
3235 #[test]
3236 fn test_i64_i48_min() {
3237 let min = I48_MIN;
3238 let v = ValueWord::from_i64(min);
3239 assert!(v.is_i64());
3240 assert_eq!(v.as_i64(), Some(min));
3241 }
3242
3243 #[test]
3244 fn test_i64_large_needs_heap() {
3245 let v = ValueWord::from_i64(i64::MAX);
3247 assert!(v.is_heap());
3248 assert_eq!(v.as_i64(), Some(i64::MAX));
3249 }
3250
3251 #[test]
3252 fn test_i64_min_needs_heap() {
3253 let v = ValueWord::from_i64(i64::MIN);
3254 assert!(v.is_heap());
3255 assert_eq!(v.as_i64(), Some(i64::MIN));
3256 }
3257
3258 #[test]
3259 fn test_i64_just_outside_i48_positive() {
3260 let val = I48_MAX + 1;
3261 let v = ValueWord::from_i64(val);
3262 assert!(v.is_heap());
3263 assert_eq!(v.as_i64(), Some(val));
3264 }
3265
3266 #[test]
3267 fn test_i64_just_outside_i48_negative() {
3268 let val = I48_MIN - 1;
3269 let v = ValueWord::from_i64(val);
3270 assert!(v.is_heap());
3271 assert_eq!(v.as_i64(), Some(val));
3272 }
3273
3274 #[test]
3277 fn test_bool_true() {
3278 let v = ValueWord::from_bool(true);
3279 assert!(v.is_bool());
3280 assert_eq!(v.as_bool(), Some(true));
3281 unsafe { assert_eq!(v.as_bool_unchecked(), true) };
3282 }
3283
3284 #[test]
3285 fn test_bool_false() {
3286 let v = ValueWord::from_bool(false);
3287 assert!(v.is_bool());
3288 assert_eq!(v.as_bool(), Some(false));
3289 unsafe { assert_eq!(v.as_bool_unchecked(), false) };
3290 }
3291
3292 #[test]
3295 fn test_none() {
3296 let v = ValueWord::none();
3297 assert!(v.is_none());
3298 assert!(!v.is_f64());
3299 assert!(!v.is_i64());
3300 assert!(!v.is_bool());
3301 }
3302
3303 #[test]
3304 fn test_unit() {
3305 let v = ValueWord::unit();
3306 assert!(v.is_unit());
3307 }
3308
3309 #[test]
3312 fn test_function() {
3313 let v = ValueWord::from_function(42);
3314 assert!(v.is_function());
3315 assert_eq!(v.as_function(), Some(42));
3316 unsafe { assert_eq!(v.as_function_unchecked(), 42) };
3317 }
3318
3319 #[test]
3320 fn test_function_max_id() {
3321 let v = ValueWord::from_function(u16::MAX);
3322 assert!(v.is_function());
3323 assert_eq!(v.as_function(), Some(u16::MAX));
3324 }
3325
3326 #[test]
3329 fn test_module_function() {
3330 let v = ValueWord::from_module_function(99);
3331 assert!(is_tagged(v.0));
3332 assert_eq!(get_tag(v.0), TAG_MODULE_FN);
3333 assert_eq!(v.as_module_function(), Some(99));
3334 }
3335
3336 #[test]
3339 fn test_heap_string_roundtrip() {
3340 let v = ValueWord::from_string(Arc::new("hello world".to_string()));
3341 assert!(v.is_heap());
3342 assert_eq!(v.as_arc_string().map(|s| s.as_str()), Some("hello world"));
3343 }
3344
3345 #[test]
3346 fn test_heap_array_roundtrip() {
3347 let arr = Arc::new(vec![
3348 ValueWord::from_i64(1),
3349 ValueWord::from_i64(2),
3350 ValueWord::from_i64(3),
3351 ]);
3352 let v = ValueWord::from_array(arr.clone());
3353 assert!(v.is_heap());
3354 let extracted = v.as_array().expect("should be array");
3355 assert_eq!(extracted.len(), 3);
3356 }
3357
3358 #[test]
3359 fn test_heap_clone() {
3360 let v = ValueWord::from_string(Arc::new("clone me".to_string()));
3361 let cloned = v.clone();
3362
3363 assert_eq!(v.as_arc_string().map(|s| s.as_str()), Some("clone me"));
3365 assert_eq!(cloned.as_arc_string().map(|s| s.as_str()), Some("clone me"));
3366
3367 assert_eq!(
3369 get_payload(v.0),
3370 get_payload(cloned.0),
3371 "cloned heap pointers should be identical (Arc shared)"
3372 );
3373 }
3374
3375 #[test]
3378 fn test_add_f64() {
3379 let a = ValueWord::from_f64(1.5);
3380 let b = ValueWord::from_f64(2.5);
3381 let result = unsafe { ValueWord::add_f64(&a, &b) };
3382 assert_eq!(result.as_f64(), Some(4.0));
3383 }
3384
3385 #[test]
3386 fn test_add_i64() {
3387 let a = ValueWord::from_i64(100);
3388 let b = ValueWord::from_i64(200);
3389 let result = unsafe { ValueWord::add_i64(&a, &b) };
3390 assert_eq!(result.as_i64(), Some(300));
3391 }
3392
3393 #[test]
3394 fn test_add_i64_negative() {
3395 let a = ValueWord::from_i64(-50);
3396 let b = ValueWord::from_i64(30);
3397 let result = unsafe { ValueWord::add_i64(&a, &b) };
3398 assert_eq!(result.as_i64(), Some(-20));
3399 }
3400
3401 #[test]
3402 fn test_sub_f64() {
3403 let a = ValueWord::from_f64(10.0);
3404 let b = ValueWord::from_f64(3.0);
3405 let result = unsafe { ValueWord::sub_f64(&a, &b) };
3406 assert_eq!(result.as_f64(), Some(7.0));
3407 }
3408
3409 #[test]
3410 fn test_sub_i64() {
3411 let a = ValueWord::from_i64(50);
3412 let b = ValueWord::from_i64(80);
3413 let result = unsafe { ValueWord::sub_i64(&a, &b) };
3414 assert_eq!(result.as_i64(), Some(-30));
3415 }
3416
3417 #[test]
3418 fn test_mul_f64() {
3419 let a = ValueWord::from_f64(3.0);
3420 let b = ValueWord::from_f64(4.0);
3421 let result = unsafe { ValueWord::mul_f64(&a, &b) };
3422 assert_eq!(result.as_f64(), Some(12.0));
3423 }
3424
3425 #[test]
3426 fn test_mul_i64() {
3427 let a = ValueWord::from_i64(7);
3428 let b = ValueWord::from_i64(-6);
3429 let result = unsafe { ValueWord::mul_i64(&a, &b) };
3430 assert_eq!(result.as_i64(), Some(-42));
3431 }
3432
3433 #[test]
3434 fn test_div_f64() {
3435 let a = ValueWord::from_f64(10.0);
3436 let b = ValueWord::from_f64(4.0);
3437 let result = unsafe { ValueWord::div_f64(&a, &b) };
3438 assert_eq!(result.as_f64(), Some(2.5));
3439 }
3440
3441 #[test]
3442 fn test_gt_i64() {
3443 let a = ValueWord::from_i64(10);
3444 let b = ValueWord::from_i64(5);
3445 let result = unsafe { ValueWord::gt_i64(&a, &b) };
3446 assert_eq!(result.as_bool(), Some(true));
3447
3448 let result2 = unsafe { ValueWord::gt_i64(&b, &a) };
3449 assert_eq!(result2.as_bool(), Some(false));
3450 }
3451
3452 #[test]
3453 fn test_lt_i64() {
3454 let a = ValueWord::from_i64(3);
3455 let b = ValueWord::from_i64(7);
3456 let result = unsafe { ValueWord::lt_i64(&a, &b) };
3457 assert_eq!(result.as_bool(), Some(true));
3458
3459 let result2 = unsafe { ValueWord::lt_i64(&b, &a) };
3460 assert_eq!(result2.as_bool(), Some(false));
3461 }
3462
3463 #[test]
3466 fn test_add_i64_overflow_to_heap() {
3467 let a = ValueWord::from_i64(I48_MAX);
3470 let b = ValueWord::from_i64(1);
3471 let result = unsafe { ValueWord::add_i64(&a, &b) };
3472 assert!(result.is_f64());
3473 let expected = (I48_MAX + 1) as f64;
3474 assert_eq!(result.as_f64(), Some(expected));
3475 }
3476
3477 #[test]
3480 fn test_type_checks_exclusive() {
3481 let f = ValueWord::from_f64(1.0);
3482 assert!(f.is_f64());
3483 assert!(!f.is_i64());
3484 assert!(!f.is_bool());
3485 assert!(!f.is_none());
3486 assert!(!f.is_unit());
3487 assert!(!f.is_function());
3488 assert!(!f.is_heap());
3489
3490 let i = ValueWord::from_i64(1);
3491 assert!(!i.is_f64());
3492 assert!(i.is_i64());
3493 assert!(!i.is_bool());
3494 assert!(!i.is_none());
3495 assert!(!i.is_unit());
3496 assert!(!i.is_function());
3497 assert!(!i.is_heap());
3498
3499 let b = ValueWord::from_bool(true);
3500 assert!(!b.is_f64());
3501 assert!(!b.is_i64());
3502 assert!(b.is_bool());
3503 assert!(!b.is_none());
3504
3505 let n = ValueWord::none();
3506 assert!(!n.is_f64());
3507 assert!(!n.is_i64());
3508 assert!(!n.is_bool());
3509 assert!(n.is_none());
3510
3511 let u = ValueWord::unit();
3512 assert!(u.is_unit());
3513 assert!(!u.is_none());
3514
3515 let func = ValueWord::from_function(0);
3516 assert!(func.is_function());
3517 assert!(!func.is_f64());
3518 }
3519
3520 #[test]
3523 fn test_size_is_8_bytes() {
3524 assert_eq!(std::mem::size_of::<ValueWord>(), 8);
3525 }
3526
3527 #[test]
3528 fn test_heap_value_size() {
3529 use crate::heap_value::HeapValue;
3530 let hv_size = std::mem::size_of::<HeapValue>();
3531 assert!(
3534 hv_size <= 48,
3535 "HeapValue grew beyond expected 48 bytes: {} bytes",
3536 hv_size
3537 );
3538 }
3539
3540 #[test]
3543 fn test_debug_format() {
3544 let v = ValueWord::from_f64(3.14);
3545 let dbg = format!("{:?}", v);
3546 assert!(dbg.contains("f64"));
3547 assert!(dbg.contains("3.14"));
3548
3549 let v = ValueWord::from_i64(42);
3550 let dbg = format!("{:?}", v);
3551 assert!(dbg.contains("i64"));
3552 assert!(dbg.contains("42"));
3553
3554 let v = ValueWord::none();
3555 let dbg = format!("{:?}", v);
3556 assert!(dbg.contains("None"));
3557 }
3558
3559 #[test]
3562 fn test_sign_extension_negative_one() {
3563 let v = ValueWord::from_i64(-1);
3564 assert!(v.is_i64());
3565 assert_eq!(v.as_i64(), Some(-1));
3566 }
3567
3568 #[test]
3569 fn test_sign_extension_boundary() {
3570 let v = ValueWord::from_i64(-1);
3572 let payload = get_payload(v.0);
3573 assert_eq!(payload, 0x0000_FFFF_FFFF_FFFF);
3574 assert_eq!(sign_extend_i48(payload), -1);
3575
3576 let v = ValueWord::from_i64(I48_MIN);
3578 let payload = get_payload(v.0);
3579 assert_eq!(payload, 0x0000_8000_0000_0000);
3581 assert_eq!(sign_extend_i48(payload), I48_MIN);
3582 }
3583
3584 #[test]
3587 fn test_drop_non_heap_is_noop() {
3588 let _ = ValueWord::from_f64(1.0);
3590 let _ = ValueWord::from_i64(1);
3591 let _ = ValueWord::from_bool(true);
3592 let _ = ValueWord::none();
3593 let _ = ValueWord::unit();
3594 let _ = ValueWord::from_function(0);
3595 }
3596
3597 #[test]
3598 fn test_drop_heap_frees_memory() {
3599 let _v = ValueWord::from_string(Arc::new("drop test".to_string()));
3601 }
3603
3604 #[test]
3605 fn test_multiple_clones_and_drops() {
3606 let v1 = ValueWord::from_string(Arc::new("multi clone".to_string()));
3607 let v2 = v1.clone();
3608 let v3 = v2.clone();
3609
3610 assert_eq!(v1.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3611 assert_eq!(v2.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3612 assert_eq!(v3.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3613
3614 drop(v2);
3616 assert_eq!(v1.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3617 assert_eq!(v3.as_arc_string().map(|s| s.as_str()), Some("multi clone"));
3618 }
3619
3620 #[test]
3623 fn test_datetime_fixed_offset_roundtrip() {
3624 use chrono::TimeZone;
3625 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();
3627 let v = ValueWord::from_time(dt);
3628 let extracted = v.as_time().unwrap();
3629 assert_eq!(extracted, dt);
3630 assert_eq!(extracted.offset().local_minus_utc(), 5 * 3600 + 30 * 60);
3631 }
3632
3633 #[test]
3634 fn test_datetime_utc_convenience() {
3635 use chrono::TimeZone;
3636 let utc_dt = chrono::Utc.with_ymd_and_hms(2024, 1, 15, 10, 0, 0).unwrap();
3637 let v = ValueWord::from_time_utc(utc_dt);
3638 let extracted = v.as_time().unwrap();
3639 assert_eq!(extracted.offset().local_minus_utc(), 0);
3640 assert_eq!(extracted.timestamp(), utc_dt.timestamp());
3641 }
3642
3643 #[test]
3644 fn test_as_datetime_returns_ref() {
3645 use chrono::TimeZone;
3646 let offset = chrono::FixedOffset::west_opt(4 * 3600).unwrap(); let dt = offset.with_ymd_and_hms(2024, 12, 25, 8, 0, 0).unwrap();
3648 let v = ValueWord::from_time(dt);
3649 let dt_ref = v.as_datetime().unwrap();
3650 assert_eq!(*dt_ref, dt);
3651 assert_eq!(dt_ref.offset().local_minus_utc(), -4 * 3600);
3652 }
3653
3654 #[test]
3655 fn test_datetime_display() {
3656 use chrono::TimeZone;
3657 let utc_dt = chrono::Utc.with_ymd_and_hms(2024, 3, 1, 12, 0, 0).unwrap();
3658 let v = ValueWord::from_time_utc(utc_dt);
3659 let display = format!("{}", v);
3660 assert!(display.contains("2024-03-01"));
3661 }
3662
3663 #[test]
3664 fn test_as_number_coerce_rejects_native_i64_u64() {
3665 let i64_nb = ValueWord::from_native_scalar(NativeScalar::I64(42));
3666 let u64_nb = ValueWord::from_native_u64(u64::MAX);
3667 assert_eq!(i64_nb.as_number_coerce(), None);
3668 assert_eq!(u64_nb.as_number_coerce(), None);
3669 }
3670
3671 #[test]
3672 fn test_as_number_coerce_accepts_native_f32() {
3673 let v = ValueWord::from_native_f32(12.5);
3674 assert_eq!(v.as_number_coerce(), Some(12.5));
3675 }
3676
3677 #[test]
3678 fn test_exact_integer_extractors_cover_u64() {
3679 let v = ValueWord::from_native_u64(u64::MAX);
3680 assert_eq!(v.as_u64(), Some(u64::MAX));
3681 assert_eq!(v.as_i128_exact(), Some(u64::MAX as i128));
3682 }
3683
3684 #[test]
3687 fn test_int_array_construction_and_roundtrip() {
3688 let data = vec![1i64, 2, 3, -100, 0];
3689 let nb = ValueWord::from_int_array(Arc::new(data.clone().into()));
3690 assert!(nb.is_heap());
3691 let arr = nb.as_int_array().unwrap();
3692 assert_eq!(arr.as_slice(), &data);
3693 }
3694
3695 #[test]
3696 fn test_float_array_construction_and_roundtrip() {
3697 use crate::aligned_vec::AlignedVec;
3698 let mut aligned = AlignedVec::with_capacity(4);
3699 aligned.push(1.0);
3700 aligned.push(2.5);
3701 aligned.push(-3.14);
3702 aligned.push(0.0);
3703 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3704 assert!(nb.is_heap());
3705 let arr = nb.as_float_array().unwrap();
3706 assert_eq!(arr.len(), 4);
3707 assert_eq!(arr[0], 1.0);
3708 assert_eq!(arr[2], -3.14);
3709 }
3710
3711 #[test]
3712 fn test_bool_array_construction_and_roundtrip() {
3713 let data = vec![1u8, 0, 1, 1, 0];
3714 let nb = ValueWord::from_bool_array(Arc::new(data.clone().into()));
3715 assert!(nb.is_heap());
3716 let arr = nb.as_bool_array().unwrap();
3717 assert_eq!(arr.as_slice(), &data);
3718 }
3719
3720 #[test]
3721 fn test_int_array_type_name() {
3722 let nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3723 assert_eq!(nb.type_name(), "Vec<int>");
3724 }
3725
3726 #[test]
3727 fn test_float_array_type_name() {
3728 use crate::aligned_vec::AlignedVec;
3729 let mut aligned = AlignedVec::with_capacity(1);
3730 aligned.push(1.0);
3731 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3732 assert_eq!(nb.type_name(), "Vec<number>");
3733 }
3734
3735 #[test]
3736 fn test_bool_array_type_name() {
3737 let nb = ValueWord::from_bool_array(Arc::new(vec![0u8, 1].into()));
3738 assert_eq!(nb.type_name(), "Vec<bool>");
3739 }
3740
3741 #[test]
3742 fn test_int_array_is_truthy_nonempty() {
3743 let nb = ValueWord::from_int_array(Arc::new(vec![42i64].into()));
3744 assert!(nb.is_truthy());
3745 }
3746
3747 #[test]
3748 fn test_int_array_is_truthy_empty() {
3749 let nb = ValueWord::from_int_array(Arc::new(Vec::<i64>::new().into()));
3750 assert!(!nb.is_truthy());
3751 }
3752
3753 #[test]
3754 fn test_float_array_is_truthy_nonempty() {
3755 use crate::aligned_vec::AlignedVec;
3756 let mut aligned = AlignedVec::with_capacity(1);
3757 aligned.push(0.0);
3758 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3759 assert!(nb.is_truthy());
3760 }
3761
3762 #[test]
3763 fn test_float_array_is_truthy_empty() {
3764 use crate::aligned_vec::AlignedVec;
3765 let nb = ValueWord::from_float_array(Arc::new(AlignedVec::new().into()));
3766 assert!(!nb.is_truthy());
3767 }
3768
3769 #[test]
3770 fn test_bool_array_is_truthy_nonempty() {
3771 let nb = ValueWord::from_bool_array(Arc::new(vec![0u8].into()));
3772 assert!(nb.is_truthy());
3773 }
3774
3775 #[test]
3776 fn test_bool_array_is_truthy_empty() {
3777 let nb = ValueWord::from_bool_array(Arc::new(Vec::<u8>::new().into()));
3778 assert!(!nb.is_truthy());
3779 }
3780
3781 #[test]
3782 fn test_int_array_clone_arc_refcount() {
3783 let data: Arc<crate::typed_buffer::TypedBuffer<i64>> = Arc::new(vec![10i64, 20, 30].into());
3784 let nb1 = ValueWord::from_int_array(data.clone());
3785 let nb2 = nb1.clone();
3786 let arr1 = nb1.as_int_array().unwrap();
3787 let arr2 = nb2.as_int_array().unwrap();
3788 assert_eq!(arr1.as_ref(), arr2.as_ref());
3789 assert!(Arc::ptr_eq(arr1, arr2));
3790 }
3791
3792 #[test]
3793 fn test_float_array_clone_arc_refcount() {
3794 use crate::aligned_vec::AlignedVec;
3795 let mut aligned = AlignedVec::with_capacity(2);
3796 aligned.push(1.0);
3797 aligned.push(2.0);
3798 let data: Arc<crate::typed_buffer::AlignedTypedBuffer> = Arc::new(aligned.into());
3799 let nb1 = ValueWord::from_float_array(data.clone());
3800 let nb2 = nb1.clone();
3801 let arr1 = nb1.as_float_array().unwrap();
3802 let arr2 = nb2.as_float_array().unwrap();
3803 assert!(Arc::ptr_eq(arr1, arr2));
3804 }
3805
3806 #[test]
3807 fn test_typed_array_len() {
3808 let int_nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3809 assert_eq!(int_nb.typed_array_len(), Some(3));
3810
3811 use crate::aligned_vec::AlignedVec;
3812 let mut aligned = AlignedVec::with_capacity(2);
3813 aligned.push(1.0);
3814 aligned.push(2.0);
3815 let float_nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3816 assert_eq!(float_nb.typed_array_len(), Some(2));
3817
3818 let bool_nb = ValueWord::from_bool_array(Arc::new(vec![0u8, 1, 1, 0].into()));
3819 assert_eq!(bool_nb.typed_array_len(), Some(4));
3820
3821 let number_nb = ValueWord::from_f64(42.0);
3822 assert_eq!(number_nb.typed_array_len(), None);
3823 }
3824
3825 #[test]
3826 fn test_coerce_to_float_array_from_float() {
3827 use crate::aligned_vec::AlignedVec;
3828 let mut aligned = AlignedVec::with_capacity(3);
3829 aligned.push(1.0);
3830 aligned.push(2.0);
3831 aligned.push(3.0);
3832 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3833 let result = nb.coerce_to_float_array().unwrap();
3834 assert_eq!(result.len(), 3);
3835 assert_eq!(result[0], 1.0);
3836 }
3837
3838 #[test]
3839 fn test_coerce_to_float_array_from_int() {
3840 let nb = ValueWord::from_int_array(Arc::new(vec![10i64, 20, 30].into()));
3841 let result = nb.coerce_to_float_array().unwrap();
3842 assert_eq!(result.len(), 3);
3843 assert_eq!(result[0], 10.0);
3844 assert_eq!(result[1], 20.0);
3845 assert_eq!(result[2], 30.0);
3846 }
3847
3848 #[test]
3849 fn test_to_generic_array_int() {
3850 let nb = ValueWord::from_int_array(Arc::new(vec![5i64, 10].into()));
3851 let generic = nb.to_generic_array().unwrap();
3852 assert_eq!(generic.len(), 2);
3853 assert_eq!(generic[0].as_i64(), Some(5));
3854 assert_eq!(generic[1].as_i64(), Some(10));
3855 }
3856
3857 #[test]
3858 fn test_to_generic_array_float() {
3859 use crate::aligned_vec::AlignedVec;
3860 let mut aligned = AlignedVec::with_capacity(2);
3861 aligned.push(1.5);
3862 aligned.push(2.5);
3863 let nb = ValueWord::from_float_array(Arc::new(aligned.into()));
3864 let generic = nb.to_generic_array().unwrap();
3865 assert_eq!(generic.len(), 2);
3866 assert_eq!(generic[0].as_f64(), Some(1.5));
3867 assert_eq!(generic[1].as_f64(), Some(2.5));
3868 }
3869
3870 #[test]
3871 fn test_to_generic_array_bool() {
3872 let nb = ValueWord::from_bool_array(Arc::new(vec![1u8, 0, 1].into()));
3873 let generic = nb.to_generic_array().unwrap();
3874 assert_eq!(generic.len(), 3);
3875 assert_eq!(generic[0].as_bool(), Some(true));
3876 assert_eq!(generic[1].as_bool(), Some(false));
3877 assert_eq!(generic[2].as_bool(), Some(true));
3878 }
3879
3880 #[test]
3881 fn test_int_array_nb_equals() {
3882 let a = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3883 let b = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 3].into()));
3884 let c = ValueWord::from_int_array(Arc::new(vec![1i64, 2, 4].into()));
3885 assert!(a.vw_equals(&b));
3886 assert!(!a.vw_equals(&c));
3887 }
3888
3889 #[test]
3890 fn test_float_array_nb_equals() {
3891 use crate::aligned_vec::AlignedVec;
3892 let mut a_data = AlignedVec::with_capacity(2);
3893 a_data.push(1.0);
3894 a_data.push(2.0);
3895 let mut b_data = AlignedVec::with_capacity(2);
3896 b_data.push(1.0);
3897 b_data.push(2.0);
3898 let a = ValueWord::from_float_array(Arc::new(a_data.into()));
3899 let b = ValueWord::from_float_array(Arc::new(b_data.into()));
3900 assert!(a.vw_equals(&b));
3901 }
3902
3903 #[test]
3904 fn test_cross_type_accessor_returns_none() {
3905 let int_nb = ValueWord::from_int_array(Arc::new(vec![1i64, 2].into()));
3906 assert!(int_nb.as_float_array().is_none());
3907 assert!(int_nb.as_bool_array().is_none());
3908 assert!(int_nb.as_array().is_none());
3909
3910 use crate::aligned_vec::AlignedVec;
3911 let float_nb = ValueWord::from_float_array(Arc::new(AlignedVec::new().into()));
3912 assert!(float_nb.as_int_array().is_none());
3913
3914 let bool_nb = ValueWord::from_bool_array(Arc::new(Vec::<u8>::new().into()));
3915 assert!(bool_nb.as_int_array().is_none());
3916 assert!(bool_nb.as_float_array().is_none());
3917 }
3918
3919 #[test]
3922 fn test_to_json_value_int_array() {
3923 let buf = crate::typed_buffer::TypedBuffer {
3924 data: vec![1i64, 2, 3],
3925 validity: None,
3926 };
3927 let v = ValueWord::from_int_array(Arc::new(buf));
3928 let json = v.to_json_value();
3929 assert_eq!(json, serde_json::json!([1, 2, 3]));
3930 }
3931
3932 #[test]
3933 fn test_to_json_value_float_array() {
3934 use crate::aligned_vec::AlignedVec;
3935 let mut av = AlignedVec::new();
3936 av.push(1.5);
3937 av.push(2.5);
3938 let buf = crate::typed_buffer::AlignedTypedBuffer {
3939 data: av,
3940 validity: None,
3941 };
3942 let v = ValueWord::from_float_array(Arc::new(buf));
3943 let json = v.to_json_value();
3944 assert_eq!(json, serde_json::json!([1.5, 2.5]));
3945 }
3946
3947 #[test]
3948 fn test_to_json_value_bool_array() {
3949 let buf = crate::typed_buffer::TypedBuffer {
3950 data: vec![1u8, 0, 1],
3951 validity: None,
3952 };
3953 let v = ValueWord::from_bool_array(Arc::new(buf));
3954 let json = v.to_json_value();
3955 assert_eq!(json, serde_json::json!([true, false, true]));
3956 }
3957
3958 #[test]
3959 fn test_to_json_value_empty_int_array() {
3960 let buf = crate::typed_buffer::TypedBuffer::<i64> {
3961 data: vec![],
3962 validity: None,
3963 };
3964 let v = ValueWord::from_int_array(Arc::new(buf));
3965 let json = v.to_json_value();
3966 assert_eq!(json, serde_json::json!([]));
3967 }
3968
3969 #[test]
3970 fn test_to_json_value_i32_array() {
3971 let buf = crate::typed_buffer::TypedBuffer {
3972 data: vec![10i32, 20, 30],
3973 validity: None,
3974 };
3975 let v = ValueWord::heap_box(HeapValue::I32Array(Arc::new(buf)));
3976 let json = v.to_json_value();
3977 assert_eq!(json, serde_json::json!([10, 20, 30]));
3978 }
3979
3980 #[test]
3981 fn test_to_json_value_u64_array() {
3982 let buf = crate::typed_buffer::TypedBuffer {
3983 data: vec![100u64, 200],
3984 validity: None,
3985 };
3986 let v = ValueWord::heap_box(HeapValue::U64Array(Arc::new(buf)));
3987 let json = v.to_json_value();
3988 assert_eq!(json, serde_json::json!([100, 200]));
3989 }
3990
3991 #[test]
3992 fn test_to_json_value_f32_array() {
3993 let buf = crate::typed_buffer::TypedBuffer {
3994 data: vec![1.0f32, 2.0],
3995 validity: None,
3996 };
3997 let v = ValueWord::heap_box(HeapValue::F32Array(Arc::new(buf)));
3998 let json = v.to_json_value();
3999 assert_eq!(json, serde_json::json!([1.0, 2.0]));
4000 }
4001}