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