script_bindings/
weakref.rs1use 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::dom::UnrootedDom;
24use crate::reflector::DomObject;
25use crate::root::DomRoot;
26
27#[derive(Clone)]
29#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
30pub struct WeakRef<T: WeakReferenceable>(Weak<T>);
31
32pub trait WeakReferenceable: DomObject + Sized {
34 fn downgrade(&self) -> WeakRef<Self> {
36 let rc = unsafe { Rc::from_raw(self as *const Self) };
37 let weak = WeakRef(Rc::downgrade(&rc));
38 mem::forget(rc);
39 weak
40 }
41}
42
43impl<T: WeakReferenceable> Eq for WeakRef<T> {}
44
45impl<T: WeakReferenceable> Hash for WeakRef<T> {
46 fn hash<H: Hasher>(&self, state: &mut H) {
47 self.0.as_ptr().hash(state);
48 }
49}
50
51impl<T: WeakReferenceable> WeakRef<T> {
52 pub fn new(value: &T) -> Self {
56 value.downgrade()
57 }
58
59 pub fn root(&self) -> Option<DomRoot<T>> {
61 self.0.upgrade().map(|x| DomRoot::from_ref(&*x))
62 }
63
64 pub fn unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
67 self.0
68 .upgrade()
69 .map(|value| UnrootedDom::from_ref(&*value, no_gc))
70 }
71
72 pub fn is_alive(&self) -> bool {
74 self.0.strong_count() > 0
75 }
76}
77
78impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
79 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
80 0
81 }
82}
83
84impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
85 fn eq(&self, other: &Self) -> bool {
86 self.0.ptr_eq(&other.0)
87 }
88}
89
90impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> {
91 fn eq(&self, other: &T) -> bool {
92 match self.0.upgrade() {
93 Some(ptr) => ptr::eq(Rc::as_ptr(&ptr), other),
94 None => false,
95 }
96 }
97}
98
99unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> {
100 unsafe fn trace(&self, _: *mut JSTracer) {
101 }
103}