rune/core/object/
tagged.rs

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
42/// A `nil` object.
43///
44/// The build.rs file guarantees that that `nil` is the first symbol in
45/// `BUILTIN_SYMBOLS`, so we know it will always be 0.
46pub(crate) const NIL: Object<'static> = unsafe { std::mem::transmute(0u64) };
47
48/// A `t` object.
49///
50/// The build.rs file guarantees that that `t` is the second symbol in
51/// `BUILTIN_SYMBOLS`, so we can rely on its value being constant.
52pub(crate) const TRUE: Object<'static> =
53    // offset from 0 by size of SymbolCell and then shift 8 to account for
54    // tagging
55    unsafe { std::mem::transmute(size_of::<SymbolCell>() << 8) };
56
57/// This type has two meanings, it is both a value that is tagged as well as
58/// something that is managed by the GC. It is intended to be pointer sized, and
59/// have a lifetime tied to the context which manages garbage collections. A Gc
60/// can be reinterpreted as any type that shares the same tag.
61#[derive(Copy, Clone)]
62pub(crate) struct Gc<T> {
63    ptr: *const u8,
64    _data: PhantomData<T>,
65}
66
67// TODO need to find a better way to handle this
68unsafe 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        // TODO: Adding this check can result in better code gen when tagging
78        // and untagging
79        // let top = x >> 55;
80        // if top != 0 && top != -1 {
81        //     unsafe { std::hint::unreachable_unchecked(); }
82        // }
83        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
132/// The [TaggedPtr] trait is local to this module (by design). This trait
133/// exports the one pubic method we want (untag) so it can be used in other
134/// modules.
135pub(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    /// A non-trait version of [Untag::untag_erased]. This is useful when we
150    /// don't want to import the trait all over the place. The only time we need
151    /// to import the trait is in generic code.
152    pub(crate) fn untag(self) -> T {
153        Self::untag_erased(self)
154    }
155}
156
157/// A wrapper trait to expose the `tag` method for GC managed references and
158/// immediate values. This is convenient when we don't have access to the
159/// `Context` but want to retag a value. Doesn't currently have a lot of use.
160pub(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
193////////////////////////
194// Traits for Objects //
195////////////////////////
196
197/// Helper trait to change the lifetime of a Gc mangaged type. This is useful
198/// because objects are initially tied to the lifetime of the
199/// [Context](crate::core::gc::Context) they are allocated in. But when rooted
200/// the lifetime is dissociated from the Context. If we only worked with
201/// references, we could just use transmutes or casts to handle this, but
202/// generic types don't expose their lifetimes. This trait is used to work
203/// around that. Must be used with extreme care, as it is easy to cast it to an
204/// invalid lifetime.
205pub(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        // work around since we can't transmute arrays
225        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
308/// Trait for types that can be managed by the GC. This trait is implemented for
309/// as many types as possible, even for types that are already Gc managed, Like
310/// `Gc<T>`. This makes it easier to write generic code for working with Gc types.
311pub(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            // having the reference implicity cast a ptr triggers UB
463            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            // having the reference implicity cast a ptr triggers UB
477            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            // record is the same layout as lispvec, just a different newtype wrapper
500            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            // block.lisp_integers.borrow_mut().push(ptr);
537            <&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 must be 0 to enable nil to be all zeroes
566        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    /// Trait for tagged pointers. Anything that can be stored and passed around
585    /// by the lisp machine should implement this trait. There are two "flavors"
586    /// of types that implement this trait. First is "base" types, which are
587    /// pointers to some memory managed by the GC with a unique tag (e.g
588    /// `LispString`, `LispVec`). This may seem stange that we would define a
589    /// tagged pointer when the type is known (i.e. `Gc<i64>`), but doing so let's
590    /// us reinterpret bits without changing the underlying memory. Base types
591    /// are untagged into a pointer.
592    ///
593    /// The second type of implementor is "sum" types which can represent more
594    /// then 1 base types (e.g `Object`, `List`). Sum types are untagged into an
595    /// enum. this let's us easily match against them to operate on the possible
596    /// value. Multiple sum types are defined (instead of just a single `Object`
597    /// type) to allow the rust code to be more precise in what values are
598    /// allowed.
599    ///
600    /// The tagging scheme uses the bottom byte of the `Gc` to represent the
601    /// tag, meaning that we have 256 possible values. The data is shifted left
602    /// by 8 bits, meaning that are fixnums are limited to 56 bits. This scheme
603    /// has the advantage that it is easy to get the tag (just read the byte)
604    /// and it maps nicely onto rusts enums. This method needs to be benchmarked
605    /// and could change in the future.
606    ///
607    /// Every method has a default implementation, and the doc string
608    /// indicates if it should be reimplemented or left untouched.
609    pub(super) trait TaggedPtr: Copy + for<'a> WithLifetime<'a> {
610        /// The type of object being pointed to. This will be different for all
611        /// implementors.
612        type Ptr;
613        /// Tag value. This is only applicable to base values. Use Int for sum
614        /// types.
615        const TAG: Tag;
616        /// Given a pointer to `Ptr` return a Tagged pointer.
617        ///
618        /// Base: default
619        /// Sum: implement
620        unsafe fn tag_ptr(ptr: *const Self::Ptr) -> Gc<Self> {
621            Gc::from_ptr(ptr, Self::TAG)
622        }
623
624        /// Remove the tag from the `Gc<T>` and return the inner type. If it is
625        /// base type then it will only have a single possible value and can be
626        /// untagged without checks, but sum types need to create all values
627        /// they can hold. We use tagged base types to let us reinterpret bits
628        /// without actually modify them.
629        ///
630        /// Base: default
631        /// Sum: implement
632        fn untag(val: Gc<Self>) -> Self {
633            let (ptr, _) = val.untag_ptr();
634            unsafe { Self::from_obj_ptr(ptr) }
635        }
636
637        /// Given the type, return a tagged version of it. When using a sum type
638        /// or an immediate value like i64, we override this method to set the
639        /// proper tag.
640        ///
641        /// Base: default
642        /// Sum: implement
643        fn tag(self) -> Gc<Self> {
644            unsafe { Self::tag_ptr(self.get_ptr()) }
645        }
646
647        /// Get the underlying pointer.
648        ///
649        /// Base: implement
650        /// Sum: default
651        fn get_ptr(self) -> *const Self::Ptr {
652            unimplemented!()
653        }
654
655        /// Given an untyped pointer, reinterpret to self.
656        ///
657        /// Base: implement
658        /// Sum: default
659        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                // SubrFn does not have IntoObject implementation, so we cast it directly
761                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        // prevent wrapping
818        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////////////////////////
1064// Proc macro section //
1065////////////////////////
1066
1067// Number
1068#[derive(Copy, Clone)]
1069#[enum_methods(Number)]
1070#[repr(u8)]
1071/// The enum form of [Number] to take advantage of ergonomics of enums in Rust.
1072pub(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
1079/// Represents a tagged pointer to a number value
1080pub(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// List
1091#[derive(Copy, Clone)]
1092#[enum_methods(List)]
1093#[repr(u8)]
1094/// The enum form of [List] to take advantage of ergonomics of enums in Rust.
1095pub(crate) enum ListType<'ob> {
1096    // Since Tag::Symbol is 0 and sym::NIL is 0, we can use 0 as the nil value
1097    Nil = Tag::Symbol as u8,
1098    Cons(&'ob Cons) = Tag::Cons as u8,
1099}
1100cast_gc!(ListType<'ob> => &'ob Cons);
1101
1102/// Represents a tagged pointer to a list value (cons or nil)
1103pub(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// Function
1120#[derive(Copy, Clone, Debug)]
1121#[enum_methods(Function)]
1122#[repr(u8)]
1123/// The enum form of [Function] to take advantage of ergonomics of enums in Rust.
1124pub(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
1132/// Represents a tagged pointer to a lisp object that could be interpreted as a
1133/// function. Note that not all `Function` types are valid functions (it could
1134/// be a cons cell for example).
1135pub(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)]
1148/// The enum form of [Object] to take advantage of ergonomics of enums in Rust.
1149pub(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
1168/// The Object defintion that contains all other possible lisp objects. This
1169/// type must remain covariant over 'ob.
1170pub(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    /// Return the type of an object
1197    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
1218// Object Impl's
1219
1220impl<'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
1359///////////////////////////
1360// Other implementations //
1361///////////////////////////
1362
1363impl<'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
1374// This function is needed due to the lack of specialization and there being a
1375// blanket impl for From<T> for Option<T>
1376impl<'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    // The WithLifetime bound ensures that T is the same type as U
1533    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                // Need to handle specially because a symbol is not a pointer,
1589                // but rather an offset
1590                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    /// Convience method to easily match against cons cells that are the start
1699    /// of a list of values.
1700    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    /// Convience method to easily match against cons cells that are the start
1709    /// of a list of values.
1710    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}