mozjs/gc/
collections.rs

1use crate::gc::RootedTraceableSet;
2use crate::jsapi::{Heap, JSTracer};
3use crate::rust::Handle;
4use mozjs_sys::jsapi::JS;
5use mozjs_sys::jsgc::GCMethods;
6use mozjs_sys::jsval::JSVal;
7use mozjs_sys::trace::Traceable;
8use std::ops::{Deref, DerefMut};
9
10/// A vector of items to be rooted with `RootedVec`.
11/// Guaranteed to be empty when not rooted.
12#[cfg_attr(feature = "crown", allow(crown::unrooted_must_root))]
13#[cfg_attr(
14    feature = "crown",
15    crown::unrooted_must_root_lint::allow_unrooted_interior
16)]
17pub struct RootableVec<T: Traceable> {
18    v: Vec<T>,
19}
20
21impl<T: Traceable> RootableVec<T> {
22    /// Create a vector of items of type T that can be rooted later.
23    pub fn new_unrooted() -> RootableVec<T> {
24        RootableVec { v: Vec::new() }
25    }
26}
27
28unsafe impl<T: Traceable> Traceable for RootableVec<T> {
29    unsafe fn trace(&self, trc: *mut JSTracer) {
30        self.v.trace(trc);
31    }
32}
33
34/// A vector of items rooted for the lifetime 'a.
35#[cfg_attr(
36    feature = "crown",
37    crown::unrooted_must_root_lint::allow_unrooted_interior
38)]
39pub struct RootedVec<'a, T: Traceable + 'static> {
40    root: &'a mut RootableVec<T>,
41}
42
43impl From<&RootedVec<'_, JSVal>> for JS::HandleValueArray {
44    fn from(vec: &RootedVec<'_, JSVal>) -> JS::HandleValueArray {
45        JS::HandleValueArray {
46            length_: vec.root.v.len(),
47            elements_: vec.root.v.as_ptr(),
48        }
49    }
50}
51
52impl<'a, T: Traceable + 'static> RootedVec<'a, T> {
53    pub fn new(root: &'a mut RootableVec<T>) -> RootedVec<'a, T> {
54        unsafe {
55            RootedTraceableSet::add(root);
56        }
57        RootedVec { root }
58    }
59
60    pub fn from_iter<I>(root: &'a mut RootableVec<T>, iter: I) -> Self
61    where
62        I: Iterator<Item = T>,
63    {
64        unsafe {
65            RootedTraceableSet::add(root);
66        }
67        root.v.extend(iter);
68        RootedVec { root }
69    }
70}
71
72impl<'a, T: Traceable + 'static> Drop for RootedVec<'a, T> {
73    fn drop(&mut self) {
74        self.clear();
75        unsafe {
76            RootedTraceableSet::remove(self.root);
77        }
78    }
79}
80
81impl<'a, T: Traceable> Deref for RootedVec<'a, T> {
82    type Target = Vec<T>;
83    fn deref(&self) -> &Vec<T> {
84        &self.root.v
85    }
86}
87
88impl<'a, T: Traceable> DerefMut for RootedVec<'a, T> {
89    fn deref_mut(&mut self) -> &mut Vec<T> {
90        &mut self.root.v
91    }
92}
93
94/// Roots any JSTraceable thing
95///
96/// If you have GC things like *mut JSObject or JSVal, use rooted!.
97/// If you know what you're doing, use this.
98pub struct RootedTraceableBox<T: Traceable + 'static> {
99    ptr: *mut T,
100}
101
102impl<T: Traceable + 'static> RootedTraceableBox<T> {
103    /// Root a JSTraceable thing for the life of this RootedTraceableBox
104    pub fn new(traceable: T) -> RootedTraceableBox<T> {
105        Self::from_box(Box::new(traceable))
106    }
107
108    /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
109    pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
110        let traceable = Box::into_raw(boxed_traceable);
111        unsafe {
112            RootedTraceableSet::add(traceable);
113        }
114        RootedTraceableBox { ptr: traceable }
115    }
116
117    /// Returns underlying pointer
118    pub unsafe fn ptr(&self) -> *mut T {
119        self.ptr
120    }
121}
122
123impl<T> RootedTraceableBox<Heap<T>>
124where
125    Heap<T>: Traceable + 'static,
126    T: GCMethods + Copy,
127{
128    pub fn handle(&self) -> Handle<T> {
129        unsafe { Handle::from_raw((*self.ptr).handle()) }
130    }
131}
132
133unsafe impl<T: Traceable + 'static> Traceable for RootedTraceableBox<T> {
134    unsafe fn trace(&self, trc: *mut JSTracer) {
135        (*self.ptr).trace(trc)
136    }
137}
138
139impl<T: Traceable> Deref for RootedTraceableBox<T> {
140    type Target = T;
141    fn deref(&self) -> &T {
142        unsafe { &*self.ptr }
143    }
144}
145
146impl<T: Traceable> DerefMut for RootedTraceableBox<T> {
147    fn deref_mut(&mut self) -> &mut T {
148        unsafe { &mut *self.ptr }
149    }
150}
151
152impl<T: Traceable + 'static> Drop for RootedTraceableBox<T> {
153    fn drop(&mut self) {
154        unsafe {
155            RootedTraceableSet::remove(self.ptr);
156            let _ = Box::from_raw(self.ptr);
157        }
158    }
159}