1use super::{
2 super::{
3 cons::Cons,
4 error::{Type, TypeError},
5 gc::Block,
6 },
7 ByteFnPrototype, ByteString, CharTableInner, GcString, LispBigInt, LispBuffer,
8};
9use super::{
10 ByteFn, CharTable, HashTable, LispFloat, LispHashTable, LispString, LispVec, Record,
11 RecordBuilder, SubrFn, Symbol, SymbolCell,
12};
13use crate::{
14 arith::{MAX_FIXNUM, MIN_FIXNUM},
15 core::{
16 env::sym,
17 gc::{DropStackElem, GcMoveable, GcState, Trace, TracePtr},
18 },
19};
20use bumpalo::collections::Vec as GcVec;
21use num_bigint::BigInt;
22use private::{Tag, TaggedPtr};
23use rune_core::hashmap::HashSet;
24use rune_macros::enum_methods;
25use std::marker::PhantomData;
26use std::{fmt, ptr::NonNull};
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
29pub(crate) struct RawObj {
30 ptr: *const u8,
31}
32
33unsafe impl Send for RawObj {}
34
35impl Default for RawObj {
36 fn default() -> Self {
37 Self { ptr: NIL.ptr }
38 }
39}
40
41pub(crate) const NIL: Object<'static> = unsafe { std::mem::transmute(0u64) };
46
47pub(crate) const TRUE: Object<'static> =
52 unsafe { std::mem::transmute(size_of::<SymbolCell>() << 8) };
55
56#[derive(Copy, Clone)]
61pub(crate) struct Gc<T> {
62 ptr: *const u8,
63 _data: PhantomData<T>,
64}
65
66unsafe impl<T> Send for Gc<T> {}
68
69impl<T> Gc<T> {
70 const fn new(ptr: *const u8) -> Self {
71 Self { ptr, _data: PhantomData }
72 }
73
74 unsafe fn from_ptr<U>(ptr: *const U, tag: Tag) -> Self {
75 assert_eq!(size_of::<*const U>(), size_of::<*const ()>());
76 let ptr = ptr.cast::<u8>().map_addr(|x| (x << 8) | tag as usize);
83 Self::new(ptr)
84 }
85
86 fn untag_ptr(self) -> (*const u8, Tag) {
87 let ptr = self.ptr.map_addr(|x| ((x as isize) >> 8) as usize);
88 let tag = self.get_tag();
89 (ptr, tag)
90 }
91
92 fn get_tag(self) -> Tag {
93 unsafe { std::mem::transmute(self.ptr.addr() as u8) }
94 }
95
96 pub(crate) fn into_raw(self) -> RawObj {
97 RawObj { ptr: self.ptr }
98 }
99
100 pub(in crate::core) fn into_ptr(self) -> *const u8 {
101 self.ptr
102 }
103
104 pub(crate) unsafe fn from_raw(raw: RawObj) -> Self {
105 Self::new(raw.ptr)
106 }
107
108 pub(crate) unsafe fn from_raw_ptr(raw: *mut u8) -> Self {
109 Self::new(raw)
110 }
111
112 pub(crate) fn ptr_eq<U>(self, other: Gc<U>) -> bool {
113 self.ptr == other.ptr
114 }
115
116 pub(crate) fn as_obj(&self) -> Object<'_> {
117 Gc::new(self.ptr)
118 }
119}
120
121#[expect(clippy::wrong_self_convention)]
122impl<'ob, T> Gc<T>
123where
124 T: 'ob,
125{
126 pub(crate) fn as_obj_copy(self) -> Object<'ob> {
127 Gc::new(self.ptr)
128 }
129}
130
131pub(crate) trait Untag<T> {
135 fn untag_erased(self) -> T;
136}
137
138impl<T: TaggedPtr> Untag<T> for Gc<T> {
139 fn untag_erased(self) -> T {
140 T::untag(self)
141 }
142}
143
144impl<T> Gc<T>
145where
146 Gc<T>: Untag<T>,
147{
148 pub(crate) fn untag(self) -> T {
152 Self::untag_erased(self)
153 }
154}
155
156pub(crate) trait TagType
160where
161 Self: Sized,
162{
163 type Out;
164 fn tag(self) -> Gc<Self::Out>;
165}
166
167impl<T: TaggedPtr> TagType for T {
168 type Out = Self;
169 fn tag(self) -> Gc<Self> {
170 self.tag()
171 }
172}
173
174unsafe fn cast_gc<U, V>(e: Gc<U>) -> Gc<V> {
175 Gc::new(e.ptr)
176}
177
178impl<'a, T: 'a + Copy> From<Gc<T>> for ObjectType<'a> {
179 fn from(x: Gc<T>) -> Self {
180 Gc::new(x.ptr).untag()
181 }
182}
183
184impl<'a, T: 'a + Copy> From<&Gc<T>> for ObjectType<'a> {
185 fn from(x: &Gc<T>) -> Self {
186 Gc::new(x.ptr).untag()
187 }
188}
189
190pub(crate) trait WithLifetime<'new> {
203 type Out: 'new;
204 unsafe fn with_lifetime(self) -> Self::Out;
205}
206
207impl<'new, T: WithLifetime<'new>> WithLifetime<'new> for Gc<T> {
208 type Out = Gc<<T as WithLifetime<'new>>::Out>;
209
210 unsafe fn with_lifetime(self) -> Self::Out {
211 cast_gc(self)
212 }
213}
214
215impl<'new, T, const N: usize> WithLifetime<'new> for [T; N]
216where
217 T: WithLifetime<'new>,
218{
219 type Out = [<T as WithLifetime<'new>>::Out; N];
220 unsafe fn with_lifetime(self) -> Self::Out {
221 let ptr = &self as *const [T; N] as *const Self::Out;
223 let value = unsafe { ptr.read() };
224 std::mem::forget(self);
225 value
226 }
227}
228
229impl<'new, T> WithLifetime<'new> for Vec<T>
230where
231 T: WithLifetime<'new>,
232{
233 type Out = Vec<<T as WithLifetime<'new>>::Out>;
234
235 unsafe fn with_lifetime(self) -> Self::Out {
236 std::mem::transmute(self)
237 }
238}
239
240impl<'new, T> WithLifetime<'new> for std::collections::VecDeque<T>
241where
242 T: WithLifetime<'new>,
243{
244 type Out = std::collections::VecDeque<<T as WithLifetime<'new>>::Out>;
245
246 unsafe fn with_lifetime(self) -> Self::Out {
247 std::mem::transmute(self)
248 }
249}
250
251impl<'new, T> WithLifetime<'new> for Option<T>
252where
253 T: WithLifetime<'new>,
254{
255 type Out = Option<<T as WithLifetime<'new>>::Out>;
256
257 unsafe fn with_lifetime(self) -> Self::Out {
258 self.map(|x| x.with_lifetime())
259 }
260}
261
262impl<'new, T, U> WithLifetime<'new> for (T, U)
263where
264 T: WithLifetime<'new>,
265 U: WithLifetime<'new>,
266{
267 type Out = (<T as WithLifetime<'new>>::Out, <U as WithLifetime<'new>>::Out);
268
269 unsafe fn with_lifetime(self) -> Self::Out {
270 (self.0.with_lifetime(), self.1.with_lifetime())
271 }
272}
273
274macro_rules! object_trait_impls {
275 ($ty:ty) => {
276 impl<'old, 'new> WithLifetime<'new> for &'old $ty {
277 type Out = &'new $ty;
278
279 unsafe fn with_lifetime(self) -> Self::Out {
280 std::mem::transmute(self)
281 }
282 }
283 impl GcPtr for &$ty {}
284 };
285}
286
287pub(in crate::core) trait GcPtr {}
288impl<T> GcPtr for Gc<T> {}
289impl GcPtr for Symbol<'_> {}
290
291object_trait_impls!(LispFloat);
292object_trait_impls!(Cons);
293object_trait_impls!(ByteFn);
294object_trait_impls!(LispString);
295object_trait_impls!(ByteString);
296object_trait_impls!(LispVec);
297object_trait_impls!(Record);
298object_trait_impls!(LispHashTable);
299object_trait_impls!(LispBuffer);
300object_trait_impls!(CharTable);
301object_trait_impls!(LispBigInt);
302
303pub(crate) trait IntoObject {
307 type Out<'ob>;
308
309 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>>;
310}
311
312impl<T> IntoObject for Gc<T> {
313 type Out<'ob> = ObjectType<'ob>;
314
315 fn into_obj<const C: bool>(self, _block: &Block<C>) -> Gc<Self::Out<'_>> {
316 unsafe { cast_gc(self) }
317 }
318}
319
320impl<T> IntoObject for Option<T>
321where
322 T: IntoObject,
323{
324 type Out<'ob> = ObjectType<'ob>;
325
326 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
327 match self {
328 Some(x) => unsafe { cast_gc(x.into_obj(block)) },
329 None => NIL,
330 }
331 }
332}
333
334impl<T> IntoObject for T
335where
336 T: TagType,
337{
338 type Out<'ob> = <T as TagType>::Out;
339
340 fn into_obj<const C: bool>(self, _block: &Block<C>) -> Gc<Self::Out<'_>> {
341 self.tag()
342 }
343}
344
345impl IntoObject for f64 {
346 type Out<'ob> = &'ob LispFloat;
347
348 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
349 let ptr = block.objects.alloc(LispFloat::new(self, C));
350 unsafe { Self::Out::tag_ptr(ptr) }
351 }
352}
353
354impl IntoObject for bool {
355 type Out<'a> = Symbol<'a>;
356
357 fn into_obj<const C: bool>(self, _: &Block<C>) -> Gc<Self::Out<'_>> {
358 let sym = match self {
359 true => sym::TRUE,
360 false => sym::NIL,
361 };
362 unsafe { Self::Out::tag_ptr(sym.get_ptr()) }
363 }
364}
365
366impl IntoObject for () {
367 type Out<'a> = Symbol<'a>;
368
369 fn into_obj<const C: bool>(self, _: &Block<C>) -> Gc<Self::Out<'_>> {
370 unsafe { Self::Out::tag_ptr(sym::NIL.get_ptr()) }
371 }
372}
373
374impl IntoObject for Cons {
375 type Out<'ob> = &'ob Cons;
376
377 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
378 let ptr = block.objects.alloc(self);
379 if C {
380 ptr.mark_const();
381 }
382 unsafe { Self::Out::tag_ptr(ptr) }
383 }
384}
385
386impl IntoObject for ByteFnPrototype {
387 type Out<'ob> = &'ob ByteFn;
388
389 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
390 let ptr = block.objects.alloc(ByteFn::new(self, C));
391 unsafe { Self::Out::tag_ptr(ptr) }
392 }
393}
394
395impl IntoObject for SymbolCell {
396 type Out<'ob> = Symbol<'ob>;
397
398 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
399 let ptr = block.objects.alloc(self);
400 let sym = unsafe { Symbol::from_ptr(ptr) };
401 unsafe { Self::Out::tag_ptr(sym.get_ptr()) }
402 }
403}
404
405impl IntoObject for String {
406 type Out<'ob> = &'ob LispString;
407
408 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
409 unsafe {
410 let mut this = self;
411 let ptr = this.as_mut_str();
412 let ptr = block.objects.alloc(LispString::new(ptr, C));
413 block.drop_stack.borrow_mut().push(DropStackElem::String(this));
414 Self::Out::tag_ptr(ptr)
415 }
416 }
417}
418
419impl IntoObject for GcString<'_> {
420 type Out<'ob> = <String as IntoObject>::Out<'ob>;
421
422 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
423 unsafe {
424 let mut this = self;
425 let ptr = block.objects.alloc(LispString::new(this.as_mut_str(), C));
426 std::mem::forget(this);
427 Self::Out::tag_ptr(ptr)
428 }
429 }
430}
431
432impl IntoObject for &str {
433 type Out<'ob> = <String as IntoObject>::Out<'ob>;
434
435 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
436 GcString::from_str_in(self, &block.objects).into_obj(block)
437 }
438}
439
440impl IntoObject for Vec<u8> {
441 type Out<'ob> = &'ob ByteString;
442
443 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
444 let mut this = self;
445 let slice = this.as_mut_slice();
446 let ptr = block.objects.alloc(ByteString::new(slice, C));
447 block.drop_stack.borrow_mut().push(DropStackElem::ByteString(this));
448 unsafe { <&ByteString>::tag_ptr(ptr) }
449 }
450}
451
452impl IntoObject for Vec<Object<'_>> {
453 type Out<'ob> = &'ob LispVec;
454
455 fn into_obj<const C: bool>(mut self, block: &Block<C>) -> Gc<Self::Out<'_>> {
456 unsafe {
457 let ptr = self.as_mut_slice() as *mut [Object];
459 let ptr = block.objects.alloc(LispVec::new(ptr, C));
460 block.drop_stack.borrow_mut().push(DropStackElem::Vec(self.with_lifetime()));
461 <&LispVec>::tag_ptr(ptr)
462 }
463 }
464}
465
466impl IntoObject for GcVec<'_, Object<'_>> {
467 type Out<'ob> = &'ob LispVec;
468
469 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
470 unsafe {
471 let ptr = self.into_bump_slice_mut() as *mut [Object];
473 let ptr = block.objects.alloc(LispVec::new(ptr, C));
474 <&LispVec>::tag_ptr(ptr)
475 }
476 }
477}
478
479impl IntoObject for &[Object<'_>] {
480 type Out<'ob> = &'ob LispVec;
481
482 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
483 let mut vec = GcVec::with_capacity_in(self.len(), &block.objects);
484 vec.extend_from_slice(self);
485 vec.into_obj(block)
486 }
487}
488
489impl IntoObject for RecordBuilder<'_> {
490 type Out<'ob> = &'ob Record;
491
492 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
493 unsafe {
494 let ptr = self.0.into_bump_slice_mut() as *mut [Object];
496 let ptr = block.objects.alloc(LispVec::new(ptr, C));
497 <&Record>::tag_ptr(ptr)
498 }
499 }
500}
501
502impl IntoObject for HashTable<'_> {
503 type Out<'ob> = &'ob LispHashTable;
504
505 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
506 unsafe {
507 let ptr = block.objects.alloc(LispHashTable::new(self, C));
508 block.lisp_hashtables.borrow_mut().push(ptr);
509 <&LispHashTable>::tag_ptr(ptr)
510 }
511 }
512}
513
514impl IntoObject for CharTableInner<'_> {
515 type Out<'ob> = &'ob CharTable;
516
517 fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
518 unsafe {
519 let ptr = block.objects.alloc(CharTable::new(self, C));
520 <Self::Out<'_>>::tag_ptr(ptr)
521 }
522 }
523}
524
525impl IntoObject for BigInt {
526 type Out<'ob> = &'ob LispBigInt;
527
528 fn into_obj<const C: bool>(self, block: &Block<C>) -> super::Gc<Self::Out<'_>> {
529 unsafe {
530 let ptr = block.objects.alloc(LispBigInt::new(self, C));
531 <&LispBigInt>::tag_ptr(ptr)
533 }
534 }
535}
536
537mod private {
538 use super::{Gc, WithLifetime};
539
540 #[repr(u8)]
541 pub(crate) enum Tag {
542 Symbol = 0,
544 Int,
545 Float,
546 Cons,
547 String,
548 ByteString,
549 Vec,
550 Record,
551 HashTable,
552 SubrFn,
553 ByteFn,
554 Buffer,
555 CharTable,
556 BigInt,
557 }
558
559 pub(super) trait TaggedPtr: Copy + for<'a> WithLifetime<'a> {
585 type Ptr;
588 const TAG: Tag;
591 unsafe fn tag_ptr(ptr: *const Self::Ptr) -> Gc<Self> {
596 Gc::from_ptr(ptr, Self::TAG)
597 }
598
599 fn untag(val: Gc<Self>) -> Self {
608 let (ptr, _) = val.untag_ptr();
609 unsafe { Self::from_obj_ptr(ptr) }
610 }
611
612 fn tag(self) -> Gc<Self> {
619 unsafe { Self::tag_ptr(self.get_ptr()) }
620 }
621
622 fn get_ptr(self) -> *const Self::Ptr {
627 unimplemented!()
628 }
629
630 unsafe fn from_obj_ptr(_: *const u8) -> Self {
635 unimplemented!()
636 }
637 }
638}
639
640impl<'a> TaggedPtr for ObjectType<'a> {
641 type Ptr = ObjectType<'a>;
642 const TAG: Tag = Tag::Int;
643
644 unsafe fn tag_ptr(_: *const Self::Ptr) -> Gc<Self> {
645 unimplemented!()
646 }
647 fn untag(val: Gc<Self>) -> Self {
648 let (ptr, tag) = val.untag_ptr();
649 unsafe {
650 match tag {
651 Tag::Symbol => ObjectType::Symbol(<Symbol>::from_obj_ptr(ptr)),
652 Tag::Cons => ObjectType::Cons(<&Cons>::from_obj_ptr(ptr)),
653 Tag::SubrFn => ObjectType::SubrFn(&*ptr.cast()),
654 Tag::ByteFn => ObjectType::ByteFn(<&ByteFn>::from_obj_ptr(ptr)),
655 Tag::Int => ObjectType::Int(i64::from_obj_ptr(ptr)),
656 Tag::Float => ObjectType::Float(<&LispFloat>::from_obj_ptr(ptr)),
657 Tag::String => ObjectType::String(<&LispString>::from_obj_ptr(ptr)),
658 Tag::ByteString => ObjectType::ByteString(<&ByteString>::from_obj_ptr(ptr)),
659 Tag::Vec => ObjectType::Vec(<&LispVec>::from_obj_ptr(ptr)),
660 Tag::Record => ObjectType::Record(<&Record>::from_obj_ptr(ptr)),
661 Tag::HashTable => ObjectType::HashTable(<&LispHashTable>::from_obj_ptr(ptr)),
662 Tag::Buffer => ObjectType::Buffer(<&LispBuffer>::from_obj_ptr(ptr)),
663 Tag::CharTable => ObjectType::CharTable(<&CharTable>::from_obj_ptr(ptr)),
664 Tag::BigInt => ObjectType::BigInt(<&LispBigInt>::from_obj_ptr(ptr)),
665 }
666 }
667 }
668
669 fn tag(self) -> Gc<Self> {
670 match self {
671 ObjectType::Int(x) => TaggedPtr::tag(x).into(),
672 ObjectType::Float(x) => TaggedPtr::tag(x).into(),
673 ObjectType::Symbol(x) => TaggedPtr::tag(x).into(),
674 ObjectType::Cons(x) => TaggedPtr::tag(x).into(),
675 ObjectType::Vec(x) => TaggedPtr::tag(x).into(),
676 ObjectType::Record(x) => TaggedPtr::tag(x).into(),
677 ObjectType::HashTable(x) => TaggedPtr::tag(x).into(),
678 ObjectType::String(x) => TaggedPtr::tag(x).into(),
679 ObjectType::ByteString(x) => TaggedPtr::tag(x).into(),
680 ObjectType::ByteFn(x) => TaggedPtr::tag(x).into(),
681 ObjectType::SubrFn(x) => TaggedPtr::tag(x).into(),
682 ObjectType::Buffer(x) => TaggedPtr::tag(x).into(),
683 ObjectType::CharTable(x) => TaggedPtr::tag(x).into(),
684 ObjectType::BigInt(x) => TaggedPtr::tag(x).into(),
685 }
686 }
687}
688
689impl<'a> TaggedPtr for ListType<'a> {
690 type Ptr = ListType<'a>;
691 const TAG: Tag = Tag::Int;
692
693 unsafe fn tag_ptr(_: *const Self::Ptr) -> Gc<Self> {
694 unimplemented!()
695 }
696
697 fn untag(val: Gc<Self>) -> Self {
698 let (ptr, tag) = val.untag_ptr();
699 match tag {
700 Tag::Symbol => ListType::Nil,
701 Tag::Cons => ListType::Cons(unsafe { <&Cons>::from_obj_ptr(ptr) }),
702 _ => unreachable!(),
703 }
704 }
705
706 fn tag(self) -> Gc<Self> {
707 match self {
708 ListType::Nil => unsafe { cast_gc(TaggedPtr::tag(sym::NIL)) },
709 ListType::Cons(x) => TaggedPtr::tag(x).into(),
710 }
711 }
712}
713
714impl<'a> TaggedPtr for FunctionType<'a> {
715 type Ptr = FunctionType<'a>;
716 const TAG: Tag = Tag::Int;
717
718 unsafe fn tag_ptr(_: *const Self::Ptr) -> Gc<Self> {
719 unimplemented!()
720 }
721
722 fn untag(val: Gc<Self>) -> Self {
723 let (ptr, tag) = val.untag_ptr();
724 unsafe {
725 match tag {
726 Tag::Cons => FunctionType::Cons(<&Cons>::from_obj_ptr(ptr)),
727 Tag::SubrFn => FunctionType::SubrFn(&*ptr.cast::<SubrFn>()),
729 Tag::ByteFn => FunctionType::ByteFn(<&ByteFn>::from_obj_ptr(ptr)),
730 Tag::Symbol => FunctionType::Symbol(<Symbol>::from_obj_ptr(ptr)),
731 _ => unreachable!(),
732 }
733 }
734 }
735
736 fn tag(self) -> Gc<Self> {
737 match self {
738 FunctionType::Cons(x) => TaggedPtr::tag(x).into(),
739 FunctionType::SubrFn(x) => TaggedPtr::tag(x).into(),
740 FunctionType::ByteFn(x) => TaggedPtr::tag(x).into(),
741 FunctionType::Symbol(x) => TaggedPtr::tag(x).into(),
742 }
743 }
744}
745
746impl<'a> TaggedPtr for NumberType<'a> {
747 type Ptr = NumberType<'a>;
748 const TAG: Tag = Tag::Int;
749
750 unsafe fn tag_ptr(_: *const Self::Ptr) -> Gc<Self> {
751 unimplemented!()
752 }
753
754 fn untag(val: Gc<Self>) -> Self {
755 let (ptr, tag) = val.untag_ptr();
756 unsafe {
757 match tag {
758 Tag::Int => NumberType::Int(i64::from_obj_ptr(ptr)),
759 Tag::Float => NumberType::Float(<&LispFloat>::from_obj_ptr(ptr)),
760 Tag::BigInt => NumberType::Big(<&LispBigInt>::from_obj_ptr(ptr)),
761 _ => unreachable!(),
762 }
763 }
764 }
765
766 fn tag(self) -> Gc<Self> {
767 match self {
768 NumberType::Int(x) => TaggedPtr::tag(x).into(),
769 NumberType::Float(x) => TaggedPtr::tag(x).into(),
770 NumberType::Big(x) => TaggedPtr::tag(x).into(),
771 }
772 }
773}
774
775impl TaggedPtr for i64 {
776 type Ptr = i64;
777 const TAG: Tag = Tag::Int;
778
779 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
780 ptr.addr() as i64
781 }
782
783 fn get_ptr(self) -> *const Self::Ptr {
784 let value = self.clamp(MIN_FIXNUM, MAX_FIXNUM);
786 core::ptr::without_provenance(value as usize)
787 }
788}
789
790pub(crate) fn int_to_char(int: i64) -> Result<char, TypeError> {
791 let err = TypeError::new(Type::Char, TagType::tag(int));
792 match u32::try_from(int) {
793 Ok(x) => match char::from_u32(x) {
794 Some(c) => Ok(c),
795 None => Err(err),
796 },
797 Err(_) => Err(err),
798 }
799}
800
801impl TaggedPtr for &LispFloat {
802 type Ptr = LispFloat;
803 const TAG: Tag = Tag::Float;
804 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
805 &*ptr.cast::<Self::Ptr>()
806 }
807
808 fn get_ptr(self) -> *const Self::Ptr {
809 self as *const Self::Ptr
810 }
811}
812
813impl TaggedPtr for &Cons {
814 type Ptr = Cons;
815 const TAG: Tag = Tag::Cons;
816 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
817 &*ptr.cast::<Self::Ptr>()
818 }
819
820 fn get_ptr(self) -> *const Self::Ptr {
821 self as *const Self::Ptr
822 }
823}
824
825impl TaggedPtr for &SubrFn {
826 type Ptr = SubrFn;
827 const TAG: Tag = Tag::SubrFn;
828 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
829 &*ptr.cast::<Self::Ptr>()
830 }
831
832 fn get_ptr(self) -> *const Self::Ptr {
833 self as *const Self::Ptr
834 }
835}
836
837impl TaggedPtr for Symbol<'_> {
838 type Ptr = u8;
839 const TAG: Tag = Tag::Symbol;
840
841 unsafe fn tag_ptr(ptr: *const Self::Ptr) -> Gc<Self> {
842 Gc::from_ptr(ptr, Self::TAG)
843 }
844
845 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
846 Symbol::from_offset_ptr(ptr)
847 }
848
849 fn get_ptr(self) -> *const Self::Ptr {
850 self.as_ptr()
851 }
852}
853
854impl TaggedPtr for &ByteFn {
855 type Ptr = ByteFn;
856 const TAG: Tag = Tag::ByteFn;
857 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
858 &*ptr.cast::<Self::Ptr>()
859 }
860
861 fn get_ptr(self) -> *const Self::Ptr {
862 self as *const Self::Ptr
863 }
864}
865
866impl TaggedPtr for &LispString {
867 type Ptr = LispString;
868 const TAG: Tag = Tag::String;
869 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
870 &*ptr.cast::<Self::Ptr>()
871 }
872
873 fn get_ptr(self) -> *const Self::Ptr {
874 self as *const Self::Ptr
875 }
876}
877
878impl TaggedPtr for &ByteString {
879 type Ptr = ByteString;
880 const TAG: Tag = Tag::ByteString;
881 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
882 &*ptr.cast::<Self::Ptr>()
883 }
884
885 fn get_ptr(self) -> *const Self::Ptr {
886 self as *const Self::Ptr
887 }
888}
889
890impl TaggedPtr for &LispVec {
891 type Ptr = LispVec;
892 const TAG: Tag = Tag::Vec;
893 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
894 &*ptr.cast::<Self::Ptr>()
895 }
896
897 fn get_ptr(self) -> *const Self::Ptr {
898 self as *const Self::Ptr
899 }
900}
901
902impl TaggedPtr for &Record {
903 type Ptr = LispVec;
904 const TAG: Tag = Tag::Record;
905 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
906 &*ptr.cast::<Record>()
907 }
908
909 fn get_ptr(self) -> *const Self::Ptr {
910 (self as *const Record).cast::<Self::Ptr>()
911 }
912}
913
914impl TaggedPtr for &LispHashTable {
915 type Ptr = LispHashTable;
916 const TAG: Tag = Tag::HashTable;
917 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
918 &*ptr.cast::<Self::Ptr>()
919 }
920
921 fn get_ptr(self) -> *const Self::Ptr {
922 self as *const Self::Ptr
923 }
924}
925
926impl TaggedPtr for &LispBuffer {
927 type Ptr = LispBuffer;
928 const TAG: Tag = Tag::Buffer;
929 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
930 &*ptr.cast::<Self::Ptr>()
931 }
932
933 fn get_ptr(self) -> *const Self::Ptr {
934 self as *const Self::Ptr
935 }
936}
937
938impl TaggedPtr for &CharTable {
939 type Ptr = CharTable;
940 const TAG: Tag = Tag::CharTable;
941
942 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
943 &*ptr.cast::<Self::Ptr>()
944 }
945
946 fn get_ptr(self) -> *const Self::Ptr {
947 self as *const Self::Ptr
948 }
949}
950
951impl TaggedPtr for &LispBigInt {
952 type Ptr = LispBigInt;
953 const TAG: Tag = Tag::BigInt;
954
955 unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
956 &*ptr.cast::<Self::Ptr>()
957 }
958
959 fn get_ptr(self) -> *const Self::Ptr {
960 self as *const Self::Ptr
961 }
962}
963
964impl<T> TracePtr for Gc<T> {
965 fn trace_ptr(&self, state: &mut GcState) {
966 match self.as_obj().untag() {
967 ObjectType::Int(_) | ObjectType::SubrFn(_) => {}
968 ObjectType::Float(x) => x.trace(state),
969 ObjectType::String(x) => x.trace(state),
970 ObjectType::ByteString(x) => x.trace(state),
971 ObjectType::Vec(vec) => vec.trace(state),
972 ObjectType::Record(x) => x.trace(state),
973 ObjectType::HashTable(x) => x.trace(state),
974 ObjectType::Cons(x) => x.trace(state),
975 ObjectType::Symbol(x) => x.trace(state),
976 ObjectType::ByteFn(x) => x.trace(state),
977 ObjectType::Buffer(x) => x.trace(state),
978 ObjectType::CharTable(x) => x.trace(state),
979 ObjectType::BigInt(x) => x.trace(state),
980 }
981 }
982}
983
984macro_rules! cast_gc {
985 ($supertype:ty => $($subtype:ty),+ $(,)?) => {
986 $(
987 impl<'ob> From<Gc<$subtype>> for Gc<$supertype> {
988 fn from(x: Gc<$subtype>) -> Self {
989 unsafe { cast_gc(x) }
990 }
991 }
992
993 impl<'ob> From<$subtype> for Gc<$supertype> {
994 fn from(x: $subtype) -> Self {
995 unsafe { <$subtype>::tag_ptr(x.get_ptr()).into() }
996 }
997 }
998 )+
999 };
1000}
1001
1002#[derive(Copy, Clone)]
1008#[enum_methods(Number)]
1009#[repr(u8)]
1010pub(crate) enum NumberType<'ob> {
1012 Int(i64) = Tag::Int as u8,
1013 Float(&'ob LispFloat) = Tag::Float as u8,
1014 Big(&'ob LispBigInt) = Tag::BigInt as u8,
1015}
1016cast_gc!(NumberType<'ob> => i64, &LispFloat, &LispBigInt);
1017
1018pub(crate) type Number<'ob> = Gc<NumberType<'ob>>;
1020
1021impl<'old, 'new> WithLifetime<'new> for NumberType<'old> {
1022 type Out = NumberType<'new>;
1023
1024 unsafe fn with_lifetime(self) -> Self::Out {
1025 std::mem::transmute::<NumberType<'old>, NumberType<'new>>(self)
1026 }
1027}
1028
1029#[derive(Copy, Clone)]
1031#[enum_methods(List)]
1032#[repr(u8)]
1033pub(crate) enum ListType<'ob> {
1035 Nil = Tag::Symbol as u8,
1037 Cons(&'ob Cons) = Tag::Cons as u8,
1038}
1039cast_gc!(ListType<'ob> => &'ob Cons);
1040
1041pub(crate) type List<'ob> = Gc<ListType<'ob>>;
1043
1044impl ListType<'_> {
1045 pub(crate) fn empty() -> Gc<Self> {
1046 unsafe { cast_gc(NIL) }
1047 }
1048}
1049
1050impl<'old, 'new> WithLifetime<'new> for ListType<'old> {
1051 type Out = ListType<'new>;
1052
1053 unsafe fn with_lifetime(self) -> Self::Out {
1054 std::mem::transmute::<ListType<'old>, ListType<'new>>(self)
1055 }
1056}
1057
1058#[derive(Copy, Clone, Debug)]
1060#[enum_methods(Function)]
1061#[repr(u8)]
1062pub(crate) enum FunctionType<'ob> {
1064 ByteFn(&'ob ByteFn) = Tag::ByteFn as u8,
1065 SubrFn(&'static SubrFn) = Tag::SubrFn as u8,
1066 Cons(&'ob Cons) = Tag::Cons as u8,
1067 Symbol(Symbol<'ob>) = Tag::Symbol as u8,
1068}
1069cast_gc!(FunctionType<'ob> => &'ob ByteFn, &'ob SubrFn, &'ob Cons, Symbol<'ob>);
1070
1071pub(crate) type Function<'ob> = Gc<FunctionType<'ob>>;
1075
1076impl<'old, 'new> WithLifetime<'new> for FunctionType<'old> {
1077 type Out = FunctionType<'new>;
1078
1079 unsafe fn with_lifetime(self) -> Self::Out {
1080 std::mem::transmute::<FunctionType<'old>, FunctionType<'new>>(self)
1081 }
1082}
1083
1084#[derive(Copy, Clone, PartialEq, Eq)]
1085#[enum_methods(Object)]
1086#[repr(u8)]
1087pub(crate) enum ObjectType<'ob> {
1089 Int(i64) = Tag::Int as u8,
1090 Float(&'ob LispFloat) = Tag::Float as u8,
1091 Symbol(Symbol<'ob>) = Tag::Symbol as u8,
1092 Cons(&'ob Cons) = Tag::Cons as u8,
1093 Vec(&'ob LispVec) = Tag::Vec as u8,
1094 Record(&'ob Record) = Tag::Record as u8,
1095 HashTable(&'ob LispHashTable) = Tag::HashTable as u8,
1096 String(&'ob LispString) = Tag::String as u8,
1097 ByteString(&'ob ByteString) = Tag::ByteString as u8,
1098 ByteFn(&'ob ByteFn) = Tag::ByteFn as u8,
1099 SubrFn(&'static SubrFn) = Tag::SubrFn as u8,
1100 Buffer(&'static LispBuffer) = Tag::Buffer as u8,
1101 CharTable(&'static CharTable) = Tag::CharTable as u8,
1102 BigInt(&'ob LispBigInt) = Tag::BigInt as u8,
1103}
1104
1105pub(crate) type Object<'ob> = Gc<ObjectType<'ob>>;
1108
1109cast_gc!(ObjectType<'ob> => NumberType<'ob>,
1110 ListType<'ob>,
1111 FunctionType<'ob>,
1112 i64,
1113 Symbol<'_>,
1114 &'ob LispFloat,
1115 &'ob Cons,
1116 &'ob LispVec,
1117 &'ob Record,
1118 &'ob LispHashTable,
1119 &'ob LispString,
1120 &'ob ByteString,
1121 &'ob ByteFn,
1122 &'ob SubrFn,
1123 &'ob LispBuffer,
1124 &'ob CharTable,
1125 &'ob LispBigInt
1126);
1127
1128impl ObjectType<'_> {
1129 pub(crate) const NIL: ObjectType<'static> = ObjectType::Symbol(sym::NIL);
1130 pub(crate) const TRUE: ObjectType<'static> = ObjectType::Symbol(sym::TRUE);
1131 pub(crate) fn get_type(self) -> Type {
1133 match self {
1134 ObjectType::Int(_) => Type::Int,
1135 ObjectType::Float(_) => Type::Float,
1136 ObjectType::Symbol(_) => Type::Symbol,
1137 ObjectType::Cons(_) => Type::Cons,
1138 ObjectType::Vec(_) => Type::Vec,
1139 ObjectType::Record(_) => Type::Record,
1140 ObjectType::HashTable(_) => Type::HashTable,
1141 ObjectType::String(_) => Type::String,
1142 ObjectType::ByteString(_) => Type::String,
1143 ObjectType::ByteFn(_) | ObjectType::SubrFn(_) => Type::Func,
1144 ObjectType::Buffer(_) => Type::Buffer,
1145 ObjectType::CharTable(_) => Type::CharTable,
1146 ObjectType::BigInt(_) => Type::BigInt,
1147 }
1148 }
1149}
1150
1151impl<'old, 'new> WithLifetime<'new> for ObjectType<'old> {
1154 type Out = ObjectType<'new>;
1155
1156 unsafe fn with_lifetime(self) -> Self::Out {
1157 std::mem::transmute::<ObjectType<'old>, ObjectType<'new>>(self)
1158 }
1159}
1160
1161impl WithLifetime<'_> for i64 {
1162 type Out = i64;
1163
1164 unsafe fn with_lifetime(self) -> Self::Out {
1165 self
1166 }
1167}
1168
1169impl From<usize> for Object<'_> {
1170 fn from(x: usize) -> Self {
1171 let ptr = core::ptr::without_provenance(x);
1172 unsafe { i64::tag_ptr(ptr).into() }
1173 }
1174}
1175
1176impl TagType for usize {
1177 type Out = i64;
1178 fn tag(self) -> Gc<Self::Out> {
1179 TagType::tag(self as i64)
1180 }
1181}
1182
1183impl TagType for i32 {
1184 type Out = i64;
1185 fn tag(self) -> Gc<Self::Out> {
1186 TagType::tag(i64::from(self))
1187 }
1188}
1189
1190impl TagType for u32 {
1191 type Out = i64;
1192 fn tag(self) -> Gc<Self::Out> {
1193 TagType::tag(i64::from(self))
1194 }
1195}
1196
1197impl TagType for char {
1198 type Out = i64;
1199 fn tag(self) -> Gc<Self::Out> {
1200 TagType::tag(i64::from(self as u32))
1201 }
1202}
1203
1204impl TagType for u64 {
1205 type Out = i64;
1206 fn tag(self) -> Gc<Self::Out> {
1207 TagType::tag(self as i64)
1208 }
1209}
1210
1211impl TagType for u16 {
1212 type Out = i64;
1213 fn tag(self) -> Gc<Self::Out> {
1214 TagType::tag(i64::from(self))
1215 }
1216}
1217
1218impl From<i32> for Object<'_> {
1219 fn from(x: i32) -> Self {
1220 i64::from(x).into()
1221 }
1222}
1223
1224impl From<Object<'_>> for () {
1225 fn from(_: Object) {}
1226}
1227
1228pub(crate) type OptionalFlag = Option<()>;
1229
1230impl<'ob> TryFrom<Object<'ob>> for Number<'ob> {
1231 type Error = TypeError;
1232
1233 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1234 match value.get_tag() {
1235 Tag::Int | Tag::Float => unsafe { Ok(cast_gc(value)) },
1236 _ => Err(TypeError::new(Type::Number, value)),
1237 }
1238 }
1239}
1240
1241impl<'ob> TryFrom<Object<'ob>> for Option<Number<'ob>> {
1242 type Error = TypeError;
1243
1244 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1245 if value.is_nil() { Ok(None) } else { value.try_into().map(Some) }
1246 }
1247}
1248
1249impl<'ob> TryFrom<Object<'ob>> for List<'ob> {
1250 type Error = TypeError;
1251
1252 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1253 match value.untag() {
1254 ObjectType::NIL | ObjectType::Cons(_) => unsafe { Ok(cast_gc(value)) },
1255 _ => Err(TypeError::new(Type::List, value)),
1256 }
1257 }
1258}
1259
1260impl<'ob> TryFrom<Function<'ob>> for Gc<&'ob Cons> {
1261 type Error = TypeError;
1262
1263 fn try_from(value: Function<'ob>) -> Result<Self, Self::Error> {
1264 match value.untag() {
1265 FunctionType::Cons(_) => unsafe { Ok(cast_gc(value)) },
1266 _ => Err(TypeError::new(Type::Cons, value)),
1267 }
1268 }
1269}
1270
1271impl<'ob> TryFrom<Object<'ob>> for Gc<Symbol<'ob>> {
1272 type Error = TypeError;
1273 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1274 match value.untag() {
1275 ObjectType::Symbol(_) => unsafe { Ok(cast_gc(value)) },
1276 _ => Err(TypeError::new(Type::Symbol, value)),
1277 }
1278 }
1279}
1280
1281impl<'ob> TryFrom<Object<'ob>> for Function<'ob> {
1282 type Error = TypeError;
1283
1284 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1285 match value.get_tag() {
1286 Tag::ByteFn | Tag::SubrFn | Tag::Cons | Tag::Symbol => unsafe { Ok(cast_gc(value)) },
1287 _ => Err(TypeError::new(Type::Func, value)),
1288 }
1289 }
1290}
1291
1292impl<'ob> TryFrom<Object<'ob>> for Gc<i64> {
1297 type Error = TypeError;
1298
1299 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1300 match value.get_tag() {
1301 Tag::Int => unsafe { Ok(cast_gc(value)) },
1302 _ => Err(TypeError::new(Type::Int, value)),
1303 }
1304 }
1305}
1306
1307impl<'ob> Object<'ob> {
1310 pub(crate) fn try_from_option<T, E>(value: Object<'ob>) -> Result<Option<T>, E>
1311 where
1312 Object<'ob>: TryInto<T, Error = E>,
1313 {
1314 if value.is_nil() { Ok(None) } else { Ok(Some(value.try_into()?)) }
1315 }
1316
1317 pub(crate) fn is_nil(self) -> bool {
1318 self == sym::NIL
1319 }
1320}
1321
1322impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob Cons> {
1323 type Error = TypeError;
1324
1325 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1326 match value.get_tag() {
1327 Tag::Cons => unsafe { Ok(cast_gc(value)) },
1328 _ => Err(TypeError::new(Type::Cons, value)),
1329 }
1330 }
1331}
1332
1333impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispString> {
1334 type Error = TypeError;
1335
1336 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1337 match value.get_tag() {
1338 Tag::String => unsafe { Ok(cast_gc(value)) },
1339 _ => Err(TypeError::new(Type::String, value)),
1340 }
1341 }
1342}
1343
1344impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob ByteString> {
1345 type Error = TypeError;
1346
1347 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1348 match value.get_tag() {
1349 Tag::ByteString => unsafe { Ok(cast_gc(value)) },
1350 _ => Err(TypeError::new(Type::String, value)),
1351 }
1352 }
1353}
1354
1355impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispHashTable> {
1356 type Error = TypeError;
1357
1358 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1359 match value.get_tag() {
1360 Tag::HashTable => unsafe { Ok(cast_gc(value)) },
1361 _ => Err(TypeError::new(Type::HashTable, value)),
1362 }
1363 }
1364}
1365
1366impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispVec> {
1367 type Error = TypeError;
1368
1369 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1370 match value.get_tag() {
1371 Tag::Vec => unsafe { Ok(cast_gc(value)) },
1372 _ => Err(TypeError::new(Type::Vec, value)),
1373 }
1374 }
1375}
1376
1377impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispBuffer> {
1378 type Error = TypeError;
1379
1380 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1381 match value.get_tag() {
1382 Tag::Buffer => unsafe { Ok(cast_gc(value)) },
1383 _ => Err(TypeError::new(Type::Buffer, value)),
1384 }
1385 }
1386}
1387
1388impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob CharTable> {
1389 type Error = TypeError;
1390
1391 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1392 match value.get_tag() {
1393 Tag::CharTable => unsafe { Ok(cast_gc(value)) },
1394 _ => Err(TypeError::new(Type::String, value)),
1395 }
1396 }
1397}
1398
1399impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispBigInt> {
1400 type Error = TypeError;
1401
1402 fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
1403 match value.get_tag() {
1404 Tag::BigInt => unsafe { Ok(cast_gc(value)) },
1405 _ => Err(TypeError::new(Type::String, value)),
1406 }
1407 }
1408}
1409
1410impl<'ob> std::ops::Deref for Gc<&'ob Cons> {
1411 type Target = Cons;
1412
1413 fn deref(&self) -> &'ob Self::Target {
1414 self.untag()
1415 }
1416}
1417
1418pub(crate) trait CloneIn<'new, T>
1419where
1420 T: 'new,
1421{
1422 fn clone_in<const C: bool>(&self, bk: &'new Block<C>) -> Gc<T>;
1423}
1424
1425impl<'new, T, U, E> CloneIn<'new, U> for Gc<T>
1426where
1427 T: WithLifetime<'new, Out = U>,
1429 Gc<U>: TryFrom<Object<'new>, Error = E> + 'new,
1430{
1431 fn clone_in<const C: bool>(&self, bk: &'new Block<C>) -> Gc<U> {
1432 let obj = match self.as_obj().untag() {
1433 ObjectType::Int(x) => x.into(),
1434 ObjectType::Cons(x) => x.clone_in(bk).into(),
1435 ObjectType::String(x) => x.clone_in(bk).into(),
1436 ObjectType::ByteString(x) => x.clone_in(bk).into(),
1437 ObjectType::Symbol(x) => x.clone_in(bk).into(),
1438 ObjectType::ByteFn(x) => x.clone_in(bk).into(),
1439 ObjectType::SubrFn(x) => x.into(),
1440 ObjectType::Float(x) => x.clone_in(bk).into(),
1441 ObjectType::Vec(x) => x.clone_in(bk).into(),
1442 ObjectType::Record(x) => x.clone_in(bk).into(),
1443 ObjectType::HashTable(x) => x.clone_in(bk).into(),
1444 ObjectType::Buffer(x) => x.clone_in(bk).into(),
1445 ObjectType::CharTable(x) => x.clone_in(bk).into(),
1446 ObjectType::BigInt(x) => x.clone_in(bk).into(),
1447 };
1448 let Ok(x) = Gc::<U>::try_from(obj) else { unreachable!() };
1449 x
1450 }
1451}
1452
1453impl<T> GcMoveable for Gc<T>
1454where
1455 Self: Untag<T> + Copy,
1456 T: GcMoveable<Value = T> + TagType<Out = T>,
1457{
1458 type Value = Self;
1459
1460 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
1461 self.untag().move_value(to_space).map(|(x, moved)| (x.tag(), moved))
1462 }
1463}
1464
1465impl GcMoveable for Object<'_> {
1466 type Value = Self;
1467
1468 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
1469 let data = match self.untag() {
1470 ObjectType::Int(_) | ObjectType::SubrFn(_) | ObjectType::NIL => return None,
1471 ObjectType::Float(x) => cast_pair(x.move_value(to_space)?),
1472 ObjectType::Cons(x) => cast_pair(x.move_value(to_space)?),
1473 ObjectType::Vec(x) => cast_pair(x.move_value(to_space)?),
1474 ObjectType::Record(x) => cast_pair(x.move_value(to_space)?),
1475 ObjectType::HashTable(x) => cast_pair(x.move_value(to_space)?),
1476 ObjectType::String(x) => cast_pair(x.move_value(to_space)?),
1477 ObjectType::ByteString(x) => cast_pair(x.move_value(to_space)?),
1478 ObjectType::ByteFn(x) => cast_pair(x.move_value(to_space)?),
1479 ObjectType::Buffer(x) => cast_pair(x.move_value(to_space)?),
1480 ObjectType::Symbol(x) => {
1481 let (sym, moved) = x.move_value(to_space)?;
1484 (sym.as_ptr(), moved)
1485 }
1486 ObjectType::CharTable(x) => cast_pair(x.move_value(to_space)?),
1487 ObjectType::BigInt(x) => cast_pair(x.move_value(to_space)?),
1488 };
1489
1490 let tag = self.get_tag();
1491 unsafe { Some((Object::from_ptr(data.0, tag), data.1)) }
1492 }
1493}
1494
1495impl GcMoveable for Function<'_> {
1496 type Value = Self;
1497
1498 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
1499 let data = match self.untag() {
1500 FunctionType::SubrFn(_) => return None,
1501 FunctionType::Cons(x) => cast_pair(x.move_value(to_space)?),
1502 FunctionType::ByteFn(x) => cast_pair(x.move_value(to_space)?),
1503 FunctionType::Symbol(x) => {
1504 let (sym, moved) = x.move_value(to_space)?;
1505 cast_pair((NonNull::from(sym.get()), moved))
1506 }
1507 };
1508
1509 let tag = self.get_tag();
1510 unsafe { Some((Function::from_ptr(data.0, tag), data.1)) }
1511 }
1512}
1513
1514impl GcMoveable for List<'_> {
1515 type Value = Self;
1516
1517 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
1518 let data = match self.untag() {
1519 ListType::Cons(x) => cast_pair(x.move_value(to_space)?),
1520 ListType::Nil => return None,
1521 };
1522
1523 let tag = self.get_tag();
1524 unsafe { Some((List::from_ptr(data.0, tag), data.1)) }
1525 }
1526}
1527
1528fn cast_pair<T>((ptr, moved): (NonNull<T>, bool)) -> (*const u8, bool) {
1529 (ptr.as_ptr().cast::<u8>(), moved)
1530}
1531
1532impl PartialEq<&str> for Object<'_> {
1533 fn eq(&self, other: &&str) -> bool {
1534 match self.untag() {
1535 ObjectType::String(x) => **x == **other,
1536 _ => false,
1537 }
1538 }
1539}
1540
1541impl PartialEq<char> for Object<'_> {
1542 fn eq(&self, other: &char) -> bool {
1543 match self.untag() {
1544 ObjectType::Int(x) => *other as i64 == x,
1545 _ => false,
1546 }
1547 }
1548}
1549
1550impl PartialEq<Symbol<'_>> for Object<'_> {
1551 fn eq(&self, other: &Symbol) -> bool {
1552 match self.untag() {
1553 ObjectType::Symbol(x) => x == *other,
1554 _ => false,
1555 }
1556 }
1557}
1558
1559impl PartialEq<f64> for Object<'_> {
1560 fn eq(&self, other: &f64) -> bool {
1561 use float_cmp::ApproxEq;
1562 match self.untag() {
1563 ObjectType::Float(x) => x.approx_eq(*other, (f64::EPSILON, 2)),
1564 _ => false,
1565 }
1566 }
1567}
1568
1569impl PartialEq<i64> for Object<'_> {
1570 fn eq(&self, other: &i64) -> bool {
1571 match self.untag() {
1572 ObjectType::Int(x) => x == *other,
1573 _ => false,
1574 }
1575 }
1576}
1577
1578impl PartialEq<bool> for Object<'_> {
1579 fn eq(&self, other: &bool) -> bool {
1580 if *other {
1581 matches!(self.untag(), ObjectType::Symbol(sym::TRUE))
1582 } else {
1583 matches!(self.untag(), ObjectType::Symbol(sym::NIL))
1584 }
1585 }
1586}
1587
1588impl<'ob> Object<'ob> {
1589 pub(crate) fn as_cons_pair(self) -> Result<(Symbol<'ob>, ObjectType<'ob>), TypeError> {
1592 let cons: &Cons = self.try_into()?;
1593 let sym = cons.car().try_into()?;
1594 Ok((sym, cons.cdr().untag()))
1595 }
1596}
1597
1598impl<'ob> Function<'ob> {
1599 pub(crate) fn as_cons_pair(self) -> Result<(Symbol<'ob>, FunctionType<'ob>), TypeError> {
1602 if let FunctionType::Cons(cons) = self.untag() {
1603 let sym = cons.car().try_into()?;
1604 let fun: Function = cons.cdr().try_into()?;
1605 Ok((sym, fun.untag()))
1606 } else {
1607 Err(TypeError::new(Type::Cons, self))
1608 }
1609 }
1610}
1611
1612impl Default for Object<'_> {
1613 fn default() -> Self {
1614 NIL
1615 }
1616}
1617
1618impl Default for List<'_> {
1619 fn default() -> Self {
1620 ListType::empty()
1621 }
1622}
1623
1624impl<T> fmt::Display for Gc<T> {
1625 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1626 write!(f, "{}", self.as_obj().untag())
1627 }
1628}
1629
1630impl<T> fmt::Debug for Gc<T> {
1631 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1632 write!(f, "{self}")
1633 }
1634}
1635
1636impl<T> PartialEq for Gc<T> {
1637 fn eq(&self, other: &Self) -> bool {
1638 self.ptr == other.ptr || self.as_obj().untag() == other.as_obj().untag()
1639 }
1640}
1641
1642impl<T> Eq for Gc<T> {}
1643
1644use std::hash::{Hash, Hasher};
1645impl<T> Hash for Gc<T> {
1646 fn hash<H: Hasher>(&self, state: &mut H) {
1647 self.ptr.hash(state);
1648 }
1649}
1650
1651impl fmt::Display for ObjectType<'_> {
1652 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1653 self.display_walk(f, &mut HashSet::default())
1654 }
1655}
1656
1657impl fmt::Debug for ObjectType<'_> {
1658 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1659 self.display_walk(f, &mut HashSet::default())
1660 }
1661}
1662
1663impl ObjectType<'_> {
1664 pub(crate) fn display_walk(
1665 &self,
1666 f: &mut fmt::Formatter,
1667 seen: &mut HashSet<*const u8>,
1668 ) -> fmt::Result {
1669 use fmt::Display as D;
1670 match self {
1671 ObjectType::Int(x) => D::fmt(x, f),
1672 ObjectType::Cons(x) => x.display_walk(f, seen),
1673 ObjectType::Vec(x) => x.display_walk(f, seen),
1674 ObjectType::Record(x) => x.display_walk(f, seen),
1675 ObjectType::HashTable(x) => x.display_walk(f, seen),
1676 ObjectType::String(x) => write!(f, "\"{x}\""),
1677 ObjectType::ByteString(x) => write!(f, "\"{x}\""),
1678 ObjectType::Symbol(x) => D::fmt(x, f),
1679 ObjectType::ByteFn(x) => D::fmt(x, f),
1680 ObjectType::SubrFn(x) => D::fmt(x, f),
1681 ObjectType::Float(x) => D::fmt(x, f),
1682 ObjectType::Buffer(x) => D::fmt(x, f),
1683 ObjectType::CharTable(x) => D::fmt(x, f),
1684 ObjectType::BigInt(x) => D::fmt(x, f),
1685 }
1686 }
1687}
1688
1689#[cfg(test)]
1690mod test {
1691 use super::{MAX_FIXNUM, MIN_FIXNUM, TagType};
1692 use crate::core::gc::{Context, RootSet};
1693 use rune_core::macros::list;
1694
1695 #[test]
1696 fn test_clamp_fixnum() {
1697 assert_eq!(0i64.tag().untag(), 0);
1698 assert_eq!((-1_i64).tag().untag(), -1);
1699 assert_eq!(i64::MAX.tag().untag(), MAX_FIXNUM);
1700 assert_eq!(MAX_FIXNUM.tag().untag(), MAX_FIXNUM);
1701 assert_eq!(i64::MIN.tag().untag(), MIN_FIXNUM);
1702 assert_eq!(MIN_FIXNUM.tag().untag(), MIN_FIXNUM);
1703 }
1704
1705 #[test]
1706 fn test_print_circle() {
1707 let roots = &RootSet::default();
1708 let cx = &Context::new(roots);
1709 let cons = list![1; cx];
1710 cons.unwrap_cons().set_cdr(cons).unwrap();
1711 assert_eq!(format!("{cons}"), "(1 . #0)");
1712
1713 cons.unwrap_cons().set_car(cons).unwrap();
1714 assert_eq!(format!("{cons}"), "(#0 . #0)");
1715 }
1716}