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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::gc::{RootedTraceableSet, Traceable};
use crate::jsapi::{Heap, JSTracer};
use crate::rust::Handle;
use mozjs_sys::jsgc::GCMethods;
use std::ops::{Deref, DerefMut};

/// A vector of items to be rooted with `RootedVec`.
/// Guaranteed to be empty when not rooted.
pub struct RootableVec<T: Traceable> {
    v: Vec<T>,
}

impl<T: Traceable> RootableVec<T> {
    /// Create a vector of items of type T that can be rooted later.
    pub fn new_unrooted() -> RootableVec<T> {
        RootableVec { v: Vec::new() }
    }
}

unsafe impl<T: Traceable> Traceable for RootableVec<T> {
    unsafe fn trace(&self, trc: *mut JSTracer) {
        self.v.trace(trc);
    }
}

/// A vector of items rooted for the lifetime 'a.
pub struct RootedVec<'a, T: Traceable + 'static> {
    root: &'a mut RootableVec<T>,
}

impl<'a, T: Traceable + 'static> RootedVec<'a, T> {
    pub fn new(root: &'a mut RootableVec<T>) -> RootedVec<'a, T> {
        unsafe {
            RootedTraceableSet::add(root);
        }
        RootedVec { root }
    }
}

impl<'a, T: Traceable + 'static> Drop for RootedVec<'a, T> {
    fn drop(&mut self) {
        self.clear();
        unsafe {
            RootedTraceableSet::remove(self.root);
        }
    }
}

impl<'a, T: Traceable> Deref for RootedVec<'a, T> {
    type Target = Vec<T>;
    fn deref(&self) -> &Vec<T> {
        &self.root.v
    }
}

impl<'a, T: Traceable> DerefMut for RootedVec<'a, T> {
    fn deref_mut(&mut self) -> &mut Vec<T> {
        &mut self.root.v
    }
}

/// Roots any JSTraceable thing
///
/// If you have GC things like *mut JSObject or JSVal, use rooted!.
/// If you know what you're doing, use this.
pub struct RootedTraceableBox<T: Traceable + 'static> {
    ptr: *mut T,
}

impl<T: Traceable + 'static> RootedTraceableBox<T> {
    /// Root a JSTraceable thing for the life of this RootedTraceableBox
    pub fn new(traceable: T) -> RootedTraceableBox<T> {
        Self::from_box(Box::new(traceable))
    }

    /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
    pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
        let traceable = Box::into_raw(boxed_traceable);
        unsafe {
            RootedTraceableSet::add(traceable);
        }
        RootedTraceableBox { ptr: traceable }
    }

    /// Returns underlying pointer
    pub unsafe fn ptr(&self) -> *mut T {
        self.ptr
    }
}

impl<T> RootedTraceableBox<Heap<T>>
where
    Heap<T>: Traceable + 'static,
    T: GCMethods + Copy,
{
    pub fn handle(&self) -> Handle<T> {
        unsafe { Handle::from_raw((*self.ptr).handle()) }
    }
}

unsafe impl<T: Traceable + 'static> Traceable for RootedTraceableBox<T> {
    unsafe fn trace(&self, trc: *mut JSTracer) {
        (*self.ptr).trace(trc)
    }
}

impl<T: Traceable> Deref for RootedTraceableBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T: Traceable> DerefMut for RootedTraceableBox<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T: Traceable + 'static> Drop for RootedTraceableBox<T> {
    fn drop(&mut self) {
        unsafe {
            RootedTraceableSet::remove(self.ptr);
            let _ = Box::from_raw(self.ptr);
        }
    }
}