1use std::collections::HashMap;
40use std::sync::Arc;
41
42use crate::seqstring::SeqString;
43use crate::value::{ChannelData, MapKey, Value, VariantData, WeaveChannelData};
44
45const NANBOX_THRESHOLD: u64 = 0xFFF8_0000_0000_0000;
61
62const NANBOX_BASE: u64 = 0xFFF8_0000_0000_0000;
64
65const TAG_MASK: u64 = 0x0007_8000_0000_0000;
67
68const TAG_SHIFT: u32 = 47;
70
71const PAYLOAD_MASK: u64 = 0x0000_7FFF_FFFF_FFFF;
75
76pub const CANONICAL_NAN: u64 = 0x7FF8_0000_0000_0000;
79
80pub const MAX_NANBOX_INT: i64 = (1i64 << 46) - 1;
82
83pub const MIN_NANBOX_INT: i64 = -(1i64 << 46);
85
86#[repr(u8)]
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum NanBoxTag {
94 Int = 0,
95 Bool = 1,
96 String = 2,
97 Symbol = 3,
98 Variant = 4,
99 Map = 5,
100 Quotation = 6,
101 Closure = 7,
102 Channel = 8,
103 WeaveCtx = 9,
104}
105
106#[repr(C)]
115#[derive(Debug, Clone)]
116pub struct QuotationData {
117 pub wrapper: usize,
119 pub impl_: usize,
121}
122
123#[repr(C)]
128#[derive(Debug, Clone)]
129pub struct ClosureData {
130 pub fn_ptr: usize,
132 pub env: Arc<[Value]>,
134}
135
136#[repr(C)]
141#[derive(Debug, Clone)]
142pub struct WeaveCtxData {
143 pub yield_chan: Arc<WeaveChannelData>,
145 pub resume_chan: Arc<WeaveChannelData>,
147}
148
149#[repr(transparent)]
158#[derive(Clone, Copy)]
159pub struct NanBoxedValue(u64);
160
161impl NanBoxedValue {
162 #[inline(always)]
168 pub fn is_float(self) -> bool {
169 self.0 < NANBOX_THRESHOLD
172 }
173
174 #[inline(always)]
176 pub fn is_boxed(self) -> bool {
177 self.0 >= NANBOX_THRESHOLD
178 }
179
180 #[inline(always)]
182 pub fn tag(self) -> u8 {
183 debug_assert!(self.is_boxed(), "tag() called on float value");
184 ((self.0 & TAG_MASK) >> TAG_SHIFT) as u8
186 }
187
188 #[inline(always)]
190 pub fn payload(self) -> u64 {
191 debug_assert!(self.is_boxed(), "payload() called on float value");
192 self.0 & PAYLOAD_MASK
193 }
194
195 #[inline(always)]
197 pub fn is_int(self) -> bool {
198 self.is_boxed() && self.tag() == NanBoxTag::Int as u8
199 }
200
201 #[inline(always)]
203 pub fn is_bool(self) -> bool {
204 self.is_boxed() && self.tag() == NanBoxTag::Bool as u8
205 }
206
207 #[inline(always)]
209 pub fn is_string(self) -> bool {
210 self.is_boxed() && self.tag() == NanBoxTag::String as u8
211 }
212
213 #[inline(always)]
215 pub fn is_symbol(self) -> bool {
216 self.is_boxed() && self.tag() == NanBoxTag::Symbol as u8
217 }
218
219 #[inline(always)]
221 pub fn is_variant(self) -> bool {
222 self.is_boxed() && self.tag() == NanBoxTag::Variant as u8
223 }
224
225 #[inline(always)]
227 pub fn is_map(self) -> bool {
228 self.is_boxed() && self.tag() == NanBoxTag::Map as u8
229 }
230
231 #[inline(always)]
233 pub fn is_quotation(self) -> bool {
234 self.is_boxed() && self.tag() == NanBoxTag::Quotation as u8
235 }
236
237 #[inline(always)]
239 pub fn is_closure(self) -> bool {
240 self.is_boxed() && self.tag() == NanBoxTag::Closure as u8
241 }
242
243 #[inline(always)]
245 pub fn is_channel(self) -> bool {
246 self.is_boxed() && self.tag() == NanBoxTag::Channel as u8
247 }
248
249 #[inline(always)]
251 pub fn is_weave_ctx(self) -> bool {
252 self.is_boxed() && self.tag() == NanBoxTag::WeaveCtx as u8
253 }
254
255 #[inline(always)]
261 fn make_boxed(tag: NanBoxTag, payload: u64) -> Self {
262 debug_assert!(
264 payload <= PAYLOAD_MASK,
265 "Payload 0x{:x} exceeds 47-bit limit",
266 payload
267 );
268 NanBoxedValue(NANBOX_BASE | ((tag as u64) << TAG_SHIFT) | payload)
269 }
270
271 #[inline(always)]
275 pub fn from_float(f: f64) -> Self {
276 let bits = f.to_bits();
277 if bits >= NANBOX_THRESHOLD {
279 NanBoxedValue(CANONICAL_NAN)
281 } else {
282 NanBoxedValue(bits)
283 }
284 }
285
286 #[inline(always)]
291 pub fn from_int(n: i64) -> Self {
292 debug_assert!(
293 (MIN_NANBOX_INT..=MAX_NANBOX_INT).contains(&n),
294 "Integer {} outside NaN-boxing range [{}, {}]",
295 n,
296 MIN_NANBOX_INT,
297 MAX_NANBOX_INT
298 );
299 let payload = (n as u64) & PAYLOAD_MASK;
301 Self::make_boxed(NanBoxTag::Int, payload)
302 }
303
304 #[inline(always)]
306 pub fn try_from_int(n: i64) -> Option<Self> {
307 if (MIN_NANBOX_INT..=MAX_NANBOX_INT).contains(&n) {
308 Some(Self::from_int(n))
309 } else {
310 None
311 }
312 }
313
314 #[inline(always)]
316 pub fn from_bool(b: bool) -> Self {
317 let payload = if b { 1 } else { 0 };
318 Self::make_boxed(NanBoxTag::Bool, payload)
319 }
320
321 #[inline(always)]
326 pub fn from_string_ptr(ptr: *const SeqString) -> Self {
327 let payload = (ptr as u64) & PAYLOAD_MASK;
328 debug_assert_eq!(
329 payload, ptr as u64,
330 "String pointer exceeds 47-bit address space"
331 );
332 Self::make_boxed(NanBoxTag::String, payload)
333 }
334
335 #[inline(always)]
340 pub fn from_symbol_ptr(ptr: *const SeqString) -> Self {
341 let payload = (ptr as u64) & PAYLOAD_MASK;
342 debug_assert_eq!(
343 payload, ptr as u64,
344 "Symbol pointer exceeds 47-bit address space"
345 );
346 Self::make_boxed(NanBoxTag::Symbol, payload)
347 }
348
349 #[inline(always)]
351 pub fn from_variant_ptr(ptr: *const Arc<VariantData>) -> Self {
352 let payload = (ptr as u64) & PAYLOAD_MASK;
353 debug_assert_eq!(
354 payload, ptr as u64,
355 "Variant pointer exceeds 47-bit address space"
356 );
357 Self::make_boxed(NanBoxTag::Variant, payload)
358 }
359
360 #[inline(always)]
362 pub fn from_map_ptr(ptr: *const Box<HashMap<MapKey, Value>>) -> Self {
363 let payload = (ptr as u64) & PAYLOAD_MASK;
364 debug_assert_eq!(
365 payload, ptr as u64,
366 "Map pointer exceeds 47-bit address space"
367 );
368 Self::make_boxed(NanBoxTag::Map, payload)
369 }
370
371 #[inline(always)]
373 pub fn from_quotation_ptr(ptr: *const QuotationData) -> Self {
374 let payload = (ptr as u64) & PAYLOAD_MASK;
375 debug_assert_eq!(
376 payload, ptr as u64,
377 "Quotation pointer exceeds 47-bit address space"
378 );
379 Self::make_boxed(NanBoxTag::Quotation, payload)
380 }
381
382 #[inline(always)]
384 pub fn from_closure_ptr(ptr: *const ClosureData) -> Self {
385 let payload = (ptr as u64) & PAYLOAD_MASK;
386 debug_assert_eq!(
387 payload, ptr as u64,
388 "Closure pointer exceeds 47-bit address space"
389 );
390 Self::make_boxed(NanBoxTag::Closure, payload)
391 }
392
393 #[inline(always)]
395 pub fn from_channel_ptr(ptr: *const Arc<ChannelData>) -> Self {
396 let payload = (ptr as u64) & PAYLOAD_MASK;
397 debug_assert_eq!(
398 payload, ptr as u64,
399 "Channel pointer exceeds 47-bit address space"
400 );
401 Self::make_boxed(NanBoxTag::Channel, payload)
402 }
403
404 #[inline(always)]
406 pub fn from_weave_ctx_ptr(ptr: *const WeaveCtxData) -> Self {
407 let payload = (ptr as u64) & PAYLOAD_MASK;
408 debug_assert_eq!(
409 payload, ptr as u64,
410 "WeaveCtx pointer exceeds 47-bit address space"
411 );
412 Self::make_boxed(NanBoxTag::WeaveCtx, payload)
413 }
414
415 #[inline(always)]
424 pub fn as_float(self) -> f64 {
425 debug_assert!(self.is_float(), "as_float() called on non-float value");
426 f64::from_bits(self.0)
427 }
428
429 #[inline(always)]
434 pub fn as_int(self) -> i64 {
435 debug_assert!(self.is_int(), "as_int() called on non-int value");
436 let payload = self.payload();
438 if payload & (1 << 46) != 0 {
440 (payload | 0xFFFF_8000_0000_0000) as i64
442 } else {
443 payload as i64
444 }
445 }
446
447 #[inline(always)]
452 pub fn as_bool(self) -> bool {
453 debug_assert!(self.is_bool(), "as_bool() called on non-bool value");
454 self.payload() != 0
455 }
456
457 #[inline(always)]
462 pub unsafe fn as_string_ptr(self) -> *const SeqString {
463 debug_assert!(
464 self.is_string(),
465 "as_string_ptr() called on non-string value"
466 );
467 self.payload() as *const SeqString
468 }
469
470 #[inline(always)]
475 pub unsafe fn as_symbol_ptr(self) -> *const SeqString {
476 debug_assert!(
477 self.is_symbol(),
478 "as_symbol_ptr() called on non-symbol value"
479 );
480 self.payload() as *const SeqString
481 }
482
483 #[inline(always)]
488 pub unsafe fn as_variant_ptr(self) -> *const Arc<VariantData> {
489 debug_assert!(
490 self.is_variant(),
491 "as_variant_ptr() called on non-variant value"
492 );
493 self.payload() as *const Arc<VariantData>
494 }
495
496 #[inline(always)]
501 pub unsafe fn as_map_ptr(self) -> *const Box<HashMap<MapKey, Value>> {
502 debug_assert!(self.is_map(), "as_map_ptr() called on non-map value");
503 self.payload() as *const Box<HashMap<MapKey, Value>>
504 }
505
506 #[inline(always)]
511 pub unsafe fn as_quotation_ptr(self) -> *const QuotationData {
512 debug_assert!(
513 self.is_quotation(),
514 "as_quotation_ptr() called on non-quotation value"
515 );
516 self.payload() as *const QuotationData
517 }
518
519 #[inline(always)]
524 pub unsafe fn as_closure_ptr(self) -> *const ClosureData {
525 debug_assert!(
526 self.is_closure(),
527 "as_closure_ptr() called on non-closure value"
528 );
529 self.payload() as *const ClosureData
530 }
531
532 #[inline(always)]
537 pub unsafe fn as_channel_ptr(self) -> *const Arc<ChannelData> {
538 debug_assert!(
539 self.is_channel(),
540 "as_channel_ptr() called on non-channel value"
541 );
542 self.payload() as *const Arc<ChannelData>
543 }
544
545 #[inline(always)]
550 pub unsafe fn as_weave_ctx_ptr(self) -> *const WeaveCtxData {
551 debug_assert!(
552 self.is_weave_ctx(),
553 "as_weave_ctx_ptr() called on non-weave_ctx value"
554 );
555 self.payload() as *const WeaveCtxData
556 }
557
558 #[inline(always)]
564 pub fn to_bits(self) -> u64 {
565 self.0
566 }
567
568 #[inline(always)]
573 pub unsafe fn from_bits(bits: u64) -> Self {
574 NanBoxedValue(bits)
575 }
576}
577
578impl std::fmt::Debug for NanBoxedValue {
579 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
580 if self.is_float() {
581 write!(f, "Float({})", self.as_float())
582 } else {
583 match self.tag() {
584 t if t == NanBoxTag::Int as u8 => write!(f, "Int({})", self.as_int()),
585 t if t == NanBoxTag::Bool as u8 => write!(f, "Bool({})", self.as_bool()),
586 t if t == NanBoxTag::String as u8 => {
587 write!(f, "String(0x{:012x})", self.payload())
588 }
589 t if t == NanBoxTag::Symbol as u8 => {
590 write!(f, "Symbol(0x{:012x})", self.payload())
591 }
592 t if t == NanBoxTag::Variant as u8 => {
593 write!(f, "Variant(0x{:012x})", self.payload())
594 }
595 t if t == NanBoxTag::Map as u8 => write!(f, "Map(0x{:012x})", self.payload()),
596 t if t == NanBoxTag::Quotation as u8 => {
597 write!(f, "Quotation(0x{:012x})", self.payload())
598 }
599 t if t == NanBoxTag::Closure as u8 => {
600 write!(f, "Closure(0x{:012x})", self.payload())
601 }
602 t if t == NanBoxTag::Channel as u8 => {
603 write!(f, "Channel(0x{:012x})", self.payload())
604 }
605 t if t == NanBoxTag::WeaveCtx as u8 => {
606 write!(f, "WeaveCtx(0x{:012x})", self.payload())
607 }
608 _ => write!(
609 f,
610 "Unknown(tag={}, payload=0x{:012x})",
611 self.tag(),
612 self.payload()
613 ),
614 }
615 }
616 }
617}
618
619impl Default for NanBoxedValue {
620 fn default() -> Self {
621 Self::from_int(0)
623 }
624}
625
626unsafe impl Send for NanBoxedValue {}
628unsafe impl Sync for NanBoxedValue {}
629
630impl NanBoxedValue {
635 pub fn from_value(value: &Value) -> Self {
644 match value {
645 Value::Int(n) => {
646 if *n < MIN_NANBOX_INT || *n > MAX_NANBOX_INT {
648 panic!(
649 "Integer {} outside NaN-boxing range [{}, {}]",
650 n, MIN_NANBOX_INT, MAX_NANBOX_INT
651 );
652 }
653 Self::from_int(*n)
654 }
655 Value::Float(f) => Self::from_float(*f),
656 Value::Bool(b) => Self::from_bool(*b),
657 Value::String(s) => {
658 let boxed = Box::new(s.clone());
660 let ptr = Box::into_raw(boxed);
661 Self::from_string_ptr(ptr)
662 }
663 Value::Symbol(s) => {
664 let boxed = Box::new(s.clone());
665 let ptr = Box::into_raw(boxed);
666 Self::from_symbol_ptr(ptr)
667 }
668 Value::Variant(arc) => {
669 let arc_clone = arc.clone();
671 let boxed = Box::new(arc_clone);
672 let ptr = Box::into_raw(boxed);
673 Self::from_variant_ptr(ptr)
674 }
675 Value::Map(map) => {
676 let map_clone = map.clone();
678 let boxed = Box::new(map_clone);
679 let ptr = Box::into_raw(boxed);
680 Self::from_map_ptr(ptr)
681 }
682 Value::Quotation { wrapper, impl_ } => {
683 let data = Box::new(QuotationData {
684 wrapper: *wrapper,
685 impl_: *impl_,
686 });
687 let ptr = Box::into_raw(data);
688 Self::from_quotation_ptr(ptr)
689 }
690 Value::Closure { fn_ptr, env } => {
691 let data = Box::new(ClosureData {
692 fn_ptr: *fn_ptr,
693 env: env.clone(),
694 });
695 let ptr = Box::into_raw(data);
696 Self::from_closure_ptr(ptr)
697 }
698 Value::Channel(arc) => {
699 let arc_clone = arc.clone();
700 let boxed = Box::new(arc_clone);
701 let ptr = Box::into_raw(boxed);
702 Self::from_channel_ptr(ptr)
703 }
704 Value::WeaveCtx {
705 yield_chan,
706 resume_chan,
707 } => {
708 let data = Box::new(WeaveCtxData {
709 yield_chan: yield_chan.clone(),
710 resume_chan: resume_chan.clone(),
711 });
712 let ptr = Box::into_raw(data);
713 Self::from_weave_ctx_ptr(ptr)
714 }
715 }
716 }
717
718 pub unsafe fn to_value(self) -> Value {
728 if self.is_float() {
729 return Value::Float(self.as_float());
730 }
731
732 match self.tag() {
733 t if t == NanBoxTag::Int as u8 => Value::Int(self.as_int()),
734 t if t == NanBoxTag::Bool as u8 => Value::Bool(self.as_bool()),
735 t if t == NanBoxTag::String as u8 => unsafe {
736 let ptr = self.as_string_ptr() as *mut SeqString;
737 let boxed = Box::from_raw(ptr);
738 Value::String(*boxed)
739 },
740 t if t == NanBoxTag::Symbol as u8 => unsafe {
741 let ptr = self.as_symbol_ptr() as *mut SeqString;
742 let boxed = Box::from_raw(ptr);
743 Value::Symbol(*boxed)
744 },
745 t if t == NanBoxTag::Variant as u8 => unsafe {
746 let ptr = self.as_variant_ptr() as *mut Arc<VariantData>;
747 let boxed = Box::from_raw(ptr);
748 Value::Variant(*boxed)
749 },
750 t if t == NanBoxTag::Map as u8 => unsafe {
751 let ptr = self.as_map_ptr() as *mut Box<HashMap<MapKey, Value>>;
752 let boxed = Box::from_raw(ptr);
753 Value::Map(*boxed)
754 },
755 t if t == NanBoxTag::Quotation as u8 => unsafe {
756 let ptr = self.as_quotation_ptr() as *mut QuotationData;
757 let data = Box::from_raw(ptr);
758 Value::Quotation {
759 wrapper: data.wrapper,
760 impl_: data.impl_,
761 }
762 },
763 t if t == NanBoxTag::Closure as u8 => unsafe {
764 let ptr = self.as_closure_ptr() as *mut ClosureData;
765 let data = Box::from_raw(ptr);
766 Value::Closure {
767 fn_ptr: data.fn_ptr,
768 env: data.env,
769 }
770 },
771 t if t == NanBoxTag::Channel as u8 => unsafe {
772 let ptr = self.as_channel_ptr() as *mut Arc<ChannelData>;
773 let boxed = Box::from_raw(ptr);
774 Value::Channel(*boxed)
775 },
776 t if t == NanBoxTag::WeaveCtx as u8 => unsafe {
777 let ptr = self.as_weave_ctx_ptr() as *mut WeaveCtxData;
778 let data = Box::from_raw(ptr);
779 Value::WeaveCtx {
780 yield_chan: data.yield_chan,
781 resume_chan: data.resume_chan,
782 }
783 },
784 _ => panic!("Unknown NanBoxedValue tag: {}", self.tag()),
785 }
786 }
787
788 pub fn clone_nanboxed(&self) -> Self {
792 if self.is_float() {
793 return *self;
794 }
795
796 match self.tag() {
797 t if t == NanBoxTag::Int as u8 => *self,
798 t if t == NanBoxTag::Bool as u8 => *self,
799 t if t == NanBoxTag::String as u8 => {
800 let ptr = unsafe { self.as_string_ptr() };
801 let s = unsafe { &*ptr };
802 let boxed = Box::new(s.clone());
803 Self::from_string_ptr(Box::into_raw(boxed))
804 }
805 t if t == NanBoxTag::Symbol as u8 => {
806 let ptr = unsafe { self.as_symbol_ptr() };
807 let s = unsafe { &*ptr };
808 let boxed = Box::new(s.clone());
809 Self::from_symbol_ptr(Box::into_raw(boxed))
810 }
811 t if t == NanBoxTag::Variant as u8 => {
812 let ptr = unsafe { self.as_variant_ptr() };
813 let arc = unsafe { &*ptr };
814 let boxed = Box::new(arc.clone());
815 Self::from_variant_ptr(Box::into_raw(boxed))
816 }
817 t if t == NanBoxTag::Map as u8 => {
818 let ptr = unsafe { self.as_map_ptr() };
819 let map = unsafe { &*ptr };
820 let boxed = Box::new(map.clone());
821 Self::from_map_ptr(Box::into_raw(boxed))
822 }
823 t if t == NanBoxTag::Quotation as u8 => {
824 let ptr = unsafe { self.as_quotation_ptr() };
825 let data = unsafe { &*ptr };
826 let boxed = Box::new(data.clone());
827 Self::from_quotation_ptr(Box::into_raw(boxed))
828 }
829 t if t == NanBoxTag::Closure as u8 => {
830 let ptr = unsafe { self.as_closure_ptr() };
831 let data = unsafe { &*ptr };
832 let boxed = Box::new(data.clone());
833 Self::from_closure_ptr(Box::into_raw(boxed))
834 }
835 t if t == NanBoxTag::Channel as u8 => {
836 let ptr = unsafe { self.as_channel_ptr() };
837 let arc = unsafe { &*ptr };
838 let boxed = Box::new(arc.clone());
839 Self::from_channel_ptr(Box::into_raw(boxed))
840 }
841 t if t == NanBoxTag::WeaveCtx as u8 => {
842 let ptr = unsafe { self.as_weave_ctx_ptr() };
843 let data = unsafe { &*ptr };
844 let boxed = Box::new(data.clone());
845 Self::from_weave_ctx_ptr(Box::into_raw(boxed))
846 }
847 _ => *self, }
849 }
850
851 pub unsafe fn drop_nanboxed(self) {
860 if self.is_float() {
861 return;
862 }
863
864 match self.tag() {
865 t if t == NanBoxTag::Int as u8 => {}
866 t if t == NanBoxTag::Bool as u8 => {}
867 t if t == NanBoxTag::String as u8 => unsafe {
868 let ptr = self.as_string_ptr() as *mut SeqString;
869 drop(Box::from_raw(ptr));
870 },
871 t if t == NanBoxTag::Symbol as u8 => unsafe {
872 let ptr = self.as_symbol_ptr() as *mut SeqString;
873 drop(Box::from_raw(ptr));
874 },
875 t if t == NanBoxTag::Variant as u8 => unsafe {
876 let ptr = self.as_variant_ptr() as *mut Arc<VariantData>;
877 drop(Box::from_raw(ptr));
878 },
879 t if t == NanBoxTag::Map as u8 => unsafe {
880 let ptr = self.as_map_ptr() as *mut Box<HashMap<MapKey, Value>>;
881 drop(Box::from_raw(ptr));
882 },
883 t if t == NanBoxTag::Quotation as u8 => unsafe {
884 let ptr = self.as_quotation_ptr() as *mut QuotationData;
885 drop(Box::from_raw(ptr));
886 },
887 t if t == NanBoxTag::Closure as u8 => unsafe {
888 let ptr = self.as_closure_ptr() as *mut ClosureData;
889 drop(Box::from_raw(ptr));
890 },
891 t if t == NanBoxTag::Channel as u8 => unsafe {
892 let ptr = self.as_channel_ptr() as *mut Arc<ChannelData>;
893 drop(Box::from_raw(ptr));
894 },
895 t if t == NanBoxTag::WeaveCtx as u8 => unsafe {
896 let ptr = self.as_weave_ctx_ptr() as *mut WeaveCtxData;
897 drop(Box::from_raw(ptr));
898 },
899 _ => {} }
901 }
902}
903
904#[cfg(test)]
909mod tests {
910 use super::*;
911
912 #[test]
913 fn test_nanboxed_value_size() {
914 assert_eq!(std::mem::size_of::<NanBoxedValue>(), 8);
915 assert_eq!(std::mem::align_of::<NanBoxedValue>(), 8);
916 }
917
918 #[test]
919 fn test_float_encoding() {
920 let v = NanBoxedValue::from_float(2.5);
922 assert!(v.is_float());
923 assert!(!v.is_boxed());
924 assert_eq!(v.as_float(), 2.5);
925
926 let v = NanBoxedValue::from_float(0.0);
928 assert!(v.is_float());
929 assert_eq!(v.as_float(), 0.0);
930
931 let v = NanBoxedValue::from_float(-123.456);
933 assert!(v.is_float());
934 assert_eq!(v.as_float(), -123.456);
935
936 let v = NanBoxedValue::from_float(f64::INFINITY);
938 assert!(v.is_float());
939 assert!(v.as_float().is_infinite());
940
941 let v = NanBoxedValue::from_float(f64::NEG_INFINITY);
943 assert!(v.is_float());
944 assert!(v.as_float().is_infinite());
945 }
946
947 #[test]
948 fn test_nan_canonicalization() {
949 let v = NanBoxedValue::from_float(f64::NAN);
951 assert!(v.is_float());
952 assert!(v.as_float().is_nan());
953 }
954
955 #[test]
956 fn test_int_encoding() {
957 let v = NanBoxedValue::from_int(0);
959 assert!(v.is_int());
960 assert_eq!(v.as_int(), 0);
961
962 let v = NanBoxedValue::from_int(42);
964 assert!(v.is_int());
965 assert_eq!(v.as_int(), 42);
966
967 let v = NanBoxedValue::from_int(-42);
969 assert!(v.is_int());
970 assert_eq!(v.as_int(), -42);
971
972 let v = NanBoxedValue::from_int(MAX_NANBOX_INT);
974 assert!(v.is_int());
975 assert_eq!(v.as_int(), MAX_NANBOX_INT);
976
977 let v = NanBoxedValue::from_int(MIN_NANBOX_INT);
979 assert!(v.is_int());
980 assert_eq!(v.as_int(), MIN_NANBOX_INT);
981
982 let v = NanBoxedValue::from_int(1000000);
984 assert_eq!(v.as_int(), 1000000);
985
986 let v = NanBoxedValue::from_int(-1);
987 assert_eq!(v.as_int(), -1);
988 }
989
990 #[test]
991 fn test_try_from_int() {
992 assert!(NanBoxedValue::try_from_int(0).is_some());
994 assert!(NanBoxedValue::try_from_int(MAX_NANBOX_INT).is_some());
995 assert!(NanBoxedValue::try_from_int(MIN_NANBOX_INT).is_some());
996
997 assert!(NanBoxedValue::try_from_int(MAX_NANBOX_INT + 1).is_none());
999 assert!(NanBoxedValue::try_from_int(MIN_NANBOX_INT - 1).is_none());
1000 assert!(NanBoxedValue::try_from_int(i64::MAX).is_none());
1001 assert!(NanBoxedValue::try_from_int(i64::MIN).is_none());
1002 }
1003
1004 #[test]
1005 fn test_bool_encoding() {
1006 let v_true = NanBoxedValue::from_bool(true);
1007 assert!(v_true.is_bool());
1008 assert!(v_true.as_bool());
1009
1010 let v_false = NanBoxedValue::from_bool(false);
1011 assert!(v_false.is_bool());
1012 assert!(!v_false.as_bool());
1013 }
1014
1015 #[test]
1016 fn test_type_discrimination() {
1017 let float = NanBoxedValue::from_float(1.0);
1018 let int = NanBoxedValue::from_int(1);
1019 let bool_val = NanBoxedValue::from_bool(true);
1020
1021 assert!(float.is_float());
1023 assert!(!float.is_int());
1024 assert!(!float.is_bool());
1025
1026 assert!(!int.is_float());
1028 assert!(int.is_int());
1029 assert!(!int.is_bool());
1030
1031 assert!(!bool_val.is_float());
1033 assert!(!bool_val.is_int());
1034 assert!(bool_val.is_bool());
1035 }
1036
1037 #[test]
1038 fn test_int_range_boundaries() {
1039 let near_max = MAX_NANBOX_INT - 1;
1041 let near_min = MIN_NANBOX_INT + 1;
1042
1043 let v = NanBoxedValue::from_int(near_max);
1044 assert_eq!(v.as_int(), near_max);
1045
1046 let v = NanBoxedValue::from_int(near_min);
1047 assert_eq!(v.as_int(), near_min);
1048 }
1049
1050 #[test]
1051 fn test_pointer_encoding() {
1052 let boxed: Box<u64> = Box::new(42);
1054 let ptr = Box::into_raw(boxed);
1055
1056 let ptr_val = ptr as u64;
1058 assert!(
1059 ptr_val <= PAYLOAD_MASK,
1060 "Pointer 0x{:x} exceeds 47-bit range",
1061 ptr_val
1062 );
1063
1064 unsafe {
1066 drop(Box::from_raw(ptr));
1067 }
1068 }
1069
1070 #[test]
1071 fn test_quotation_data_size() {
1072 assert_eq!(std::mem::size_of::<QuotationData>(), 16);
1074 }
1075
1076 #[test]
1077 fn test_debug_format() {
1078 let float = NanBoxedValue::from_float(2.5);
1079 let int = NanBoxedValue::from_int(42);
1080 let bool_val = NanBoxedValue::from_bool(true);
1081
1082 assert!(format!("{:?}", float).contains("Float"));
1083 assert!(format!("{:?}", int).contains("Int(42)"));
1084 assert!(format!("{:?}", bool_val).contains("Bool(true)"));
1085 }
1086
1087 #[test]
1088 fn test_default() {
1089 let v = NanBoxedValue::default();
1090 assert!(v.is_int());
1091 assert_eq!(v.as_int(), 0);
1092 }
1093
1094 #[test]
1095 fn test_raw_bits_roundtrip() {
1096 let original = NanBoxedValue::from_int(12345);
1097 let bits = original.to_bits();
1098 let restored = unsafe { NanBoxedValue::from_bits(bits) };
1099 assert_eq!(restored.as_int(), 12345);
1100 }
1101
1102 #[test]
1107 fn test_negative_zero() {
1108 let v = NanBoxedValue::from_float(-0.0);
1109 assert!(v.is_float());
1110 assert_eq!(v.as_float(), 0.0);
1112 assert_eq!(v.to_bits(), (-0.0_f64).to_bits());
1114 }
1115
1116 #[test]
1117 fn test_subnormal_floats() {
1118 let smallest = f64::from_bits(1);
1120 let v = NanBoxedValue::from_float(smallest);
1121 assert!(v.is_float());
1122 assert_eq!(v.as_float().to_bits(), 1);
1123
1124 let largest_subnormal = f64::from_bits(0x000F_FFFF_FFFF_FFFF);
1126 let v = NanBoxedValue::from_float(largest_subnormal);
1127 assert!(v.is_float());
1128 assert_eq!(v.as_float().to_bits(), 0x000F_FFFF_FFFF_FFFF);
1129 }
1130
1131 #[test]
1132 fn test_special_float_values() {
1133 let v = NanBoxedValue::from_float(f64::MIN);
1135 assert!(v.is_float());
1136 assert_eq!(v.as_float(), f64::MIN);
1137
1138 let v = NanBoxedValue::from_float(f64::MAX);
1140 assert!(v.is_float());
1141 assert_eq!(v.as_float(), f64::MAX);
1142
1143 let v = NanBoxedValue::from_float(f64::MIN_POSITIVE);
1145 assert!(v.is_float());
1146 assert_eq!(v.as_float(), f64::MIN_POSITIVE);
1147
1148 let v = NanBoxedValue::from_float(f64::EPSILON);
1150 assert!(v.is_float());
1151 assert_eq!(v.as_float(), f64::EPSILON);
1152 }
1153
1154 #[test]
1155 fn test_negative_infinity() {
1156 let v = NanBoxedValue::from_float(f64::NEG_INFINITY);
1157 assert!(v.is_float());
1158 assert!(!v.is_boxed());
1159 assert!(v.as_float().is_infinite());
1160 assert!(v.as_float().is_sign_negative());
1161 }
1162
1163 #[test]
1164 fn test_large_negative_floats_not_boxed() {
1165 let values = [-1.0e308, -1.0e100, -1.0e50, -1.0, -0.5, -f64::MIN_POSITIVE];
1168
1169 for &f in &values {
1170 let v = NanBoxedValue::from_float(f);
1171 assert!(
1172 v.is_float(),
1173 "Float {} should be recognized as float, not boxed (bits: 0x{:016x})",
1174 f,
1175 f.to_bits()
1176 );
1177 assert_eq!(v.as_float(), f);
1178 }
1179 }
1180
1181 #[test]
1182 fn test_no_float_boxed_collision() {
1183 assert!(f64::NEG_INFINITY.to_bits() < NANBOX_THRESHOLD);
1189
1190 assert!(f64::MIN.to_bits() < NANBOX_THRESHOLD);
1192
1193 assert!((-1.0_f64).to_bits() < NANBOX_THRESHOLD);
1195
1196 let neg_qnan = f64::from_bits(0xFFF8_0000_0000_0000);
1199 assert!(neg_qnan.to_bits() >= NANBOX_THRESHOLD);
1200
1201 let boxed = NanBoxedValue::from_float(neg_qnan);
1203 assert!(boxed.is_float());
1204 assert_eq!(boxed.to_bits(), CANONICAL_NAN);
1205 }
1206
1207 #[test]
1208 fn test_all_tags_discriminate() {
1209 let int = NanBoxedValue::from_int(0);
1211 let bool_v = NanBoxedValue::from_bool(false);
1212
1213 assert_eq!(int.tag(), NanBoxTag::Int as u8);
1215 assert_eq!(bool_v.tag(), NanBoxTag::Bool as u8);
1216
1217 assert!(int.is_int());
1219 assert!(!int.is_bool());
1220 assert!(!int.is_string());
1221
1222 assert!(bool_v.is_bool());
1223 assert!(!bool_v.is_int());
1224 assert!(!bool_v.is_string());
1225 }
1226
1227 #[test]
1228 fn test_encoding_bit_patterns() {
1229 let int_zero = NanBoxedValue::from_int(0);
1234 let bits = int_zero.to_bits();
1235 assert_eq!(
1236 bits >> 51,
1237 0x1FFF,
1238 "All boxed values have 0x1FFF in high 13 bits (negative quiet NaN)"
1239 );
1240 assert_eq!(int_zero.tag(), 0, "Int should have tag 0");
1241 assert_eq!(bits & PAYLOAD_MASK, 0, "Int(0) should have payload 0");
1242
1243 let bool_true = NanBoxedValue::from_bool(true);
1245 let bits = bool_true.to_bits();
1246 assert_eq!(
1247 bits >> 51,
1248 0x1FFF,
1249 "All boxed values have 0x1FFF in high 13 bits (negative quiet NaN)"
1250 );
1251 assert_eq!(bool_true.tag(), 1, "Bool should have tag 1");
1252 assert_eq!(bits & PAYLOAD_MASK, 1, "Bool(true) should have payload 1");
1253
1254 let int_42 = NanBoxedValue::from_int(42);
1256 let bits = int_42.to_bits();
1257 assert_eq!(bits >> 51, 0x1FFF);
1258 assert_eq!(int_42.tag(), 0);
1259 assert_eq!(bits & PAYLOAD_MASK, 42);
1260
1261 let expected_bool_bits = 0xFFF8_0000_0000_0000_u64 | (1_u64 << 47) | 1;
1264 assert_eq!(
1265 bool_true.to_bits(),
1266 expected_bool_bits,
1267 "Bool(true) bit pattern should be 0xFFF8_8000_0000_0001"
1268 );
1269 }
1270
1271 #[test]
1272 fn test_negative_int_sign_extension() {
1273 let v = NanBoxedValue::from_int(-1);
1276 assert_eq!(v.as_int(), -1);
1277
1278 let v = NanBoxedValue::from_int(-100);
1279 assert_eq!(v.as_int(), -100);
1280
1281 let v = NanBoxedValue::from_int(-1000000);
1282 assert_eq!(v.as_int(), -1000000);
1283
1284 let v = NanBoxedValue::from_int(MIN_NANBOX_INT);
1286 assert_eq!(v.as_int(), MIN_NANBOX_INT);
1287 assert!(v.as_int() < 0);
1288 }
1289
1290 #[test]
1291 fn test_closure_and_weave_data_sizes() {
1292 assert_eq!(std::mem::size_of::<QuotationData>(), 16); assert!(std::mem::size_of::<ClosureData>() >= 24);
1296 assert!(std::mem::size_of::<WeaveCtxData>() >= 16);
1298 }
1299
1300 #[test]
1305 fn test_value_int_roundtrip() {
1306 let original = Value::Int(42);
1307 let nb = NanBoxedValue::from_value(&original);
1308 let restored = unsafe { nb.to_value() };
1309 assert_eq!(restored, original);
1310
1311 let original = Value::Int(-12345);
1313 let nb = NanBoxedValue::from_value(&original);
1314 let restored = unsafe { nb.to_value() };
1315 assert_eq!(restored, original);
1316 }
1317
1318 #[test]
1319 fn test_value_float_roundtrip() {
1320 let original = Value::Float(std::f64::consts::PI);
1321 let nb = NanBoxedValue::from_value(&original);
1322 let restored = unsafe { nb.to_value() };
1323 assert_eq!(restored, original);
1324
1325 let original = Value::Float(-std::f64::consts::E);
1327 let nb = NanBoxedValue::from_value(&original);
1328 let restored = unsafe { nb.to_value() };
1329 assert_eq!(restored, original);
1330 }
1331
1332 #[test]
1333 fn test_value_bool_roundtrip() {
1334 let original = Value::Bool(true);
1335 let nb = NanBoxedValue::from_value(&original);
1336 let restored = unsafe { nb.to_value() };
1337 assert_eq!(restored, original);
1338
1339 let original = Value::Bool(false);
1340 let nb = NanBoxedValue::from_value(&original);
1341 let restored = unsafe { nb.to_value() };
1342 assert_eq!(restored, original);
1343 }
1344
1345 #[test]
1346 fn test_value_string_roundtrip() {
1347 let original = Value::String(SeqString::from("hello world"));
1348 let nb = NanBoxedValue::from_value(&original);
1349 let restored = unsafe { nb.to_value() };
1350 assert_eq!(restored, original);
1351 }
1352
1353 #[test]
1354 fn test_value_symbol_roundtrip() {
1355 let original = Value::Symbol(SeqString::from("my-symbol"));
1356 let nb = NanBoxedValue::from_value(&original);
1357 let restored = unsafe { nb.to_value() };
1358 assert_eq!(restored, original);
1359 }
1360
1361 #[test]
1362 fn test_value_quotation_roundtrip() {
1363 let original = Value::Quotation {
1364 wrapper: 0x1234,
1365 impl_: 0x5678,
1366 };
1367 let nb = NanBoxedValue::from_value(&original);
1368 let restored = unsafe { nb.to_value() };
1369 assert_eq!(restored, original);
1370 }
1371
1372 #[test]
1373 fn test_clone_nanboxed_int() {
1374 let original = NanBoxedValue::from_int(42);
1375 let cloned = original.clone_nanboxed();
1376 assert_eq!(cloned.as_int(), 42);
1377 assert_eq!(original.as_int(), 42);
1379 }
1380
1381 #[test]
1382 fn test_clone_nanboxed_string() {
1383 let value = Value::String(SeqString::from("test"));
1384 let nb = NanBoxedValue::from_value(&value);
1385 let cloned = nb.clone_nanboxed();
1386
1387 let restored1 = unsafe { nb.to_value() };
1389 let restored2 = unsafe { cloned.to_value() };
1390
1391 assert_eq!(restored1, value);
1392 assert_eq!(restored2, value);
1393 }
1394
1395 #[test]
1396 fn test_drop_nanboxed_string() {
1397 let value = Value::String(SeqString::from("test"));
1398 let nb = NanBoxedValue::from_value(&value);
1399 unsafe { nb.drop_nanboxed() };
1401 }
1403
1404 #[test]
1405 fn test_drop_nanboxed_primitive() {
1406 let nb = NanBoxedValue::from_int(42);
1407 unsafe { nb.drop_nanboxed() };
1409 assert_eq!(nb.as_int(), 42);
1411 }
1412}