ion/root/
local.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use std::fmt;
8use std::fmt::{Debug, Formatter};
9
10use mozjs::gc::{GCMethods, Handle, MutableHandle, RootKind};
11use mozjs::jsapi::{Handle as RawHandle, Heap, MutableHandle as RawMutableHandle, Rooted};
12
13use crate::Context;
14
15/// Represents a local reference managed by the Garbage Collector.
16/// Prevents a local value that is currently being used from being garbage collected and causing undefined behaviour.
17pub enum Local<'local, T: 'local>
18where
19	T: RootKind,
20{
21	Rooted(&'local mut Rooted<T>),
22	Mutable(MutableHandle<'local, T>),
23	Handle(Handle<'local, T>),
24}
25
26impl<'local, T: Copy + RootKind> Local<'local, T> {
27	/// Forms a [Handle] to the [Local] which can be passed to SpiderMonkey APIs.
28	pub fn handle(&self) -> Handle<'local, T> {
29		match self {
30			Self::Rooted(root) => unsafe { Handle::from_marked_location(&raw const root.data) },
31			Self::Mutable(handle) => unsafe { Handle::from_marked_location(&handle.get()) },
32			Self::Handle(handle) => *handle,
33		}
34	}
35
36	/// Forms a [Handle] to the [Local] which can be passed to SpiderMonkey APIs.
37	///
38	/// ### Panics
39	/// Panics when a [`Local::Handle`] is passed.
40	pub fn handle_mut(&mut self) -> MutableHandle<'local, T> {
41		match self {
42			Local::Rooted(root) => unsafe { MutableHandle::from_marked_location(&raw mut root.data) },
43			Local::Mutable(handle) => unsafe { MutableHandle::from_marked_location(handle.as_mut()) },
44			Local::Handle(_) => panic!("&mut Local::Handle should never be constructed"),
45		}
46	}
47
48	pub fn get(&self) -> T {
49		match self {
50			Self::Rooted(root) => root.data,
51			Self::Mutable(handle) => handle.get(),
52			Self::Handle(handle) => handle.get(),
53		}
54	}
55}
56
57impl<'local, T: RootKind> Local<'local, T> {
58	/// Creates a new [Local].
59	/// `Context::root` should be used instead.
60	pub(crate) fn new(cx: &Context, root: &'local mut Rooted<T>) -> Local<'local, T> {
61		unsafe {
62			Rooted::add_to_root_stack(root, cx.as_ptr());
63		}
64		Local::Rooted(root)
65	}
66
67	/// Creates a [Local] from a [Handle].
68	pub fn from_handle(handle: Handle<'local, T>) -> Local<'local, T> {
69		Local::Handle(handle)
70	}
71
72	/// Creates a [Local] from a [MutableHandle].
73	pub fn from_handle_mut(handle: MutableHandle<'local, T>) -> Local<'local, T> {
74		Local::Mutable(handle)
75	}
76
77	/// Creates a [Local] from a marked (pointer).
78	///
79	/// ### Safety
80	/// The pointer must point to a location marked by the Garbage Collector.
81	pub unsafe fn from_marked(ptr: *const T) -> Local<'local, T> {
82		Local::Handle(unsafe { Handle::from_marked_location(ptr) })
83	}
84
85	/// Creates a [Local] from a [raw handle](RawHandle).
86	///
87	/// ### Safety
88	/// The handle must be valid and still be recognised by the Garbage Collector.
89	pub unsafe fn from_raw_handle(handle: RawHandle<T>) -> Local<'local, T> {
90		Local::Handle(unsafe { Handle::from_raw(handle) })
91	}
92
93	/// Creates a [Local] from a marked [mutable pointer](pointer);
94	///
95	/// ### Safety
96	/// The pointer must point to a location marked by the Garbage Collector.
97	pub unsafe fn from_marked_mut(ptr: *mut T) -> Local<'local, T> {
98		Local::Mutable(unsafe { MutableHandle::from_marked_location(ptr) })
99	}
100
101	/// Creates a [Local] from a [raw mutable handle](RawMutableHandle);
102	///
103	/// ### Safety
104	/// The mutable handle must be valid and still be recognised by the Garbage Collector.
105	pub unsafe fn from_raw_handle_mut(handle: RawMutableHandle<T>) -> Local<'local, T> {
106		Local::Mutable(unsafe { MutableHandle::from_raw(handle) })
107	}
108}
109
110impl<'local, T: Copy + GCMethods + RootKind> Local<'local, T> {
111	pub unsafe fn from_heap(heap: &'local Heap<T>) -> Local<'local, T> {
112		unsafe { Local::from_raw_handle(heap.handle()) }
113	}
114}
115
116impl<T: Copy + Debug + RootKind> Debug for Local<'_, T> {
117	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
118		self.handle().fmt(f)
119	}
120}