1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! A collection of traits and structures to help define the semantics of a multithreading garbage
//! collector.
use crate::alloc::access::Accessor;
use crate::alloc::{Alloc, AllocMut};
use crate::error::Error;

pub mod alloc;
pub mod error;
pub mod mark;
pub mod root;
pub mod trace;

/// An owned handle into a garbage collected heap. The heap should outlive
pub trait Heap {
    /// The type of handles for this heap. The primary purpose of handles is to provide guarantee
    /// the lifetime of the heap.
    type Handle;
    type Allocator;

    /// Create a new allocator into this heap. It is recommended that allocators implement `Send` so
    /// they may be shared across threads and used as thread local allocators. Similarly to heap
    /// handles, the heap is expected to outlive all allocators.
    fn create_allocator(&self) -> Self::Allocator;

    /// Create a new handle for this heap. While not required, it may be beneficial to make
    /// `type Handle = Self;`. It is assumed that handles provide shared ownership of the heap. This
    /// may be implemented via reference counting (Ex: `Arc<Self>`) or as a wrapper for unsafe code.
    fn handle(&self) -> Self::Handle;
}

/// A pointer into the heap. Depending on how the implementing garbage collector is implemented,
/// the data stored in a GC pointer can be accessed in one of a few ways.
///
/// ```rust
/// # use gc_api::Gc;
/// let mut item: Gc<i32, SomeAllocator> = allocator.alloc(3);
///
/// // `Gc<T>` may implement `Deref` to mimic `Arc<T>` in function. However, this is the least safe
/// // approach to access data and may trigger a panic if unsupported by the current GC.
/// let deref: &i32 = &*item;
///
/// // This is the recommended way to access data since it provides extra safety guarantees. The
/// // reference to an allocator prevents garbage collection from being performed while the item is
/// // in use and ensures that the heap is still alive. It also has the option to use the allocator
/// // to get information necessary to dereference the item.
/// let with_alloc: &i32 = item.with(&allocator);
/// ```
#[repr(transparent)]
pub struct Gc<T: ?Sized, H: Alloc<T>> {
    handle: <H as Alloc<T>>::RawHandle,
}

impl<T: ?Sized, H: Alloc<T>> Gc<T, H> {
    /// Use an allocator to access data held within a handle.
    ///
    /// This function is syntactic sugar for `allocator.read(self)`.
    #[inline(always)]
    pub fn get<'a, A>(&'a self, allocator: &'a A) -> <A as Accessor<T, H>>::Guard<'a>
    where
        A: Accessor<T, H>,
    {
        allocator.read(self)
    }

    #[inline(always)]
    pub fn try_get<'a, A>(
        &'a self,
        allocator: &'a A,
    ) -> Result<<A as Accessor<T, H>>::Guard<'a>, Error>
    where
        A: Accessor<T, H>,
    {
        allocator.try_read(self)
    }

    /// Converts a `Gc<T>` into the underlying raw handle type.
    pub fn into_raw(self) -> <H as Alloc<T>>::RawHandle {
        self.handle
    }

    /// Get a reference into the underlying raw handle type.
    pub fn as_raw(&self) -> &<H as Alloc<T>>::RawHandle {
        &self.handle
    }

    /// Reconstructs a Gc<T> from a raw handle type.
    ///
    /// # Safety
    /// This function should only be used with an unmodified raw handle produced by [`Gc::into_raw`]
    /// or by an underlying garbage collector implementation to create a new `Gc<T>`.
    pub unsafe fn from_raw(raw: <H as Alloc<T>>::RawHandle) -> Self {
        Gc { handle: raw }
    }
}

impl<T: ?Sized, H: Alloc<T>> Copy for Gc<T, H> where <H as Alloc<T>>::RawHandle: Copy {}

impl<T: ?Sized, H: Alloc<T>> Clone for Gc<T, H>
where
    <H as Alloc<T>>::RawHandle: Clone,
{
    fn clone(&self) -> Self {
        Gc {
            handle: self.handle.clone(),
        }
    }
}

pub type GcMut<T, H> = Gc<<H as Alloc<T>>::MutTy, H>;