Skip to main content

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