casus/
lib.rs

1//! Casus is a simple library containing a handful of useful generic async primitives. At present, it contains `Event` and `Waiter` primitives.
2//!
3//! ## Event
4//!
5//! The Event primitive allows a future to await the completion of an event. Once the event is completed, all futures trying to await it will immediately return and continue until the event is reset.
6//!
7//! ```rs
8//! use casus::Event;
9//!
10//! let event = Event::new();
11//!
12//! // this will block until Event::set is called elsewhere
13//! event.wait().await;
14//! ```
15//!
16//! ## Waiter
17//!
18//! The Waiter primitive simply waits to be woken up with it's return value.
19//!
20//! ```rs
21//! use casus::Waiter;
22//!
23//! let waiter = Waiter::new();
24//!
25//! // this will block until Event::wake is called elsewhere
26//! waiter.await;
27//! ```
28
29use std::{
30    future::Future,
31    sync::{Arc, Mutex, RwLock},
32    task::{Poll, Waker},
33};
34/// The Event primitive allows a future to await the completion of an event. Once the event is completed, all futures trying to await it will immediately return and continue until the event is reset.
35///
36/// # Example
37///
38/// ```rs
39/// use casus::Event;
40///
41/// let event = Event::new();
42///
43/// // this will block until Event::set is called elsewhere
44/// event.wait().await;
45/// ```
46
47#[derive(Debug)]
48pub struct Event {
49    state: RwLock<bool>,
50    waiters: Mutex<Vec<Waiter<()>>>,
51}
52
53impl Event {
54    /// Creates a new `Event`
55    ///
56    /// # Example
57    /// ```rs
58    /// use casus::Event;
59    ///
60    /// let event = Event::new();
61    /// ```
62    pub fn new() -> Self {
63        Self {
64            state: RwLock::new(false),
65            waiters: Mutex::new(vec![]),
66        }
67    }
68
69    /// Waits for an event to be set
70    ///
71    /// # Example
72    /// ```rs
73    /// // will return when `Event::set` is called
74    /// event.wait().await;
75    /// ```
76    pub async fn wait(&self) -> bool {
77        let state = *self.state.read().unwrap();
78        if !state {
79            let fut = Waiter::new();
80            {
81                let mut waiters = self.waiters.lock().unwrap();
82                waiters.push(fut.clone());
83            }
84            fut.await;
85        }
86        true
87    }
88
89    /// Sets the event and returns all current and future waiters until the event is reset
90    ///
91    /// # Example
92    /// ```rs
93    /// event.set();
94    /// ```
95    pub fn set(&self) {
96        {
97            let mut state = self.state.write().unwrap();
98            *state = true;
99        }
100        for i in self.waiters.lock().unwrap().iter() {
101            i.wake(());
102        }
103    }
104
105    /// Clears the event, allowing waiters to start waiting again until the event is set
106    ///
107    /// # Example
108    /// ```rs
109    /// event.clear();
110    /// ```
111    pub fn clear(&self) {
112        *self.state.write().unwrap() = false;
113    }
114
115    /// Checks if the event is set
116    ///
117    /// # Example
118    /// ```rs
119    /// if !event.is_set() {
120    ///     event.wait().await;
121    /// }
122    pub fn is_set(&self) -> bool {
123        *self.state.read().unwrap()
124    }
125}
126
127impl Default for Event {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132/// The Waiter primitive simply waits to be woken up with it's return value.
133///
134/// # Example
135///
136/// ```rs
137/// use casus::Waiter;
138///
139/// let waiter = Waiter::new();
140///
141/// // this will block until Event::wake is called elsewhere
142/// waiter.await;
143/// ```
144
145#[derive(Clone, Debug)]
146pub struct Waiter<T>(
147    #[allow(clippy::type_complexity)] Arc<Mutex<(bool, Option<Waker>, Option<T>)>>,
148);
149
150impl<T> Waiter<T> {
151    /// Creates a new `Waiter`
152    ///
153    /// # Example
154    /// ```rs
155    /// use casus::Waiter;
156    ///
157    /// let waiter = Waiter::new();
158    /// ```
159    pub fn new() -> Self {
160        Self(Arc::new(Mutex::new((false, None, None))))
161    }
162
163    /// Wakes up the waiter with `T` as the return value, meaning anything awaiting the waiter will return the value T
164    ///
165    /// # Example
166    /// ```
167    /// waiter.wake(T)
168    /// ```
169    pub fn wake(&self, v: T) {
170        let mut state = self.0.lock().unwrap();
171        state.0 = true;
172        state.2 = Some(v);
173        if let Some(waker) = state.1.take() {
174            waker.wake();
175        }
176    }
177}
178
179impl<T> Default for Waiter<T> {
180    fn default() -> Self {
181        Self::new()
182    }
183}
184
185impl<T> Future for Waiter<T> {
186    type Output = T;
187
188    fn poll(
189        self: std::pin::Pin<&mut Self>,
190        cx: &mut std::task::Context<'_>,
191    ) -> std::task::Poll<Self::Output> {
192        let mut state = self.0.lock().unwrap();
193        if state.0 {
194            Poll::Ready(state.2.take().unwrap())
195        } else {
196            state.1 = Some(cx.waker().clone());
197            Poll::Pending
198        }
199    }
200}