1use std::ffi::c_void;
2use std::ops::{Deref, DerefMut};
3
4use crate::glue::{CallObjectRootTracer, CallValueRootTracer};
5use crate::jsapi;
6use crate::jsapi::{AutoGCRooter, AutoGCRooterKind, JSContext, JSObject, JSTracer, Value};
7use crate::rust::{Handle, MutableHandle};
8use mozjs_sys::jsgc::{CustomAutoRooterVFTable, RootKind};
9
10pub unsafe trait CustomTrace {
13 fn trace(&self, trc: *mut JSTracer);
14}
15
16unsafe impl CustomTrace for *mut JSObject {
17 fn trace(&self, trc: *mut JSTracer) {
18 let this = self as *const *mut _ as *mut *mut _;
19 unsafe {
20 CallObjectRootTracer(trc, this, c"object".as_ptr());
21 }
22 }
23}
24
25unsafe impl CustomTrace for Value {
26 fn trace(&self, trc: *mut JSTracer) {
27 let this = self as *const _ as *mut _;
28 unsafe {
29 CallValueRootTracer(trc, this, c"any".as_ptr());
30 }
31 }
32}
33
34unsafe impl<T: CustomTrace> CustomTrace for Option<T> {
35 fn trace(&self, trc: *mut JSTracer) {
36 if let Some(ref some) = *self {
37 some.trace(trc);
38 }
39 }
40}
41
42unsafe impl<T: CustomTrace> CustomTrace for Vec<T> {
43 fn trace(&self, trc: *mut JSTracer) {
44 for elem in self {
45 elem.trace(trc);
46 }
47 }
48}
49
50#[repr(C)]
53#[cfg_attr(
54 feature = "crown",
55 crown::unrooted_must_root_lint::allow_unrooted_interior
56)]
57pub struct CustomAutoRooter<T> {
58 _base: jsapi::CustomAutoRooter,
59 data: T,
60}
61
62impl<T> CustomAutoRooter<T> {
63 unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) {
64 self._base._base.add_to_root_stack(cx);
65 }
66
67 unsafe fn remove_from_root_stack(&mut self) {
68 self._base._base.remove_from_root_stack();
69 }
70}
71
72unsafe trait CustomAutoTraceable: Sized {
75 const vftable: CustomAutoRooterVFTable = CustomAutoRooterVFTable {
76 padding: CustomAutoRooterVFTable::PADDING,
77 trace: Self::trace,
78 };
79
80 unsafe extern "C" fn trace(this: *mut c_void, trc: *mut JSTracer) {
81 let this = this as *const Self;
82 let this = this.as_ref().unwrap();
83 Self::do_trace(this, trc);
84 }
85
86 fn do_trace(&self, trc: *mut JSTracer);
89}
90
91unsafe impl<T: CustomTrace> CustomAutoTraceable for CustomAutoRooter<T> {
92 fn do_trace(&self, trc: *mut JSTracer) {
93 self.data.trace(trc);
94 }
95}
96
97impl<T: CustomTrace> CustomAutoRooter<T> {
98 pub fn new(data: T) -> Self {
99 let vftable = &Self::vftable;
100 CustomAutoRooter {
101 _base: jsapi::CustomAutoRooter {
102 vtable_: vftable as *const _ as *const _,
103 _base: AutoGCRooter::new_unrooted(AutoGCRooterKind::Custom),
104 },
105 data,
106 }
107 }
108
109 pub fn root(&mut self, cx: *mut JSContext) -> CustomAutoRooterGuard<T> {
110 CustomAutoRooterGuard::new(cx, self)
111 }
112}
113
114#[cfg_attr(
121 feature = "crown",
122 crown::unrooted_must_root_lint::allow_unrooted_interior
123)]
124pub struct CustomAutoRooterGuard<'a, T: 'a + CustomTrace> {
125 rooter: &'a mut CustomAutoRooter<T>,
126}
127
128impl<'a, T: 'a + CustomTrace> CustomAutoRooterGuard<'a, T> {
129 pub fn new(cx: *mut JSContext, rooter: &'a mut CustomAutoRooter<T>) -> Self {
130 unsafe {
131 rooter.add_to_root_stack(cx);
132 }
133 CustomAutoRooterGuard { rooter }
134 }
135
136 pub fn handle(&'a self) -> Handle<'a, T>
137 where
138 T: RootKind,
139 {
140 Handle::new(&self.rooter.data)
141 }
142
143 pub fn handle_mut(&mut self) -> MutableHandle<T>
144 where
145 T: RootKind,
146 {
147 unsafe { MutableHandle::from_marked_location(&mut self.rooter.data) }
148 }
149}
150
151impl<'a, T: 'a + CustomTrace> Deref for CustomAutoRooterGuard<'a, T> {
152 type Target = T;
153 fn deref(&self) -> &T {
154 &self.rooter.data
155 }
156}
157
158impl<'a, T: 'a + CustomTrace> DerefMut for CustomAutoRooterGuard<'a, T> {
159 fn deref_mut(&mut self) -> &mut T {
160 &mut self.rooter.data
161 }
162}
163
164impl<'a, T: 'a + CustomTrace> Drop for CustomAutoRooterGuard<'a, T> {
165 fn drop(&mut self) {
166 unsafe {
167 self.rooter.remove_from_root_stack();
168 }
169 }
170}
171
172pub type SequenceRooter<T> = CustomAutoRooter<Vec<T>>;
173pub type SequenceRooterGuard<'a, T> = CustomAutoRooterGuard<'a, Vec<T>>;