1use super::*;
2use std::sync::*;
3
4/// A type that you can use to declare and implement an event of a specified delegate type.
5///
6/// The implementation is thread-safe and designed to avoid contention between events being
7/// raised and delegates being added or removed.
8pub struct Event<T: ComInterface> {
9 swap: Mutex<()>,
10 change: Mutex<()>,
11 delegates: Array<T>,
12}
13
14impl<T: ComInterface> Default for Event<T> {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl<T: ComInterface> Event<T> {
21 /// Creates a new, empty `Event<T>`.
22 pub fn new() -> Self {
23 Self { delegates: Array::new(), swap: Mutex::default(), change: Mutex::default() }
24 }
25
26 /// Registers a delegate with the event object.
27 pub fn add(&mut self, delegate: &T) -> Result<i64> {
28 let mut _lock_free_drop = Array::new();
29 Ok({
30 let _change_lock = self.change.lock().unwrap();
31 let mut new_delegates = Array::with_capacity(self.delegates.len() + 1)?;
32 for delegate in self.delegates.as_slice() {
33 new_delegates.push(delegate.clone());
34 }
35 let delegate = Delegate::new(delegate)?;
36 let token = delegate.to_token();
37 new_delegates.push(delegate);
38
39 let _swap_lock = self.swap.lock().unwrap();
40 _lock_free_drop = self.delegates.swap(new_delegates);
41 token
42 })
43 }
44
45 /// Revokes a delegate's registration from the event object.
46 pub fn remove(&mut self, token: i64) -> Result<()> {
47 let mut _lock_free_drop = Array::new();
48 {
49 let _change_lock = self.change.lock().unwrap();
50 if self.delegates.is_empty() {
51 return Ok(());
52 }
53 let mut capacity = self.delegates.len() - 1;
54 let mut new_delegates = Array::new();
55 let mut removed = false;
56 if capacity == 0 {
57 removed = self.delegates.as_slice()[0].to_token() == token;
58 } else {
59 new_delegates = Array::with_capacity(capacity)?;
60 for delegate in self.delegates.as_slice() {
61 if !removed && delegate.to_token() == token {
62 removed = true;
63 continue;
64 }
65 if capacity == 0 {
66 break;
67 }
68 new_delegates.push(delegate.clone());
69 capacity -= 1;
70 }
71 }
72 if removed {
73 let _swap_lock = self.swap.lock().unwrap();
74 _lock_free_drop = self.delegates.swap(new_delegates);
75 }
76 }
77 Ok(())
78 }
79
80 /// Clears the event, removing all delegates.
81 pub fn clear(&mut self) {
82 let mut _lock_free_drop = Array::new();
83 {
84 let _change_lock = self.change.lock().unwrap();
85 if self.delegates.is_empty() {
86 return;
87 }
88 let _swap_lock = self.swap.lock().unwrap();
89 _lock_free_drop = self.delegates.swap(Array::new());
90 }
91 }
92
93 /// Invokes all of the event object's registered delegates with the provided callback.
94 pub fn call<F: FnMut(&T) -> Result<()>>(&mut self, mut callback: F) -> Result<()> {
95 let lock_free_calls = {
96 let _swap_lock = self.swap.lock().unwrap();
97 self.delegates.clone()
98 };
99 for delegate in lock_free_calls.as_slice() {
100 if let Err(error) = delegate.call(&mut callback) {
101 const RPC_E_SERVER_UNAVAILABLE: HRESULT = HRESULT(-2147023174); // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
102 if matches!(error.code(), crate::imp::RPC_E_DISCONNECTED | crate::imp::JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE) {
103 self.remove(delegate.to_token())?;
104 }
105 }
106 }
107 Ok(())
108 }
109}
110
111/// A thread-safe reference-counted array of delegates.
112struct Array<T: ComInterface> {
113 buffer: *mut Buffer<T>,
114 len: usize,
115 _phantom: std::marker::PhantomData<T>,
116}
117
118impl<T: ComInterface> Default for Array<T> {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124impl<T: ComInterface> Array<T> {
125 /// Creates a new, empty `Array<T>` with no capacity.
126 fn new() -> Self {
127 Self { buffer: std::ptr::null_mut(), len: 0, _phantom: std::marker::PhantomData }
128 }
129
130 /// Creates a new, empty `Array<T>` with the specified capacity.
131 fn with_capacity(capacity: usize) -> Result<Self> {
132 Ok(Self { buffer: Buffer::new(capacity)?, len: 0, _phantom: std::marker::PhantomData })
133 }
134
135 /// Swaps the contents of two `Array<T>` objects.
136 fn swap(&mut self, mut other: Self) -> Self {
137 unsafe { std::ptr::swap(&mut self.buffer, &mut other.buffer) };
138 std::mem::swap(&mut self.len, &mut other.len);
139 other
140 }
141
142 /// Returns `true` if the array contains no delegates.
143 fn is_empty(&self) -> bool {
144 self.len == 0
145 }
146
147 /// Returns the number of delegates in the array.
148 fn len(&self) -> usize {
149 self.len
150 }
151
152 /// Appends a delegate to the back of the array.
153 fn push(&mut self, delegate: Delegate<T>) {
154 unsafe {
155 std::ptr::write((*self.buffer).as_mut_ptr().add(self.len), delegate);
156 self.len += 1;
157 }
158 }
159
160 /// Returns a slice containing of all delegates.
161 fn as_slice(&self) -> &[Delegate<T>] {
162 if self.is_empty() {
163 &[]
164 } else {
165 unsafe { std::slice::from_raw_parts((*self.buffer).as_ptr(), self.len) }
166 }
167 }
168
169 /// Returns a mutable slice of all delegates.
170 fn as_mut_slice(&mut self) -> &mut [Delegate<T>] {
171 if self.is_empty() {
172 &mut []
173 } else {
174 unsafe { std::slice::from_raw_parts_mut((*self.buffer).as_mut_ptr(), self.len) }
175 }
176 }
177}
178
179impl<T: ComInterface> Clone for Array<T> {
180 fn clone(&self) -> Self {
181 if !self.is_empty() {
182 unsafe { (*self.buffer).0.add_ref() };
183 }
184 Self { buffer: self.buffer, len: self.len, _phantom: std::marker::PhantomData }
185 }
186}
187
188impl<T: ComInterface> Drop for Array<T> {
189 fn drop(&mut self) {
190 unsafe {
191 if !self.is_empty() && (*self.buffer).0.release() == 0 {
192 std::ptr::drop_in_place(self.as_mut_slice());
193 crate::imp::heap_free(self.buffer as _)
194 }
195 }
196 }
197}
198
199/// A reference-counted buffer.
200#[repr(C)]
201struct Buffer<T>(crate::imp::RefCount, std::marker::PhantomData<T>);
202
203impl<T: ComInterface> Buffer<T> {
204 /// Creates a new `Buffer` with the specified size in bytes.
205 fn new(len: usize) -> Result<*mut Self> {
206 if len == 0 {
207 Ok(std::ptr::null_mut())
208 } else {
209 let alloc_size = std::mem::size_of::<Self>() + len * std::mem::size_of::<Delegate<T>>();
210 let header = crate::imp::heap_alloc(alloc_size)? as *mut Self;
211 unsafe {
212 header.write(Self(crate::imp::RefCount::new(1), std::marker::PhantomData));
213 }
214 Ok(header)
215 }
216 }
217
218 /// Returns a raw pointer to the buffer's contents. The resulting pointer might be uninititalized.
219 fn as_ptr(&self) -> *const Delegate<T> {
220 unsafe { (self as *const Self).add(1) as *const _ }
221 }
222
223 /// Returns a raw mutable pointer to the buffer's contents. The resulting pointer might be uninititalized.
224 fn as_mut_ptr(&mut self) -> *mut Delegate<T> {
225 unsafe { (self as *mut Self).add(1) as *mut _ }
226 }
227}
228
229/// Holds either a direct or indirect reference to a delegate. A direct reference is typically
230/// agile while an indirect reference is an agile wrapper.
231#[derive(Clone)]
232enum Delegate<T> {
233 Direct(T),
234 Indirect(AgileReference<T>),
235}
236
237impl<T: ComInterface> Delegate<T> {
238 /// Creates a new `Delegate<T>`, containing a suitable reference to the specified delegate.
239 fn new(delegate: &T) -> Result<Self> {
240 if delegate.cast::<crate::imp::IAgileObject>().is_ok() {
241 Ok(Self::Direct(delegate.clone()))
242 } else {
243 Ok(Self::Indirect(AgileReference::new(delegate)?))
244 }
245 }
246
247 /// Returns an encoded token to identify the delegate.
248 fn to_token(&self) -> i64 {
249 unsafe {
250 match self {
251 Self::Direct(delegate) => crate::imp::EncodePointer(std::mem::transmute_copy(delegate)) as i64,
252 Self::Indirect(delegate) => crate::imp::EncodePointer(std::mem::transmute_copy(delegate)) as i64,
253 }
254 }
255 }
256
257 /// Invokes the delegates with the provided callback.
258 fn call<F: FnMut(&T) -> Result<()>>(&self, mut callback: F) -> Result<()> {
259 match self {
260 Self::Direct(delegate) => callback(delegate),
261 Self::Indirect(delegate) => callback(&delegate.resolve()?),
262 }
263 }
264}
265