1pub use shape_value::tags::{
26 CANONICAL_NAN,
28 HEAP_KIND_ARRAY,
30 HEAP_KIND_BIG_INT,
31 HEAP_KIND_BOOL,
32 HEAP_KIND_CLOSURE,
33 HEAP_KIND_COLUMN_REF,
34 HEAP_KIND_DATA_DATETIME_REF,
35 HEAP_KIND_DATA_REFERENCE,
36 HEAP_KIND_DATATABLE,
37 HEAP_KIND_DATETIME_EXPR,
38 HEAP_KIND_DECIMAL,
39 HEAP_KIND_DURATION,
40 HEAP_KIND_ENUM,
41 HEAP_KIND_ERR,
42 HEAP_KIND_EXPR_PROXY,
43 HEAP_KIND_FILTER_EXPR,
44 HEAP_KIND_FUNCTION,
45 HEAP_KIND_FLOAT_ARRAY,
46 HEAP_KIND_FLOAT_ARRAY_SLICE,
47 HEAP_KIND_FUNCTION_REF,
48 HEAP_KIND_FUTURE,
49 HEAP_KIND_HASHMAP,
50 HEAP_KIND_INT_ARRAY,
51 HEAP_KIND_HOST_CLOSURE,
52 HEAP_KIND_MATRIX,
53 HEAP_KIND_BOOL_ARRAY,
54 HEAP_KIND_I8_ARRAY,
55 HEAP_KIND_I16_ARRAY,
56 HEAP_KIND_I32_ARRAY,
57 HEAP_KIND_U8_ARRAY,
58 HEAP_KIND_U16_ARRAY,
59 HEAP_KIND_U32_ARRAY,
60 HEAP_KIND_U64_ARRAY,
61 HEAP_KIND_F32_ARRAY,
62 HEAP_KIND_INDEXED_TABLE,
63 HEAP_KIND_MODULE_FUNCTION,
64 HEAP_KIND_NONE,
65 HEAP_KIND_NUMBER,
66 HEAP_KIND_OK,
67 HEAP_KIND_PRINT_RESULT,
68 HEAP_KIND_RANGE,
69 HEAP_KIND_ROW_VIEW,
70 HEAP_KIND_SIMULATION_CALL,
71 HEAP_KIND_SOME,
72 HEAP_KIND_STRING,
73 HEAP_KIND_TASK_GROUP,
74 HEAP_KIND_TIME,
75 HEAP_KIND_TIME_REFERENCE,
76 HEAP_KIND_TIMEFRAME,
77 HEAP_KIND_TIMESPAN,
78 HEAP_KIND_TRAIT_OBJECT,
79 HEAP_KIND_TYPE_ANNOTATED_VALUE,
80 HEAP_KIND_TYPE_ANNOTATION,
81 HEAP_KIND_TYPED_OBJECT,
82 HEAP_KIND_TYPED_TABLE,
83 HEAP_KIND_UNIT,
84 I48_MAX,
85 I48_MIN,
86 PAYLOAD_MASK,
87 TAG_BASE,
88 TAG_SHIFT,
89 make_tagged,
91 sign_extend_i48,
92};
93
94pub const NAN_BASE: u64 = 0x7FF0_0000_0000_0000;
100
101pub const TAG_MASK: u64 = 0xFFFF_0000_0000_0000;
103
104pub const TAG_NULL: u64 =
110 shape_value::tags::TAG_BASE | (shape_value::tags::TAG_NONE << shape_value::tags::TAG_SHIFT);
111
112pub const TAG_BOOL_FALSE: u64 =
114 shape_value::tags::TAG_BASE | (shape_value::tags::TAG_BOOL << shape_value::tags::TAG_SHIFT);
115
116pub const TAG_BOOL_TRUE: u64 =
118 shape_value::tags::TAG_BASE | (shape_value::tags::TAG_BOOL << shape_value::tags::TAG_SHIFT) | 1;
119
120pub const TAG_UNIT: u64 =
122 shape_value::tags::TAG_BASE | (shape_value::tags::TAG_UNIT << shape_value::tags::TAG_SHIFT);
123
124pub const TAG_NONE: u64 = TAG_NULL;
126
127pub const TAG_NUMBER: u64 = 0x0000_0000_0000_0000;
129
130pub const TAG_DATA_ROW: u64 = TAG_BASE | (shape_value::tags::TAG_INT << TAG_SHIFT);
138
139pub const HK_STRING: u16 = HEAP_KIND_STRING as u16;
146pub const HK_ARRAY: u16 = HEAP_KIND_ARRAY as u16;
147pub const HK_TYPED_OBJECT: u16 = HEAP_KIND_TYPED_OBJECT as u16;
148pub const HK_CLOSURE: u16 = HEAP_KIND_CLOSURE as u16;
149pub const HK_DECIMAL: u16 = HEAP_KIND_DECIMAL as u16;
150pub const HK_BIG_INT: u16 = HEAP_KIND_BIG_INT as u16;
151pub const HK_HOST_CLOSURE: u16 = HEAP_KIND_HOST_CLOSURE as u16;
152pub const HK_DATATABLE: u16 = HEAP_KIND_DATATABLE as u16;
153pub const HK_HASHMAP: u16 = HEAP_KIND_HASHMAP as u16;
154pub const HK_TYPED_TABLE: u16 = HEAP_KIND_TYPED_TABLE as u16;
155pub const HK_ROW_VIEW: u16 = HEAP_KIND_ROW_VIEW as u16;
156pub const HK_COLUMN_REF: u16 = HEAP_KIND_COLUMN_REF as u16;
157pub const HK_INDEXED_TABLE: u16 = HEAP_KIND_INDEXED_TABLE as u16;
158pub const HK_RANGE: u16 = HEAP_KIND_RANGE as u16;
159pub const HK_ENUM: u16 = HEAP_KIND_ENUM as u16;
160pub const HK_SOME: u16 = HEAP_KIND_SOME as u16;
161pub const HK_OK: u16 = HEAP_KIND_OK as u16;
162pub const HK_ERR: u16 = HEAP_KIND_ERR as u16;
163pub const HK_FUTURE: u16 = HEAP_KIND_FUTURE as u16;
164pub const HK_TASK_GROUP: u16 = HEAP_KIND_TASK_GROUP as u16;
165pub const HK_TRAIT_OBJECT: u16 = HEAP_KIND_TRAIT_OBJECT as u16;
166pub const HK_EXPR_PROXY: u16 = HEAP_KIND_EXPR_PROXY as u16;
167pub const HK_FILTER_EXPR: u16 = HEAP_KIND_FILTER_EXPR as u16;
168pub const HK_TIME: u16 = HEAP_KIND_TIME as u16;
169pub const HK_DURATION: u16 = HEAP_KIND_DURATION as u16;
170pub const HK_TIMESPAN: u16 = HEAP_KIND_TIMESPAN as u16;
171pub const HK_TIMEFRAME: u16 = HEAP_KIND_TIMEFRAME as u16;
172pub const HK_TIME_REFERENCE: u16 = HEAP_KIND_TIME_REFERENCE as u16;
173pub const HK_DATETIME_EXPR: u16 = HEAP_KIND_DATETIME_EXPR as u16;
174pub const HK_DATA_DATETIME_REF: u16 = HEAP_KIND_DATA_DATETIME_REF as u16;
175pub const HK_TYPE_ANNOTATION: u16 = HEAP_KIND_TYPE_ANNOTATION as u16;
176pub const HK_TYPE_ANNOTATED_VALUE: u16 = HEAP_KIND_TYPE_ANNOTATED_VALUE as u16;
177pub const HK_PRINT_RESULT: u16 = HEAP_KIND_PRINT_RESULT as u16;
178pub const HK_SIMULATION_CALL: u16 = HEAP_KIND_SIMULATION_CALL as u16;
179pub const HK_FUNCTION_REF: u16 = HEAP_KIND_FUNCTION_REF as u16;
180pub const HK_DATA_REFERENCE: u16 = HEAP_KIND_DATA_REFERENCE as u16;
181pub const HK_FLOAT_ARRAY: u16 = HEAP_KIND_FLOAT_ARRAY as u16;
182pub const HK_INT_ARRAY: u16 = HEAP_KIND_INT_ARRAY as u16;
183pub const HK_FLOAT_ARRAY_SLICE: u16 = HEAP_KIND_FLOAT_ARRAY_SLICE as u16;
184pub const HK_MATRIX: u16 = HEAP_KIND_MATRIX as u16;
185pub const HK_BOOL_ARRAY: u16 = HEAP_KIND_BOOL_ARRAY as u16;
186pub const HK_I8_ARRAY: u16 = HEAP_KIND_I8_ARRAY as u16;
187pub const HK_I16_ARRAY: u16 = HEAP_KIND_I16_ARRAY as u16;
188pub const HK_I32_ARRAY: u16 = HEAP_KIND_I32_ARRAY as u16;
189pub const HK_U8_ARRAY: u16 = HEAP_KIND_U8_ARRAY as u16;
190pub const HK_U16_ARRAY: u16 = HEAP_KIND_U16_ARRAY as u16;
191pub const HK_U32_ARRAY: u16 = HEAP_KIND_U32_ARRAY as u16;
192pub const HK_U64_ARRAY: u16 = HEAP_KIND_U64_ARRAY as u16;
193pub const HK_F32_ARRAY: u16 = HEAP_KIND_F32_ARRAY as u16;
194
195pub const HK_JIT_FUNCTION: u16 = 128;
197pub const HK_JIT_SIGNAL_BUILDER: u16 = 129;
198pub const HK_JIT_TABLE_REF: u16 = 130;
199pub const HK_JIT_OBJECT: u16 = 131;
201
202#[repr(C)]
211pub struct JitAlloc<T> {
212 pub kind: u16,
214 _pad: [u8; 6],
215 pub data: T,
217}
218
219pub const JIT_ALLOC_DATA_OFFSET: usize = 8;
221
222const _: () = {
224 assert!(
226 TAG_NULL & 0x8000_0000_0000_0000 != 0,
227 "TAG_NULL must be in negative NaN space"
228 );
229 assert!(
230 TAG_BOOL_FALSE & 0x8000_0000_0000_0000 != 0,
231 "TAG_BOOL must be in negative NaN space"
232 );
233 assert!(
234 TAG_UNIT & 0x8000_0000_0000_0000 != 0,
235 "TAG_UNIT must be in negative NaN space"
236 );
237 assert!(
239 TAG_DATA_ROW & 0x8000_0000_0000_0000 != 0,
240 "TAG_DATA_ROW must be in negative NaN space"
241 );
242};
243
244#[inline]
251pub fn is_number(bits: u64) -> bool {
252 !shape_value::tags::is_tagged(bits)
253}
254
255#[inline]
257pub fn unbox_number(bits: u64) -> f64 {
258 f64::from_bits(bits)
259}
260
261#[inline]
263pub const fn box_number(n: f64) -> u64 {
264 f64::to_bits(n)
265}
266
267#[inline]
269pub const fn box_bool(b: bool) -> u64 {
270 if b { TAG_BOOL_TRUE } else { TAG_BOOL_FALSE }
271}
272
273#[inline]
275pub fn box_function(fn_id: u16) -> u64 {
276 make_tagged(shape_value::tags::TAG_FUNCTION, fn_id as u64)
277}
278
279#[inline]
281pub fn is_inline_function(bits: u64) -> bool {
282 shape_value::tags::is_tagged(bits)
283 && shape_value::tags::get_tag(bits) == shape_value::tags::TAG_FUNCTION
284}
285
286#[inline]
288pub fn unbox_function_id(bits: u64) -> u16 {
289 (bits & PAYLOAD_MASK) as u16
290}
291
292#[inline]
301pub fn jit_box<T>(kind: u16, data: T) -> u64 {
302 let alloc = Box::new(JitAlloc {
303 kind,
304 _pad: [0; 6],
305 data,
306 });
307 let ptr = Box::into_raw(alloc);
308 TAG_BASE | ((ptr as u64) & PAYLOAD_MASK)
310}
311
312#[inline]
318pub unsafe fn read_heap_kind(bits: u64) -> u16 {
319 let ptr = (bits & PAYLOAD_MASK) as *const u16;
320 unsafe { *ptr }
321}
322
323#[inline]
340pub unsafe fn jit_unbox<T>(bits: u64) -> &'static T {
341 let ptr = (bits & PAYLOAD_MASK) as *const JitAlloc<T>;
342 debug_assert!(!ptr.is_null(), "jit_unbox called with null payload pointer");
343 unsafe { &(*ptr).data }
344}
345
346#[inline]
357pub unsafe fn jit_unbox_mut<T>(bits: u64) -> &'static mut T {
358 let ptr = (bits & PAYLOAD_MASK) as *mut JitAlloc<T>;
359 debug_assert!(
360 !ptr.is_null(),
361 "jit_unbox_mut called with null payload pointer"
362 );
363 unsafe { &mut (*ptr).data }
364}
365
366#[inline]
372pub unsafe fn jit_drop<T>(bits: u64) {
373 let ptr = (bits & PAYLOAD_MASK) as *mut JitAlloc<T>;
374 unsafe { drop(Box::from_raw(ptr)) };
375}
376
377#[inline]
379pub fn is_heap(bits: u64) -> bool {
380 shape_value::tags::is_tagged(bits)
381 && shape_value::tags::get_tag(bits) == shape_value::tags::TAG_HEAP
382}
383
384#[inline]
386pub fn heap_kind(bits: u64) -> Option<u16> {
387 if is_heap(bits) {
388 Some(unsafe { read_heap_kind(bits) })
389 } else {
390 None
391 }
392}
393
394#[inline]
396pub fn is_heap_kind(bits: u64, expected_kind: u16) -> bool {
397 is_heap(bits) && unsafe { read_heap_kind(bits) } == expected_kind
398}
399
400#[inline]
402pub fn unbox_heap_pointer(bits: u64) -> *const u8 {
403 (bits & PAYLOAD_MASK) as *const u8
404}
405
406#[inline]
411pub fn is_ok_tag(bits: u64) -> bool {
412 is_heap_kind(bits, HK_OK)
413}
414
415#[inline]
416pub fn is_err_tag(bits: u64) -> bool {
417 is_heap_kind(bits, HK_ERR)
418}
419
420#[inline]
421pub fn is_result_tag(bits: u64) -> bool {
422 is_ok_tag(bits) || is_err_tag(bits)
423}
424
425#[inline]
426pub fn box_ok(inner_bits: u64) -> u64 {
427 jit_box(HK_OK, inner_bits)
428}
429
430#[inline]
431pub fn box_err(inner_bits: u64) -> u64 {
432 jit_box(HK_ERR, inner_bits)
433}
434
435#[inline]
436pub unsafe fn unbox_result_inner(bits: u64) -> u64 {
437 *unsafe { jit_unbox::<u64>(bits) }
438}
439
440#[inline]
441pub fn unbox_result_pointer(bits: u64) -> *const u64 {
442 let ptr = (bits & PAYLOAD_MASK) as *const JitAlloc<u64>;
443 if ptr.is_null() {
444 std::ptr::null()
445 } else {
446 unsafe { &(*ptr).data as *const u64 }
447 }
448}
449
450#[inline]
455pub fn is_some_tag(bits: u64) -> bool {
456 is_heap_kind(bits, HK_SOME)
457}
458
459#[inline]
460pub fn is_none_tag(bits: u64) -> bool {
461 bits == TAG_NONE
462}
463
464#[inline]
465pub fn is_option_tag(bits: u64) -> bool {
466 is_some_tag(bits) || is_none_tag(bits)
467}
468
469#[inline]
470pub fn box_some(inner_bits: u64) -> u64 {
471 jit_box(HK_SOME, inner_bits)
472}
473
474#[inline]
475pub unsafe fn unbox_some_inner(bits: u64) -> u64 {
476 *unsafe { jit_unbox::<u64>(bits) }
477}
478
479#[inline]
485pub const fn box_data_row(row_index: usize) -> u64 {
486 TAG_DATA_ROW | ((row_index as u64) & PAYLOAD_MASK)
487}
488
489#[inline]
491pub const fn unbox_data_row(bits: u64) -> usize {
492 (bits & PAYLOAD_MASK) as usize
493}
494
495#[inline]
498pub fn is_data_row(bits: u64) -> bool {
499 shape_value::tags::is_tagged(bits)
500 && shape_value::tags::get_tag(bits) == shape_value::tags::TAG_INT
501}
502
503#[inline]
508pub fn box_column_ref(ptr: *const f64, len: usize) -> u64 {
509 jit_box(HK_COLUMN_REF, (ptr, len))
510}
511
512#[inline]
513pub unsafe fn unbox_column_ref(bits: u64) -> (*const f64, usize) {
514 *unsafe { jit_unbox::<(*const f64, usize)>(bits) }
515}
516
517#[inline]
518pub fn is_column_ref(bits: u64) -> bool {
519 is_heap_kind(bits, HK_COLUMN_REF)
520}
521
522#[inline]
532pub unsafe fn extract_column(bits: u64) -> Option<&'static [f64]> {
533 if !is_column_ref(bits) {
534 return None;
535 }
536 let (ptr, len) = unsafe { unbox_column_ref(bits) };
537 if ptr.is_null() || len == 0 {
538 return None;
539 }
540 Some(unsafe { std::slice::from_raw_parts(ptr, len) })
541}
542
543#[inline]
549pub fn box_column_result(data: Vec<f64>) -> u64 {
550 let len = data.len();
551 let leaked = Box::leak(data.into_boxed_slice());
552 box_column_ref(leaked.as_ptr(), len)
553}
554
555#[inline]
560pub fn box_typed_object(ptr: *const u8) -> u64 {
561 jit_box(HK_TYPED_OBJECT, ptr)
562}
563
564#[inline]
565pub fn unbox_typed_object(bits: u64) -> *const u8 {
566 *unsafe { jit_unbox::<*const u8>(bits) }
567}
568
569#[inline]
570pub fn is_typed_object(bits: u64) -> bool {
571 is_heap_kind(bits, HK_TYPED_OBJECT)
572}
573
574#[cfg(test)]
579mod tests {
580 use super::*;
581
582 #[test]
583 fn test_inline_types_in_negative_nan_space() {
584 assert!(TAG_NULL & 0x8000_0000_0000_0000 != 0);
585 assert!(TAG_BOOL_FALSE & 0x8000_0000_0000_0000 != 0);
586 assert!(TAG_BOOL_TRUE & 0x8000_0000_0000_0000 != 0);
587 assert!(TAG_UNIT & 0x8000_0000_0000_0000 != 0);
588 }
589
590 #[test]
591 fn test_data_row_in_negative_nan_space() {
592 assert!(TAG_DATA_ROW & 0x8000_0000_0000_0000 != 0);
593 assert!(!is_number(TAG_DATA_ROW));
594 }
595
596 #[test]
597 fn test_nan_base_detects_all_tags() {
598 assert!(!is_number(TAG_NULL), "TAG_NULL should not be a number");
599 assert!(
600 !is_number(TAG_DATA_ROW),
601 "TAG_DATA_ROW should not be a number"
602 );
603 assert!(
604 !is_number(TAG_BOOL_TRUE),
605 "TAG_BOOL_TRUE should not be a number"
606 );
607
608 assert!(is_number(box_number(3.14)));
610 assert!(is_number(box_number(0.0)));
611 assert!(is_number(box_number(-1.0)));
612 assert!(is_number(box_number(f64::MAX)));
613 assert!(is_number(box_number(f64::MIN)));
614 }
615
616 #[test]
617 fn test_inline_constants_match_shared_scheme() {
618 assert_eq!(TAG_NULL, make_tagged(shape_value::tags::TAG_NONE, 0));
619 assert_eq!(TAG_BOOL_FALSE, make_tagged(shape_value::tags::TAG_BOOL, 0));
620 assert_eq!(TAG_BOOL_TRUE, make_tagged(shape_value::tags::TAG_BOOL, 1));
621 assert_eq!(TAG_UNIT, make_tagged(shape_value::tags::TAG_UNIT, 0));
622 }
623
624 #[test]
625 fn test_box_unbox_number() {
626 let n = 3.14f64;
627 let boxed = box_number(n);
628 assert!(is_number(boxed));
629 assert_eq!(unbox_number(boxed), n);
630 }
631
632 #[test]
633 fn test_box_unbox_bool() {
634 assert_eq!(box_bool(true), TAG_BOOL_TRUE);
635 assert_eq!(box_bool(false), TAG_BOOL_FALSE);
636 }
637
638 #[test]
639 fn test_box_function() {
640 let bits = box_function(42);
641 assert!(is_inline_function(bits));
642 assert_eq!(unbox_function_id(bits), 42);
643 assert!(!is_number(bits));
644 assert!(!is_heap(bits));
645 }
646
647 #[test]
648 fn test_jit_alloc_string() {
649 let bits = jit_box(HK_STRING, "hello".to_string());
650 assert!(is_heap(bits));
651 assert!(is_heap_kind(bits, HK_STRING));
652 assert!(!is_number(bits));
653 assert_eq!(heap_kind(bits), Some(HK_STRING));
654 let s = unsafe { jit_unbox::<String>(bits) };
655 assert_eq!(s, "hello");
656 unsafe { jit_drop::<String>(bits) };
657 }
658
659 #[test]
660 fn test_jit_alloc_array() {
661 let bits = jit_box(HK_ARRAY, vec![1u64, 2, 3]);
662 assert!(is_heap(bits));
663 assert!(is_heap_kind(bits, HK_ARRAY));
664 assert_eq!(heap_kind(bits), Some(HK_ARRAY));
665 let arr = unsafe { jit_unbox::<Vec<u64>>(bits) };
666 assert_eq!(arr.len(), 3);
667 unsafe { jit_drop::<Vec<u64>>(bits) };
668 }
669
670 #[test]
671 fn test_heap_kind_none_for_non_heap() {
672 assert_eq!(heap_kind(TAG_NULL), None);
673 assert_eq!(heap_kind(TAG_BOOL_TRUE), None);
674 assert_eq!(heap_kind(box_number(42.0)), None);
675 assert_eq!(heap_kind(TAG_DATA_ROW | 5), None);
676 }
677
678 #[test]
679 fn test_data_row_round_trip() {
680 let bits = box_data_row(999);
681 assert!(is_data_row(bits));
682 assert_eq!(unbox_data_row(bits), 999);
683 assert!(!is_number(bits));
684 assert!(!is_heap(bits));
685 }
686
687 #[test]
688 fn test_result_tag_discrimination() {
689 assert!(!is_ok_tag(TAG_NULL));
690 assert!(!is_err_tag(TAG_NULL));
691 assert!(!is_result_tag(box_number(1.0)));
692
693 let ok_val = box_ok(box_number(1.0));
694 assert!(is_ok_tag(ok_val));
695 assert!(!is_err_tag(ok_val));
696 assert!(is_result_tag(ok_val));
697
698 let err_val = box_err(box_number(42.0));
699 assert!(is_err_tag(err_val));
700 assert!(!is_ok_tag(err_val));
701 assert!(is_result_tag(err_val));
702
703 assert!(!is_err_tag(TAG_BOOL_FALSE));
705 assert!(!is_err_tag(TAG_BOOL_TRUE));
706
707 unsafe { jit_drop::<u64>(ok_val) };
709 unsafe { jit_drop::<u64>(err_val) };
710 }
711
712 #[test]
713 fn test_result_round_trip() {
714 let inner = box_number(99.5);
715 let ok_val = box_ok(inner);
716 assert!(is_ok_tag(ok_val));
717 let recovered = unsafe { unbox_result_inner(ok_val) };
718 assert_eq!(unbox_number(recovered), 99.5);
719 unsafe { jit_drop::<u64>(ok_val) };
720 }
721
722 #[test]
723 fn test_option_tag_discrimination() {
724 assert!(is_none_tag(TAG_NONE));
725 assert!(is_option_tag(TAG_NONE));
726 assert!(!is_some_tag(TAG_NONE));
727
728 let some_val = box_some(box_number(3.14));
729 assert!(is_some_tag(some_val));
730 assert!(is_option_tag(some_val));
731 assert!(!is_none_tag(some_val));
732
733 let inner = unsafe { unbox_some_inner(some_val) };
735 assert_eq!(unbox_number(inner), 3.14);
736
737 unsafe { jit_drop::<u64>(some_val) };
739 }
740
741 #[test]
742 fn test_typed_object_encoding() {
743 let fake_ptr = 0x0000_1234_5678_0000u64 as *const u8;
744 let boxed = box_typed_object(fake_ptr);
745 assert!(is_typed_object(boxed));
746 assert!(!is_number(boxed));
747
748 let recovered = unbox_typed_object(boxed);
750 assert_eq!(recovered, fake_ptr);
751
752 assert!(!is_typed_object(TAG_NULL));
754 assert!(!is_typed_object(box_number(42.0)));
755
756 unsafe { jit_drop::<*const u8>(boxed) };
758 }
759
760 #[test]
761 fn test_column_ref_round_trip() {
762 let data = vec![1.0f64, 2.0, 3.0];
763 let bits = box_column_ref(data.as_ptr(), data.len());
764 assert!(is_column_ref(bits));
765 assert!(!is_number(bits));
766
767 let (ptr, len) = unsafe { unbox_column_ref(bits) };
768 assert_eq!(ptr, data.as_ptr());
769 assert_eq!(len, 3);
770
771 unsafe { jit_drop::<(*const f64, usize)>(bits) };
773 }
774}