Skip to main content

script_bindings/
weakref.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
5//! Weak-referenceable JS-managed DOM objects.
6//!
7//! IDL interfaces marked as `weakReferenceable` in `Bindings.conf`
8//! automatically implement the `WeakReferenceable` trait in codegen.
9//! The instance object is responsible for setting `None` in its own
10//! own `WeakBox` when it is collected, through the `DOM_WEAK_SLOT`
11//! slot. When all associated `WeakRef` values are dropped, the
12//! `WeakBox` itself is dropped too.
13
14use std::hash::{Hash, Hasher};
15use std::rc::{Rc, Weak};
16use std::{mem, ptr};
17
18use js::context::NoGC;
19use js::jsapi::JSTracer;
20use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
21
22use crate::JSTraceable;
23use crate::codegen::PrototypeList::proto_id_to_id;
24use crate::conversions::IDLInterface;
25use crate::dom::UnrootedDom;
26use crate::reflector::DomObject;
27use crate::root::DomRoot;
28
29/// A weak reference to a JS-managed DOM object.
30#[derive(Clone)]
31#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
32pub struct WeakRef<T: WeakReferenceable>(Weak<T>);
33
34/// Trait implemented by weak-referenceable interfaces.
35pub trait WeakReferenceable: IDLInterface + DomObject + Sized {
36    /// Downgrade a DOM object reference to a weak one.
37    ///
38    /// Panics if the object is parent type not leaf type
39    fn downgrade(&self) -> WeakRef<Self> {
40        assert_eq!(Self::PROTO_ID, proto_id_to_id(self.reflector().proto_id()));
41        let rc = unsafe { Rc::from_raw(self as *const Self) };
42        let weak = WeakRef(Rc::downgrade(&rc));
43        mem::forget(rc);
44        weak
45    }
46}
47
48impl<T: WeakReferenceable> Eq for WeakRef<T> {}
49
50impl<T: WeakReferenceable> Hash for WeakRef<T> {
51    fn hash<H: Hasher>(&self, state: &mut H) {
52        self.0.as_ptr().hash(state);
53    }
54}
55
56impl<T: WeakReferenceable> WeakRef<T> {
57    /// Create a new weak reference from a `WeakReferenceable` interface instance.
58    /// This is just a convenience wrapper around `<T as WeakReferenceable>::downgrade`
59    /// to not have to import `WeakReferenceable`.
60    pub fn new(value: &T) -> Self {
61        value.downgrade()
62    }
63
64    /// DomRoot a weak reference. Returns `None` if the object was already collected.
65    pub fn root(&self) -> Option<DomRoot<T>> {
66        self.0.upgrade().map(|x| DomRoot::from_ref(&*x))
67    }
68
69    /// Return an [`UnrootedDom`] reference to the data contained in this [`WeakRef`],
70    /// if it is still alive.
71    pub fn unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
72        self.0
73            .upgrade()
74            .map(|value| UnrootedDom::from_ref(&*value, no_gc))
75    }
76
77    /// Return whether the weakly-referenced object is still alive.
78    pub fn is_alive(&self) -> bool {
79        self.0.strong_count() > 0
80    }
81}
82
83impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
84    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
85        0
86    }
87}
88
89impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
90    fn eq(&self, other: &Self) -> bool {
91        self.0.ptr_eq(&other.0)
92    }
93}
94
95impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> {
96    fn eq(&self, other: &T) -> bool {
97        match self.0.upgrade() {
98            Some(ptr) => ptr::eq(Rc::as_ptr(&ptr), other),
99            None => false,
100        }
101    }
102}
103
104unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> {
105    unsafe fn trace(&self, _: *mut JSTracer) {
106        // Do nothing.
107    }
108}