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
#![feature(extern_types, arbitrary_self_types)]
mod alloc;
mod gc_ptr;
mod list;
mod root;
mod state;
mod trace;

use std::pin::Pin;

use once_cell::sync::Lazy;

use crate::state::GcState;

pub use crate::gc_ptr::GcPtr;
pub use crate::root::Root;
pub use crate::trace::{NullTrace, Trace};

static GC: Lazy<GcState> = Lazy::new(|| GcState::default());
// thread_local! {
//     static GC: GcState = GcState::default();
// }

/// Allocate an unmanaged GcPtr
pub fn alloc_unmanaged<T: Trace>(data: T) -> GcPtr<T> {
    GcPtr::new(data)
}

/// Allocate a managed GcPtr
pub fn alloc<T: Trace>(data: T) -> GcPtr<T> {
    let gc_ptr = alloc_unmanaged(data);
    unsafe {
        manage(gc_ptr);
    }
    gc_ptr
}

/// Manage a GcPtr
///
/// Invariants: ptr must not be dangling and must not already be managed
pub unsafe fn manage<T: Trace + ?Sized>(ptr: GcPtr<T>) {
    with_gc(|gc| gc.manage(ptr))
}

/// Count objects managed by the GC
pub fn count_managed_objects() -> usize {
    with_gc(|gc| gc.objects().into_iter().count())
}

/// Count roots into the GC
pub fn count_roots() -> usize {
    with_gc(|gc| gc.count_roots())
}

fn set_root<T: Trace + ?Sized>(idx: usize, ptr: GcPtr<T>) {
    with_gc(|gc| gc.set_root(idx, ptr))
}

fn pop_root(idx: usize) {
    with_gc(|gc| gc.pop_root(idx))
}

fn with_gc<T, F: FnOnce(Pin<&GcState>) -> T>(f: F) -> T {
    let gc: Pin<&GcState> = unsafe { Pin::new_unchecked(&GC) };
    f(gc)
}

pub fn collect() {
    with_gc(|gc| gc.collect())
}