ion/class/
reflect.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::any::{Any as _, TypeId};
8use std::ptr;
9
10use mozjs::gc::Traceable;
11use mozjs::jsapi::{Heap, JSObject, JSTracer};
12use mozjs::rust::{Handle, get_object_class};
13
14use crate::class::{NativeClass, PrototypeChain};
15
16pub trait NativeObject: Traceable + Sized + 'static {
17	fn reflector(&self) -> &Reflector;
18}
19
20pub unsafe trait DerivedFrom<T: Castable>: Castable {}
21
22unsafe impl<T: Castable> DerivedFrom<T> for T {}
23
24pub trait Castable: NativeObject {
25	fn is<T>(&self) -> bool
26	where
27		T: NativeObject,
28	{
29		let class = unsafe { get_object_class(self.reflector().get()) };
30		if class.is_null() {
31			return false;
32		}
33
34		unsafe {
35			(*class.cast::<NativeClass>())
36				.prototype_chain
37				.iter()
38				.any(|proto| proto.type_id() == TypeId::of::<T>())
39		}
40	}
41
42	fn upcast<T: Castable>(&self) -> &T
43	where
44		Self: DerivedFrom<T>,
45	{
46		unsafe { &*ptr::from_ref(self).cast::<T>() }
47	}
48
49	fn downcast<T>(&self) -> Option<&T>
50	where
51		T: DerivedFrom<Self> + NativeObject,
52	{
53		self.is::<T>().then(|| unsafe { &*ptr::from_ref(self).cast::<T>() })
54	}
55}
56
57#[derive(Debug, Default)]
58pub struct Reflector(Heap<*mut JSObject>);
59
60impl Reflector {
61	pub fn new() -> Reflector {
62		Reflector::default()
63	}
64
65	pub fn get(&self) -> *mut JSObject {
66		self.0.get()
67	}
68
69	pub fn handle(&self) -> Handle<'_, *mut JSObject> {
70		unsafe { Handle::from_raw(self.0.handle()) }
71	}
72
73	pub(super) fn set(&self, obj: *mut JSObject) {
74		assert!(self.0.get().is_null());
75		assert!(!obj.is_null());
76		self.0.set(obj);
77	}
78
79	#[doc(hidden)]
80	pub const fn __ion_native_prototype_chain() -> PrototypeChain {
81		PrototypeChain::new()
82	}
83}
84
85unsafe impl Traceable for Reflector {
86	unsafe fn trace(&self, trc: *mut JSTracer) {
87		unsafe {
88			self.0.trace(trc);
89		}
90	}
91}
92
93impl NativeObject for Reflector {
94	fn reflector(&self) -> &Reflector {
95		self
96	}
97}
98
99impl Castable for Reflector {}