1use std::borrow::Borrow;
2use std::hash::Hash;
3use std::hash::Hasher;
4use std::marker::PhantomData;
5use std::mem::transmute;
6use std::ops::Deref;
7use std::ptr::NonNull;
8
9use crate::Data;
10use crate::HandleScope;
11use crate::Isolate;
12use crate::IsolateHandle;
13
14extern "C" {
15 fn v8__Local__New(isolate: *mut Isolate, other: *const Data) -> *const Data;
16 fn v8__Global__New(isolate: *mut Isolate, data: *const Data) -> *const Data;
17 fn v8__Global__Reset(data: *const Data);
18}
19
20#[repr(C)]
54#[derive(Debug)]
55pub struct Local<'s, T>(NonNull<T>, PhantomData<&'s ()>);
56
57impl<'s, T> Local<'s, T> {
58 pub fn new(
60 scope: &mut HandleScope<'s, ()>,
61 handle: impl Handle<Data = T>,
62 ) -> Self {
63 let HandleInfo { data, host } = handle.get_handle_info();
64 host.assert_match_isolate(scope);
65 unsafe {
66 scope.cast_local(|sd| {
67 v8__Local__New(sd.get_isolate_ptr(), data.cast().as_ptr()) as *const T
68 })
69 }
70 .unwrap()
71 }
72
73 pub unsafe fn cast<A>(other: Local<'s, A>) -> Self
76 where
77 Local<'s, A>: From<Self>,
78 {
79 transmute(other)
80 }
81
82 pub(crate) unsafe fn from_raw(ptr: *const T) -> Option<Self> {
83 NonNull::new(ptr as *mut _).map(|nn| Self::from_non_null(nn))
84 }
85
86 pub(crate) unsafe fn from_non_null(nn: NonNull<T>) -> Self {
87 Self(nn, PhantomData)
88 }
89
90 pub(crate) fn as_non_null(self) -> NonNull<T> {
91 self.0
92 }
93
94 pub(crate) fn slice_into_raw(slice: &[Self]) -> &[*const T] {
95 unsafe { &*(slice as *const [Self] as *const [*const T]) }
96 }
97}
98
99impl<'s, T> Copy for Local<'s, T> {}
100
101impl<'s, T> Clone for Local<'s, T> {
102 fn clone(&self) -> Self {
103 *self
104 }
105}
106
107impl<'s, T> Deref for Local<'s, T> {
108 type Target = T;
109 fn deref(&self) -> &T {
110 unsafe { self.0.as_ref() }
111 }
112}
113
114#[derive(Debug)]
123pub struct Global<T> {
124 data: NonNull<T>,
125 isolate_handle: IsolateHandle,
126}
127
128impl<T> Global<T> {
129 pub fn new(isolate: &mut Isolate, handle: impl Handle<Data = T>) -> Self {
131 let HandleInfo { data, host } = handle.get_handle_info();
132 host.assert_match_isolate(isolate);
133 unsafe { Self::new_raw(isolate, data) }
134 }
135
136 unsafe fn new_raw(isolate: *mut Isolate, data: NonNull<T>) -> Self {
139 let data = data.cast().as_ptr();
140 let data = v8__Global__New(isolate, data) as *const T;
141 let data = NonNull::new_unchecked(data as *mut _);
142 let isolate_handle = (*isolate).thread_safe_handle();
143 Self {
144 data,
145 isolate_handle,
146 }
147 }
148
149 pub fn open<'a>(&'a self, scope: &mut Isolate) -> &'a T {
150 Handle::open(self, scope)
151 }
152
153 #[deprecated = "use Global::open() instead"]
154 pub fn get<'a>(&'a self, scope: &mut Isolate) -> &'a T {
155 Handle::open(self, scope)
156 }
157}
158
159impl<T> Clone for Global<T> {
160 fn clone(&self) -> Self {
161 let HandleInfo { data, host } = self.get_handle_info();
162 unsafe { Self::new_raw(host.get_isolate().as_mut(), data) }
163 }
164}
165
166impl<T> Drop for Global<T> {
167 fn drop(&mut self) {
168 unsafe {
169 if self.isolate_handle.get_isolate_ptr().is_null() {
170 } else {
173 v8__Global__Reset(self.data.cast().as_ptr())
175 }
176 }
177 }
178}
179
180pub trait Handle: Sized {
181 type Data;
182
183 #[doc(hidden)]
184 fn get_handle_info(&self) -> HandleInfo<Self::Data>;
185
186 fn open<'a>(&'a self, isolate: &mut Isolate) -> &'a Self::Data {
195 let HandleInfo { data, host } = self.get_handle_info();
196 host.assert_match_isolate(isolate);
197 unsafe { &*data.as_ptr() }
198 }
199
200 unsafe fn get_unchecked(&self) -> &Self::Data {
214 let HandleInfo { data, host } = self.get_handle_info();
215 if let HandleHost::DisposedIsolate = host {
216 panic!("attempt to access Handle hosted by disposed Isolate");
217 }
218 &*data.as_ptr()
219 }
220}
221
222impl<'s, T> Handle for Local<'s, T> {
223 type Data = T;
224 fn get_handle_info(&self) -> HandleInfo<T> {
225 HandleInfo::new(self.as_non_null(), HandleHost::Scope)
226 }
227}
228
229impl<'a, 's: 'a, T> Handle for &'a Local<'s, T> {
230 type Data = T;
231 fn get_handle_info(&self) -> HandleInfo<T> {
232 HandleInfo::new(self.as_non_null(), HandleHost::Scope)
233 }
234}
235
236impl<T> Handle for Global<T> {
237 type Data = T;
238 fn get_handle_info(&self) -> HandleInfo<T> {
239 HandleInfo::new(self.data, (&self.isolate_handle).into())
240 }
241}
242
243impl<'a, T> Handle for &'a Global<T> {
244 type Data = T;
245 fn get_handle_info(&self) -> HandleInfo<T> {
246 HandleInfo::new(self.data, (&self.isolate_handle).into())
247 }
248}
249
250impl<'s, T> Borrow<T> for Local<'s, T> {
251 fn borrow(&self) -> &T {
252 &**self
253 }
254}
255
256impl<T> Borrow<T> for Global<T> {
257 fn borrow(&self) -> &T {
258 let HandleInfo { data, host } = self.get_handle_info();
259 if let HandleHost::DisposedIsolate = host {
260 panic!("attempt to access Handle hosted by disposed Isolate");
261 }
262 unsafe { &*data.as_ptr() }
263 }
264}
265
266impl<'s, T> Eq for Local<'s, T> where T: Eq {}
267impl<T> Eq for Global<T> where T: Eq {}
268
269impl<'s, T: Hash> Hash for Local<'s, T> {
270 fn hash<H: Hasher>(&self, state: &mut H) {
271 (&**self).hash(state)
272 }
273}
274
275impl<T: Hash> Hash for Global<T> {
276 fn hash<H: Hasher>(&self, state: &mut H) {
277 unsafe {
278 if self.isolate_handle.get_isolate_ptr().is_null() {
279 panic!("can't hash Global after its host Isolate has been disposed");
280 }
281 self.data.as_ref().hash(state);
282 }
283 }
284}
285
286impl<'s, T, Rhs: Handle> PartialEq<Rhs> for Local<'s, T>
287where
288 T: PartialEq<Rhs::Data>,
289{
290 fn eq(&self, other: &Rhs) -> bool {
291 let i1 = self.get_handle_info();
292 let i2 = other.get_handle_info();
293 i1.host.match_host(i2.host, None)
294 && unsafe { i1.data.as_ref() == i2.data.as_ref() }
295 }
296}
297
298impl<'s, T, Rhs: Handle> PartialEq<Rhs> for Global<T>
299where
300 T: PartialEq<Rhs::Data>,
301{
302 fn eq(&self, other: &Rhs) -> bool {
303 let i1 = self.get_handle_info();
304 let i2 = other.get_handle_info();
305 i1.host.match_host(i2.host, None)
306 && unsafe { i1.data.as_ref() == i2.data.as_ref() }
307 }
308}
309
310#[derive(Copy, Debug, Clone)]
311pub struct HandleInfo<T> {
312 data: NonNull<T>,
313 host: HandleHost,
314}
315
316impl<T> HandleInfo<T> {
317 fn new(data: NonNull<T>, host: HandleHost) -> Self {
318 Self { data, host }
319 }
320}
321
322#[derive(Copy, Debug, Clone)]
323enum HandleHost {
324 Scope,
330 Isolate(NonNull<Isolate>),
331 DisposedIsolate,
332}
333
334impl From<&'_ mut Isolate> for HandleHost {
335 fn from(isolate: &'_ mut Isolate) -> Self {
336 Self::Isolate(NonNull::from(isolate))
337 }
338}
339
340impl From<&'_ IsolateHandle> for HandleHost {
341 fn from(isolate_handle: &IsolateHandle) -> Self {
342 NonNull::new(unsafe { isolate_handle.get_isolate_ptr() })
343 .map(Self::Isolate)
344 .unwrap_or(Self::DisposedIsolate)
345 }
346}
347
348impl HandleHost {
349 fn match_host(
368 self,
369 other: Self,
370 scope_isolate_opt: Option<&mut Isolate>,
371 ) -> bool {
372 let scope_isolate_opt_nn = scope_isolate_opt.map(NonNull::from);
373 match (self, other, scope_isolate_opt_nn) {
374 (Self::Scope, Self::Scope, _) => true,
375 (Self::Isolate(ile1), Self::Isolate(ile2), _) => ile1 == ile2,
376 (Self::Scope, Self::Isolate(ile1), Some(ile2)) => ile1 == ile2,
377 (Self::Isolate(ile1), Self::Scope, Some(ile2)) => ile1 == ile2,
378 (Self::Scope, Self::Isolate(_), _) => true,
383 (Self::Isolate(_), Self::Scope, _) => true,
384 (Self::DisposedIsolate, ..) | (_, Self::DisposedIsolate, _) => {
388 panic!("attempt to access Handle hosted by disposed Isolate")
389 }
390 }
391 }
392
393 fn assert_match_host(self, other: Self, scope_opt: Option<&mut Isolate>) {
394 assert!(
395 self.match_host(other, scope_opt),
396 "attempt to use Handle in an Isolate that is not its host"
397 )
398 }
399
400 fn match_isolate(self, isolate: &mut Isolate) -> bool {
401 self.match_host(isolate.into(), Some(isolate))
402 }
403
404 fn assert_match_isolate(self, isolate: &mut Isolate) {
405 self.assert_match_host(isolate.into(), Some(isolate))
406 }
407
408 fn get_isolate(self) -> NonNull<Isolate> {
409 match self {
410 Self::Scope => panic!("host Isolate for Handle not available"),
411 Self::Isolate(ile) => ile,
412 Self::DisposedIsolate => panic!("attempt to access disposed Isolate"),
413 }
414 }
415
416 fn get_isolate_handle(self) -> IsolateHandle {
417 unsafe { self.get_isolate().as_ref() }.thread_safe_handle()
418 }
419}