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