breadx_special_events/
lib.rs

1//               Copyright John Nunley, 2022.
2// Distributed under the Boost Software License, Version 1.0.
3//       (See accompanying file LICENSE or copy at
4//         https://www.boost.org/LICENSE_1_0.txt)
5
6//! Implements the "special events" pattern for [`breadx`].
7//!
8//! Some extensions to X11 mandate a pattern known as "special events", where
9//! certain events are sorted into queues for libraries to process. It's only
10//! ever used in a couple of extensions, and checking for them is not idiomatic
11//! to do on the hot path for event processing. Therefore, [`breadx`] does not
12//! do it by default.
13//!
14//! This module provides a way to process special events. The [`SpecialEventDisplay`]
15//! type is a wrapper around a `Display` that provides queues for special events.
16//! Queues can be registered or deregistered, and then polled or waited on, similar
17//! to regular events.
18//!
19//! [`SpecialEventDisplay`] can be created through its universal `From` implementation.
20
21#![no_std]
22
23extern crate alloc;
24
25use alloc::{boxed::Box, collections::VecDeque, sync::Arc, vec::Vec};
26use breadx::{
27    display::{Display, DisplayBase, RawReply, RawRequest},
28    protocol::Event,
29    Result,
30};
31use slab::Slab;
32
33#[cfg(feature = "async")]
34use breadx::display::{AsyncDisplay, AsyncDisplayExt, AsyncStatus, CanBeAsyncDisplay};
35#[cfg(feature = "async")]
36use core::task::Context;
37
38/// A special type of [`Display`] that provides queues for special events.
39///
40/// See the [module level documentation](index.html) for more information.
41///
42/// [`Display`]: breadx::display::Display
43pub struct SpecialEventDisplay<Dpy: ?Sized> {
44    /// Queue for normal events.
45    event_queue: VecDeque<Event>,
46    /// Queues for special events.
47    special_event_queues: Slab<VecDeque<Event>>,
48    /// List of classifiers used to classify the special events.
49    classifiers: Vec<Classifier>,
50    /// The wrapped display.
51    display: Dpy,
52}
53
54struct Classifier {
55    /// The function used to classify the event.
56    classify: Box<dyn FnMut(&Event) -> bool + Send + Sync + 'static>,
57    /// The queue to insert the event into.
58    key: usize,
59}
60
61impl<Dpy> From<Dpy> for SpecialEventDisplay<Dpy> {
62    fn from(display: Dpy) -> Self {
63        Self {
64            event_queue: VecDeque::new(),
65            special_event_queues: Slab::new(),
66            classifiers: Vec::new(),
67            display,
68        }
69    }
70}
71
72impl<Dpy: ?Sized> AsRef<Dpy> for SpecialEventDisplay<Dpy> {
73    fn as_ref(&self) -> &Dpy {
74        &self.display
75    }
76}
77
78impl<Dpy: ?Sized> AsMut<Dpy> for SpecialEventDisplay<Dpy> {
79    fn as_mut(&mut self) -> &mut Dpy {
80        &mut self.display
81    }
82}
83
84impl<Dpy> SpecialEventDisplay<Dpy> {
85    /// Get the inner display type.
86    pub fn into_inner(self) -> Dpy {
87        self.display
88    }
89}
90
91impl<Dpy: ?Sized> SpecialEventDisplay<Dpy> {
92    /// Create a new special event queue with the given classifier.
93    ///
94    /// Returns the key to be used to poll the event queue.
95    pub fn create_special_event_queue(
96        &mut self,
97        classifier: impl FnMut(&Event) -> bool + Send + Sync + 'static,
98    ) -> usize {
99        // create a new queue in the slab
100        let key = self.special_event_queues.insert(VecDeque::new());
101
102        // add the classifier to the list of classifiers
103        self.classifiers.push(Classifier {
104            classify: Box::new(classifier),
105            key,
106        });
107
108        key
109    }
110
111    /// Remove the special event queue with the given key.
112    pub fn remove_special_event_queue(&mut self, key: usize) {
113        // remove the classifier from the list of classifiers
114        self.classifiers.retain(|classifier| classifier.key != key);
115
116        // remove the queue from the slab
117        self.special_event_queues.remove(key);
118    }
119
120    /// Put a given event into the queue it belongs in.
121    fn enqueue_event(&mut self, event: Event) {
122        // check if the event is special
123        for classifier in &mut self.classifiers {
124            if (classifier.classify)(&event) {
125                // put the event into the queue
126                self.special_event_queues[classifier.key].push_back(event);
127                return;
128            }
129        }
130
131        // if it's not special, put it into the normal queue
132        self.event_queue.push_back(event);
133    }
134}
135
136impl<Dpy: DisplayBase + ?Sized> SpecialEventDisplay<Dpy> {
137    /// Poll for an event from the inner display until we find one that we want.
138    fn poll_for_some_event(
139        &mut self,
140        mut until: impl FnMut(&mut Self) -> Option<Event>,
141    ) -> Result<Option<Event>> {
142        loop {
143            if let Some(event) = until(self) {
144                return Ok(Some(event));
145            }
146
147            // poll for event from the inner display
148            let event = match self.display.poll_for_event()? {
149                Some(event) => event,
150                None => return Ok(None),
151            };
152
153            self.enqueue_event(event);
154        }
155    }
156
157    /// Poll for a special event for the given queue.
158    pub fn poll_for_special_event(&mut self, key: usize) -> Result<Option<Event>> {
159        self.poll_for_some_event(|this| this.special_event_queues[key].pop_front())
160    }
161}
162
163impl<Dpy: Display + ?Sized> SpecialEventDisplay<Dpy> {
164    /// Wait for an event from the inner display.
165    fn wait_for_some_event(
166        &mut self,
167        mut until: impl FnMut(&mut Self) -> Option<Event>,
168    ) -> Result<Event> {
169        loop {
170            if let Some(event) = until(self) {
171                return Ok(event);
172            }
173
174            // poll for event from the inner display
175            let event = self.display.wait_for_event()?;
176
177            self.enqueue_event(event);
178        }
179    }
180
181    /// Wait for a special event from the given queue.
182    pub fn wait_for_special_event(&mut self, key: usize) -> Result<Event> {
183        self.wait_for_some_event(|this| this.special_event_queues[key].pop_front())
184    }
185}
186
187#[cfg(feature = "async")]
188impl<Dpy: AsyncDisplay + ?Sized> SpecialEventDisplay<Dpy> {
189    /// Wait for a speical event from the given queue.
190    pub async fn wait_for_special_event_async(&mut self, key: usize) -> Result<Event> {
191        loop {
192            if let Some(event) = self.special_event_queues[key].pop_front() {
193                return Ok(event);
194            }
195
196            let event = self.display.wait_for_event().await?;
197
198            self.enqueue_event(event);
199        }
200    }
201}
202
203impl<D: DisplayBase + ?Sized> DisplayBase for SpecialEventDisplay<D> {
204    fn setup(&self) -> &Arc<breadx::protocol::xproto::Setup> {
205        self.display.setup()
206    }
207
208    fn default_screen_index(&self) -> usize {
209        self.display.default_screen_index()
210    }
211
212    fn poll_for_event(&mut self) -> Result<Option<Event>> {
213        self.poll_for_some_event(|this| this.event_queue.pop_front())
214    }
215
216    fn poll_for_reply_raw(&mut self, seq: u64) -> Result<Option<RawReply>> {
217        self.display.poll_for_reply_raw(seq)
218    }
219}
220
221impl<D: Display + ?Sized> Display for SpecialEventDisplay<D> {
222    fn send_request_raw(&mut self, req: RawRequest<'_, '_>) -> Result<u64> {
223        self.display.send_request_raw(req)
224    }
225
226    fn flush(&mut self) -> Result<()> {
227        self.display.flush()
228    }
229
230    fn generate_xid(&mut self) -> Result<u32> {
231        self.display.generate_xid()
232    }
233
234    fn maximum_request_length(&mut self) -> Result<usize> {
235        self.display.maximum_request_length()
236    }
237
238    fn synchronize(&mut self) -> Result<()> {
239        self.display.synchronize()
240    }
241
242    fn wait_for_reply_raw(&mut self, seq: u64) -> Result<RawReply> {
243        self.display.wait_for_reply_raw(seq)
244    }
245
246    fn wait_for_event(&mut self) -> Result<Event> {
247        self.wait_for_some_event(|this| this.event_queue.pop_front())
248    }
249
250    fn check_for_error(&mut self, seq: u64) -> Result<()> {
251        self.display.check_for_error(seq)
252    }
253}
254
255#[cfg(feature = "async")]
256impl<D: CanBeAsyncDisplay + ?Sized> CanBeAsyncDisplay for SpecialEventDisplay<D> {
257    fn format_request(
258        &mut self,
259        req: &mut RawRequest<'_, '_>,
260        ctx: &mut Context<'_>,
261    ) -> Result<AsyncStatus<u64>> {
262        self.display.format_request(req, ctx)
263    }
264
265    fn try_flush(&mut self, ctx: &mut Context<'_>) -> Result<AsyncStatus<()>> {
266        self.display.try_flush(ctx)
267    }
268
269    fn try_generate_xid(&mut self, ctx: &mut Context<'_>) -> Result<AsyncStatus<u32>> {
270        self.display.try_generate_xid(ctx)
271    }
272
273    fn try_maximum_request_length(&mut self, ctx: &mut Context<'_>) -> Result<AsyncStatus<usize>> {
274        self.display.try_maximum_request_length(ctx)
275    }
276
277    fn try_send_request_raw(
278        &mut self,
279        req: &mut RawRequest<'_, '_>,
280        ctx: &mut Context<'_>,
281    ) -> Result<AsyncStatus<()>> {
282        self.display.try_send_request_raw(req, ctx)
283    }
284
285    fn try_wait_for_event(&mut self, ctx: &mut Context<'_>) -> Result<AsyncStatus<Event>> {
286        loop {
287            let event = match self.display.try_wait_for_event(ctx)? {
288                AsyncStatus::Ready(event) => event,
289                stats => return Ok(stats),
290            };
291
292            self.enqueue_event(event);
293
294            if let Some(event) = self.event_queue.pop_front() {
295                return Ok(AsyncStatus::Ready(event));
296            }
297        }
298    }
299
300    fn try_wait_for_reply_raw(
301        &mut self,
302        seq: u64,
303        ctx: &mut Context<'_>,
304    ) -> Result<AsyncStatus<RawReply>> {
305        self.display.try_wait_for_reply_raw(seq, ctx)
306    }
307
308    fn try_check_for_error(&mut self, seq: u64, ctx: &mut Context<'_>) -> Result<AsyncStatus<()>> {
309        self.display.try_check_for_error(seq, ctx)
310    }
311}
312
313#[cfg(feature = "async")]
314impl<D: AsyncDisplay + ?Sized> AsyncDisplay for SpecialEventDisplay<D> {
315    fn poll_for_interest(
316        &mut self,
317        interest: breadx::display::Interest,
318        callback: &mut dyn FnMut(&mut dyn AsyncDisplay, &mut Context<'_>) -> Result<()>,
319        ctx: &mut Context<'_>,
320    ) -> core::task::Poll<Result<()>> {
321        self.display.poll_for_interest(interest, callback, ctx)
322    }
323}