tawasuyu

tawasuyu/mirada

Sovereign tiling Wayland compositor + window manager in Rust, on Llimphi.

Rust 50Markdown 30TOML 211282 Definitions

⎇ main vendor/smithay/src/utils/signaling.rs Rust · 272 lines · 8.9 KB History Who touched what raw

chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0) a91da3fea · Sergio ·

1//! A general purpose signaling mechanism
2//!
3//! This mechanism allows inter-module communication, by letting your modules
4//! register callbacks to listen for events generated by other modules. This
5//! signaling mechanism is synchronous and non-thread safe. If you need
6//! asynchronous thread safe communication, instead consider relying on channels.
7//!
8//! The whole mechanism is built on the [`Signaler`] type.
9//! It serves both as a message sending facility and a way to register new callbacks
10//! for these messages. It can be cloned and passed around between your modules with
11//! `Rc`-like semantics.
12//!
13//! When sending a new signal with [`Signaler::signal`], the provided value `E` will
14//! be made accessible as a reference `&E` to all registered callback.
15//!
16//! Sending a signal or registering a new callback from within a callback is supported.
17//! These will however take effect after the current signal is completely delivered.
18//! Ordering of sent signals and callback registration is preserved.
19
20use std::{
21    any::Any,
22    cell::RefCell,
23    collections::VecDeque,
24    fmt,
25    rc::{Rc, Weak},
26};
27
28/// A signaler, main type for signaling
29#[derive(Debug)]
30pub struct Signaler<S> {
31    inner: Rc<SignalInner<S>>,
32}
33
34// Manual clone impl because of type parameters
35impl<S> Clone for Signaler<S> {
36    fn clone(&self) -> Signaler<S> {
37        Signaler {
38            inner: self.inner.clone(),
39        }
40    }
41}
42
43impl<S> Signaler<S> {
44    /// Create a new signaler for given signal type
45    pub fn new() -> Signaler<S> {
46        Signaler {
47            inner: Rc::new(SignalInner::new()),
48        }
49    }
50
51    /// Register a new callback to this signaler
52    ///
53    /// This method returns a `SignalToken`, which you must keep as long
54    /// as you need your callback to remain in place. Dropping it will
55    /// disable and free your callback. If you don't plan to ever disable
56    /// your callback, see [`SignalToken::leak()`](./struct.SignalToken.html).
57    ///
58    /// If you register a callback from within a callback of the same Signaler,
59    /// the new callback will only be inserted *after* the current signal is
60    /// completely delivered, and thus will not receive it.
61    #[must_use]
62    pub fn register<F: FnMut(&S) + 'static>(&self, f: F) -> SignalToken {
63        let rc = Rc::new(RefCell::new(f));
64        let weak = Rc::downgrade(&rc) as Weak<RefCell<dyn FnMut(&S)>>;
65        self.inner.insert(weak);
66        SignalToken { signal: rc }
67    }
68
69    /// Signal the callbacks
70    ///
71    /// All registered callbacks will be invoked with a reference to the value
72    /// you provide here, after which that value will be dropped.
73    ///
74    /// If this method is invoked from within a callback of the same Signaler,
75    /// its signalling will be delayed until the current signal is completely
76    /// delivered and this method will return immediately.
77    pub fn signal(&self, signal: S) {
78        self.inner.send(signal);
79    }
80}
81
82impl<S> Default for Signaler<S> {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88/// A token associated with a callback registered to a Signaler
89///
90/// Dropping it will disable and drop the callback it is associated to.
91/// If you don't plan to ever disable the callback, you can use the `leak`
92/// method to safely get rid of this value.
93#[derive(Debug)]
94pub struct SignalToken {
95    signal: Rc<dyn Any>,
96}
97
98impl SignalToken {
99    /// Destroy the token without disabling the associated callback
100    pub fn leak(self) {
101        // leak the Rc, so that it is never deallocated
102        let _ = Rc::into_raw(self.signal);
103    }
104}
105
106type WeakCallback<S> = Weak<RefCell<dyn FnMut(&S)>>;
107
108struct SignalInner<S> {
109    callbacks: RefCell<Vec<WeakCallback<S>>>,
110    pending_callbacks: RefCell<Vec<WeakCallback<S>>>,
111    pending_events: RefCell<VecDeque<S>>,
112}
113
114// WeakCallback does not implement debug, so we have to impl Debug manually
115impl<S: fmt::Debug> fmt::Debug for SignalInner<S> {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("SignalInner")
118            .field("callbacks::len()", &self.callbacks.borrow().len())
119            .field("pending_callbacks::len()", &self.pending_callbacks.borrow().len())
120            .field("pending_events", &self.pending_events)
121            .finish()
122    }
123}
124
125impl<S> SignalInner<S> {
126    fn new() -> SignalInner<S> {
127        SignalInner {
128            callbacks: RefCell::new(Vec::new()),
129            pending_callbacks: RefCell::new(Vec::new()),
130            pending_events: RefCell::new(VecDeque::new()),
131        }
132    }
133
134    fn insert(&self, weak: WeakCallback<S>) {
135        // attempt to insert the new callback
136        if let Ok(mut guard) = self.callbacks.try_borrow_mut() {
137            // success, insert it
138            guard.push(weak);
139        } else {
140            // The callback list is already borrowed, this means that this insertion is
141            // done from within a callback.
142            // In that case, insert the callback into the pending list, `send`
143            // will insert it in the callback list when it is finished dispatching
144            // the current event.
145            self.pending_callbacks.borrow_mut().push(weak);
146        }
147    }
148
149    fn send(&self, event: S) {
150        // insert the new event into the pending list
151        self.pending_events.borrow_mut().push_back(event);
152        // now try to dispatch the events from the pending list
153        // new events might be added by other callbacks in the process
154        // so we try to completely drain it before returning
155        //
156        // If we cannot get the guard, that means an other dispatching is
157        // already in progress. It'll empty the pending list, so there is
158        // nothing more we need to do.
159        if let Ok(mut guard) = self.callbacks.try_borrow_mut() {
160            // We cannot just use `while let` because this would keep the
161            // borrow of self.pending_events alive during the whole loop, rather
162            // than just the evaluation of the condition. :/
163            loop {
164                let next_event = self.pending_events.borrow_mut().pop_front();
165                if let Some(event) = next_event {
166                    // Send the message, cleaning up defunct callbacks in the process
167                    guard.retain(|weak| {
168                        if let Some(cb) = Weak::upgrade(weak) {
169                            (*cb.borrow_mut())(&event);
170                            true
171                        } else {
172                            false
173                        }
174                    });
175                    // integrate any pending callbacks resulting from the dispatching
176                    // of this event
177                    guard.extend(self.pending_callbacks.borrow_mut().drain(..));
178                } else {
179                    break;
180                }
181            }
182        }
183    }
184}
185
186/// Trait representing the capability of an object to listen for some signals
187///
188/// It is provided so that the signaling system can play nicely into generic
189/// constructs.
190pub trait Linkable<S> {
191    /// Make this object listen for signals from given signaler
192    fn link(&mut self, signaler: Signaler<S>);
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    use std::{cell::Cell, rc::Rc};
200
201    #[test]
202    fn basic_signal() {
203        let signaler = Signaler::<u32>::new();
204
205        let signaled = Rc::new(Cell::new(false));
206        let signaled2 = signaled.clone();
207
208        let _token = signaler.register(move |_| signaled2.set(true));
209
210        signaler.signal(0);
211
212        assert!(signaled.get());
213    }
214
215    #[test]
216    fn remove_callback() {
217        let signaler = Signaler::<u32>::new();
218
219        let token = signaler.register(|&i| assert_eq!(i, 42));
220
221        signaler.signal(42);
222
223        ::std::mem::drop(token);
224
225        signaler.signal(41);
226
227        let _token = signaler.register(|&i| assert_eq!(i, 39));
228
229        signaler.signal(39);
230    }
231
232    #[test]
233    fn delayed_signal() {
234        let signaler = Signaler::<u32>::new();
235
236        let mut signaled = false;
237        let sign2 = signaler.clone();
238        let _token = signaler.register(move |&i| {
239            if !signaled {
240                sign2.signal(42);
241                signaled = true;
242            } else {
243                assert_eq!(i, 42);
244            }
245        });
246
247        signaler.signal(0);
248    }
249
250    #[test]
251    fn delayed_register() {
252        let signaler = Signaler::<bool>::new();
253
254        let signaled = Rc::new(Cell::new(0u32));
255        let signaled2 = signaled.clone();
256        let sign2 = signaler.clone();
257
258        let _token1 = signaler.register(move |&original| {
259            signaled2.set(signaled2.get() + 1);
260            if original {
261                let signaled3 = signaled2.clone();
262                sign2.register(move |_| signaled3.set(signaled3.get() + 1)).leak();
263                sign2.signal(false);
264            }
265        });
266
267        signaler.signal(true);
268
269        // Two rounds of signals, the first triggers 1 callback, the second triggers 2
270        assert_eq!(signaled.get(), 3);
271    }
272}