script_bindings/
reflector.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use js::jsapi::{Heap, JSObject};
6use js::rust::HandleObject;
7use malloc_size_of_derive::MallocSizeOf;
8
9use crate::interfaces::GlobalScopeHelpers;
10use crate::iterable::{Iterable, IterableIterator};
11use crate::realms::InRealm;
12use crate::root::{Dom, DomRoot, Root};
13use crate::script_runtime::{CanGc, JSContext};
14use crate::{DomTypes, JSTraceable};
15
16/// A struct to store a reference to the reflector of a DOM object.
17#[cfg_attr(crown, allow(crown::unrooted_must_root))]
18#[derive(MallocSizeOf)]
19#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
20// If you're renaming or moving this field, update the path in plugins::reflector as well
21pub struct Reflector {
22    #[ignore_malloc_size_of = "defined and measured in rust-mozjs"]
23    object: Heap<*mut JSObject>,
24}
25
26unsafe impl js::gc::Traceable for Reflector {
27    unsafe fn trace(&self, _: *mut js::jsapi::JSTracer) {}
28}
29
30#[cfg_attr(crown, allow(crown::unrooted_must_root))]
31impl PartialEq for Reflector {
32    fn eq(&self, other: &Reflector) -> bool {
33        self.object.get() == other.object.get()
34    }
35}
36
37impl Reflector {
38    /// Get the reflector.
39    #[inline]
40    pub fn get_jsobject(&self) -> HandleObject<'_> {
41        // We're rooted, so it's safe to hand out a handle to object in Heap
42        unsafe { HandleObject::from_raw(self.object.handle()) }
43    }
44
45    /// Initialize the reflector. (May be called only once.)
46    ///
47    /// # Safety
48    ///
49    /// The provided [`JSObject`] pointer must point to a valid [`JSObject`].
50    pub unsafe fn set_jsobject(&self, object: *mut JSObject) {
51        assert!(self.object.get().is_null());
52        assert!(!object.is_null());
53        self.object.set(object);
54    }
55
56    /// Return a pointer to the memory location at which the JS reflector
57    /// object is stored. Used to root the reflector, as
58    /// required by the JSAPI rooting APIs.
59    pub fn rootable(&self) -> &Heap<*mut JSObject> {
60        &self.object
61    }
62
63    /// Create an uninitialized `Reflector`.
64    // These are used by the bindings and do not need `default()` functions.
65    #[allow(clippy::new_without_default)]
66    pub fn new() -> Reflector {
67        Reflector {
68            object: Heap::default(),
69        }
70    }
71}
72
73/// A trait to provide access to the `Reflector` for a DOM object.
74pub trait DomObject: js::gc::Traceable + 'static {
75    /// Returns the receiver's reflector.
76    fn reflector(&self) -> &Reflector;
77}
78
79impl DomObject for Reflector {
80    fn reflector(&self) -> &Self {
81        self
82    }
83}
84
85/// A trait to initialize the `Reflector` for a DOM object.
86pub trait MutDomObject: DomObject {
87    /// Initializes the Reflector
88    ///
89    /// # Safety
90    ///
91    /// The provided [`JSObject`] pointer must point to a valid [`JSObject`].
92    unsafe fn init_reflector(&self, obj: *mut JSObject);
93}
94
95impl MutDomObject for Reflector {
96    unsafe fn init_reflector(&self, obj: *mut JSObject) {
97        self.set_jsobject(obj)
98    }
99}
100
101pub trait DomGlobalGeneric<D: DomTypes>: DomObject {
102    /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in.  If this
103    /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For
104    /// `Node`s it's almost always better to use `NodeTraits::owning_global`.
105    fn global_(&self, realm: InRealm) -> DomRoot<D::GlobalScope>
106    where
107        Self: Sized,
108    {
109        D::GlobalScope::from_reflector(self, realm)
110    }
111}
112
113impl<D: DomTypes, T: DomObject> DomGlobalGeneric<D> for T {}
114
115/// A trait to provide a function pointer to wrap function for DOM objects.
116pub trait DomObjectWrap<D: DomTypes>: Sized + DomObject + DomGlobalGeneric<D> {
117    /// Function pointer to the general wrap function type
118    #[allow(clippy::type_complexity)]
119    const WRAP: unsafe fn(
120        JSContext,
121        &D::GlobalScope,
122        Option<HandleObject>,
123        Box<Self>,
124        CanGc,
125    ) -> Root<Dom<Self>>;
126}
127
128/// A trait to provide a function pointer to wrap function for
129/// DOM iterator interfaces.
130pub trait DomObjectIteratorWrap<D: DomTypes>: DomObjectWrap<D> + JSTraceable + Iterable {
131    /// Function pointer to the wrap function for `IterableIterator<T>`
132    #[allow(clippy::type_complexity)]
133    const ITER_WRAP: unsafe fn(
134        JSContext,
135        &D::GlobalScope,
136        Option<HandleObject>,
137        Box<IterableIterator<D, Self>>,
138        CanGc,
139    ) -> Root<Dom<IterableIterator<D, Self>>>;
140}