1use std::marker::PhantomData;
2use std::mem::MaybeUninit;
3use std::ops::{Deref, IndexMut};
4use std::ptr;
5use std::ptr::NonNull;
6
7use crate::context::NoGC;
8use crate::jsapi::{jsid, JSContext, JSFunction, JSObject, JSScript, JSString, Symbol, Value, JS};
9use mozjs_sys::jsgc::{RootKind, Rooted};
10
11use crate::jsapi::Handle as RawHandle;
12use crate::jsapi::HandleObject as RawHandleObject;
13use crate::jsapi::HandleValue as RawHandleValue;
14use crate::jsapi::MutableHandle as RawMutableHandle;
15use mozjs_sys::jsgc::IntoHandle as IntoRawHandle;
16use mozjs_sys::jsgc::IntoMutableHandle as IntoRawMutableHandle;
17use mozjs_sys::jsgc::ValueArray;
18
19#[cfg_attr(
23 feature = "crown",
24 crown::unrooted_must_root_lint::allow_unrooted_interior
25)]
26pub struct RootedGuard<'a, T: 'a + RootKind> {
27 root: *mut Rooted<T>,
28 anchor: PhantomData<&'a mut Rooted<T>>,
29}
30
31impl<'a, T: 'a + RootKind> RootedGuard<'a, T> {
32 pub fn new(cx: *mut JSContext, root: &'a mut MaybeUninit<Rooted<T>>, initial: T) -> Self {
33 let root: *mut Rooted<T> = root.write(Rooted::new_unrooted(initial));
34
35 unsafe {
36 Rooted::add_to_root_stack(root, cx);
37 RootedGuard {
38 root,
39 anchor: PhantomData,
40 }
41 }
42 }
43
44 pub fn handle(&'a self) -> Handle<'a, T> {
45 unsafe { Handle::from_marked_location(self.as_ptr()) }
47 }
48
49 pub fn handle_mut(&'_ mut self) -> MutableHandle<'_, T> {
50 unsafe { MutableHandle::from_marked_location(self.as_ptr()) }
51 }
52
53 pub fn as_ptr(&self) -> *mut T {
54 unsafe { (&raw mut (*self.root).data) }
56 }
57
58 pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
76 where
77 'a: 's,
78 {
79 unsafe { &*(self.as_ptr()) }
80 }
81
82 pub fn as_mut_ref<'s: 'r, 'cx: 'r, 'r>(&'s mut self, _no_gc: &'cx NoGC) -> &'r mut T
100 where
101 'a: 's,
102 {
103 unsafe { &mut *(self.as_ptr()) }
104 }
105
106 pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
109 where
110 'a: 'b,
111 {
112 &mut *(self.as_ptr())
113 }
114
115 pub fn get(&self) -> T
116 where
117 T: Copy,
118 {
119 *self.deref()
120 }
121
122 pub fn set(&mut self, v: T) {
123 unsafe { *self.as_mut() = v };
125 }
126}
127
128impl<'a, T> RootedGuard<'a, Option<T>>
129where
130 Option<T>: RootKind,
131{
132 pub fn take(&mut self) -> Option<T> {
133 unsafe { self.as_mut().take() }
135 }
136}
137
138impl<'a, T> RootedGuard<'a, Vec<T>>
139where
140 Vec<T>: RootKind,
141{
142 pub fn push(&mut self, value: T) {
143 unsafe { self.as_mut().push(value) }
145 }
146
147 pub fn extend(&mut self, iterator: impl Iterator<Item = T>) {
148 unsafe { self.as_mut().extend(iterator) }
150 }
151
152 pub fn set_index(&mut self, index: usize, value: T) {
153 unsafe {
155 *self.as_mut().index_mut(index) = value;
156 }
157 }
158
159 pub fn handle_at(&'_ self, index: usize) -> Handle<'_, T> {
160 assert!(index < self.len());
161 unsafe { Handle::from_marked_location(self.deref().as_ptr().add(index)) }
163 }
164
165 pub fn handle_mut_at(&'_ mut self, index: usize) -> MutableHandle<'_, T> {
166 assert!(index < self.len());
167 unsafe { MutableHandle::from_marked_location(self.as_mut().as_mut_ptr().add(index)) }
169 }
170
171 pub fn take(&'_ mut self) -> Vec<T> {
172 std::mem::take(unsafe { self.as_mut() })
174 }
175}
176
177impl<'a, T: 'a + RootKind> Deref for RootedGuard<'a, T> {
178 type Target = T;
179
180 fn deref(&self) -> &T {
183 unsafe { &(*self.root).data }
184 }
185}
186
187impl<'a, T: 'a + RootKind> Drop for RootedGuard<'a, T> {
188 fn drop(&mut self) {
189 unsafe {
192 let ptr = self.as_ptr();
193 ptr::drop_in_place(ptr);
194 ptr.write_bytes(0, 1);
195 }
196
197 unsafe {
198 (*self.root).remove_from_root_stack();
199 }
200 }
201}
202
203impl<'a, const N: usize> From<&RootedGuard<'a, ValueArray<N>>> for JS::HandleValueArray {
204 fn from(array: &RootedGuard<'a, ValueArray<N>>) -> JS::HandleValueArray {
205 JS::HandleValueArray::from(unsafe { &*array.root })
206 }
207}
208
209pub struct Handle<'a, T: 'a> {
210 pub(crate) ptr: NonNull<T>,
211 pub(crate) _phantom: PhantomData<&'a T>,
212}
213
214impl<T> Clone for Handle<'_, T> {
215 fn clone(&self) -> Self {
216 *self
217 }
218}
219
220impl<T> Copy for Handle<'_, T> {}
221
222#[cfg_attr(
223 feature = "crown",
224 crown::unrooted_must_root_lint::allow_unrooted_interior
225)]
226pub struct MutableHandle<'a, T: 'a> {
227 pub(crate) ptr: NonNull<T>,
228 anchor: PhantomData<&'a mut T>,
229}
230
231pub type HandleFunction<'a> = Handle<'a, *mut JSFunction>;
232pub type HandleId<'a> = Handle<'a, jsid>;
233pub type HandleObject<'a> = Handle<'a, *mut JSObject>;
234pub type HandleScript<'a> = Handle<'a, *mut JSScript>;
235pub type HandleString<'a> = Handle<'a, *mut JSString>;
236pub type HandleSymbol<'a> = Handle<'a, *mut Symbol>;
237pub type HandleValue<'a> = Handle<'a, Value>;
238
239pub type MutableHandleFunction<'a> = MutableHandle<'a, *mut JSFunction>;
240pub type MutableHandleId<'a> = MutableHandle<'a, jsid>;
241pub type MutableHandleObject<'a> = MutableHandle<'a, *mut JSObject>;
242pub type MutableHandleScript<'a> = MutableHandle<'a, *mut JSScript>;
243pub type MutableHandleString<'a> = MutableHandle<'a, *mut JSString>;
244pub type MutableHandleSymbol<'a> = MutableHandle<'a, *mut Symbol>;
245pub type MutableHandleValue<'a> = MutableHandle<'a, Value>;
246
247impl<'a, T> Handle<'a, T> {
248 pub fn get(&self) -> T
249 where
250 T: Copy,
251 {
252 unsafe { *self.ptr.as_ptr() }
253 }
254
255 pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
275 where
276 'a: 's,
277 {
278 unsafe { self.ptr.as_ref() }
279 }
280
281 pub unsafe fn from_marked_location(ptr: *const T) -> Self {
282 Handle {
283 ptr: NonNull::new(ptr as *mut T).unwrap(),
284 _phantom: PhantomData,
285 }
286 }
287
288 pub unsafe fn from_raw(handle: RawHandle<T>) -> Self {
289 Handle::from_marked_location(handle.ptr)
290 }
291}
292
293impl<'a, T> IntoRawHandle for Handle<'a, T> {
294 type Target = T;
295 fn into_handle(self) -> RawHandle<T> {
296 unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
297 }
298}
299
300impl<'a, T> IntoRawHandle for MutableHandle<'a, T> {
301 type Target = T;
302 fn into_handle(self) -> RawHandle<T> {
303 unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
304 }
305}
306
307impl<'a, T> IntoRawMutableHandle for MutableHandle<'a, T> {
308 fn into_handle_mut(self) -> RawMutableHandle<T> {
309 unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
310 }
311}
312
313impl<'a, T> Deref for Handle<'a, T> {
314 type Target = T;
315
316 fn deref(&self) -> &T {
319 unsafe { self.ptr.as_ref() }
320 }
321}
322
323impl<'a, T> MutableHandle<'a, T> {
324 pub unsafe fn from_marked_location(ptr: *mut T) -> Self {
325 Self {
326 ptr: NonNull::new(ptr).unwrap(),
327 anchor: PhantomData,
328 }
329 }
330
331 pub unsafe fn from_raw(handle: RawMutableHandle<T>) -> Self {
332 MutableHandle::from_marked_location(handle.ptr)
333 }
334
335 pub fn handle(&self) -> Handle<'a, T> {
336 unsafe { Handle::from_marked_location(self.ptr.as_ptr()) }
338 }
339
340 pub fn get(&self) -> T
341 where
342 T: Copy,
343 {
344 unsafe { *self.ptr.as_ptr() }
345 }
346
347 pub fn set(&mut self, v: T)
348 where
349 T: Copy,
350 {
351 unsafe { *self.ptr.as_mut() = v }
352 }
353
354 pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
373 where
374 'a: 's,
375 {
376 unsafe { self.ptr.as_ref() }
377 }
378
379 pub fn as_mut_ref<'s: 'r, 'cx: 'r, 'r>(&'s mut self, _no_gc: &'cx NoGC) -> &'r mut T
398 where
399 'a: 's,
400 {
401 unsafe { self.ptr.as_mut() }
402 }
403
404 pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
407 where
408 'a: 'b,
409 {
410 self.ptr.as_mut()
411 }
412
413 pub fn reborrow<'b>(&'b mut self) -> MutableHandle<'b, T>
424 where
425 'a: 'b,
426 {
427 MutableHandle {
428 ptr: self.ptr,
429 anchor: PhantomData,
430 }
431 }
432
433 pub(crate) fn raw(&mut self) -> RawMutableHandle<T> {
434 unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
435 }
436}
437
438impl<'a, T> MutableHandle<'a, Option<T>> {
439 pub fn take(&mut self) -> Option<T> {
440 unsafe { self.as_mut().take() }
442 }
443}
444
445impl<'a, T> Deref for MutableHandle<'a, T> {
446 type Target = T;
447
448 fn deref(&self) -> &T {
451 unsafe { self.ptr.as_ref() }
452 }
453}
454
455impl HandleValue<'static> {
456 pub fn null() -> Self {
457 unsafe { Self::from_raw(RawHandleValue::null()) }
458 }
459
460 pub fn undefined() -> Self {
461 unsafe { Self::from_raw(RawHandleValue::undefined()) }
462 }
463}
464
465impl<'a> HandleObject<'a> {
466 pub fn null() -> Self {
467 unsafe { Self::from_raw(RawHandleObject::null()) }
468 }
469}