script_bindings/
weakref.rs1use std::cell::Cell;
15use std::ops::Drop;
16use std::{mem, ptr};
17
18use js::glue::JS_GetReservedSlot;
19use js::jsapi::{JS_SetReservedSlot, JSTracer};
20use js::jsval::{PrivateValue, UndefinedValue};
21use libc::c_void;
22use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
23
24use crate::JSTraceable;
25use crate::reflector::DomObject;
26use crate::root::DomRoot;
27
28pub(crate) const DOM_WEAK_SLOT: u32 = 1;
33
34#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
36pub struct WeakRef<T: WeakReferenceable> {
37 ptr: ptr::NonNull<WeakBox<T>>,
38}
39
40#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
42pub struct WeakBox<T: WeakReferenceable> {
43 pub count: Cell<usize>,
46 pub value: Cell<Option<ptr::NonNull<T>>>,
48}
49
50pub trait WeakReferenceable: DomObject + Sized {
52 fn downgrade(&self) -> WeakRef<Self> {
54 unsafe {
55 let object = self.reflector().get_jsobject().get();
56 let mut slot = UndefinedValue();
57 JS_GetReservedSlot(object, DOM_WEAK_SLOT, &mut slot);
58 let mut ptr = slot.to_private() as *mut WeakBox<Self>;
59 if ptr.is_null() {
60 trace!("Creating new WeakBox holder for {:p}.", self);
61 ptr = Box::into_raw(Box::new(WeakBox {
62 count: Cell::new(1),
63 value: Cell::new(Some(ptr::NonNull::from(self))),
64 }));
65 let val = PrivateValue(ptr as *const c_void);
66 JS_SetReservedSlot(object, DOM_WEAK_SLOT, &val);
67 }
68 let box_ = &*ptr;
69 assert!(box_.value.get().is_some());
70 let new_count = box_.count.get() + 1;
71 trace!(
72 "Incrementing WeakBox refcount for {:p} to {}.",
73 self, new_count
74 );
75 box_.count.set(new_count);
76 WeakRef {
77 ptr: ptr::NonNull::new_unchecked(ptr),
78 }
79 }
80 }
81}
82
83impl<T: WeakReferenceable> WeakRef<T> {
84 pub fn new(value: &T) -> Self {
88 value.downgrade()
89 }
90
91 pub fn root(&self) -> Option<DomRoot<T>> {
93 unsafe { &*self.ptr.as_ptr() }
94 .value
95 .get()
96 .map(|ptr| unsafe { DomRoot::from_ref(&*ptr.as_ptr()) })
97 }
98
99 pub fn is_alive(&self) -> bool {
101 unsafe { &*self.ptr.as_ptr() }.value.get().is_some()
102 }
103}
104
105impl<T: WeakReferenceable> Clone for WeakRef<T> {
106 fn clone(&self) -> WeakRef<T> {
107 unsafe {
108 let box_ = &*self.ptr.as_ptr();
109 let new_count = box_.count.get() + 1;
110 box_.count.set(new_count);
111 WeakRef { ptr: self.ptr }
112 }
113 }
114}
115
116impl<T: WeakReferenceable> MallocSizeOf for WeakRef<T> {
117 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
118 0
119 }
120}
121
122impl<T: WeakReferenceable> PartialEq for WeakRef<T> {
123 fn eq(&self, other: &Self) -> bool {
124 unsafe {
125 (*self.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr) ==
126 (*other.ptr.as_ptr()).value.get().map(ptr::NonNull::as_ptr)
127 }
128 }
129}
130
131impl<T: WeakReferenceable> PartialEq<T> for WeakRef<T> {
132 fn eq(&self, other: &T) -> bool {
133 unsafe {
134 match self.ptr.as_ref().value.get() {
135 Some(ptr) => ptr::eq(ptr.as_ptr(), other),
136 None => false,
137 }
138 }
139 }
140}
141
142unsafe impl<T: WeakReferenceable> JSTraceable for WeakRef<T> {
143 unsafe fn trace(&self, _: *mut JSTracer) {
144 }
146}
147
148impl<T: WeakReferenceable> Drop for WeakRef<T> {
149 fn drop(&mut self) {
150 unsafe {
151 let (count, value) = {
152 let weak_box = &*self.ptr.as_ptr();
153 assert!(weak_box.count.get() > 0);
154 let count = weak_box.count.get() - 1;
155 weak_box.count.set(count);
156 (count, weak_box.value.get())
157 };
158 if count == 0 {
159 assert!(value.is_none());
160 mem::drop(Box::from_raw(self.ptr.as_ptr()));
161 }
162 }
163 }
164}