Compare commits
5 Commits
38ec8158dd
...
a1fd74320b
| Author | SHA1 | Date | |
|---|---|---|---|
| a1fd74320b | |||
| 644b200086 | |||
| 8007922721 | |||
| 8ea6684335 | |||
| a617d21623 |
135
src/mailbox.rs
Normal file
135
src/mailbox.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::{Mutex, MutexGuard},
|
||||||
|
task::{Context, Poll, Waker},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Mailbox<T>(Mutex<MailboxInner<T>>);
|
||||||
|
|
||||||
|
impl<T> Mailbox<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Mailbox(Mutex::new(MailboxInner {
|
||||||
|
waker: None,
|
||||||
|
value: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MailboxInner<T> {
|
||||||
|
waker: Option<Waker>,
|
||||||
|
value: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake<T>(mut mb: MutexGuard<MailboxInner<T>>) {
|
||||||
|
let waker = mb.waker.take();
|
||||||
|
drop(mb);
|
||||||
|
if let Some(waker) = waker {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MailboxPut<'a, T>(&'a Mailbox<T>, Option<T>);
|
||||||
|
impl<'a, T> Unpin for MailboxPut<'a, T> {}
|
||||||
|
impl<'a, T> Future for MailboxPut<'a, T> {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut mb = self.0 .0.lock().unwrap();
|
||||||
|
let None = mb.value else {
|
||||||
|
mb.waker = Some(cx.waker().clone());
|
||||||
|
return Poll::Pending;
|
||||||
|
};
|
||||||
|
mb.value = self.1.take();
|
||||||
|
wake(mb);
|
||||||
|
Poll::Ready(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MailboxGet<'a, T>(&'a Mailbox<T>);
|
||||||
|
impl<'a, T> Future for MailboxGet<'a, T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut mb = self.0 .0.lock().unwrap();
|
||||||
|
let Some(value) = mb.value.take() else {
|
||||||
|
mb.waker = Some(cx.waker().clone());
|
||||||
|
return Poll::Pending;
|
||||||
|
};
|
||||||
|
wake(mb);
|
||||||
|
Poll::Ready(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Mailbox<T> {
|
||||||
|
pub fn put(&self, value: T) -> impl Future<Output = ()> + '_ {
|
||||||
|
MailboxPut(&self, Some(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> impl Future<Output = T> + '_ {
|
||||||
|
MailboxGet(&self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{pin::pin, sync::Arc, task::Wake};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct NoopWaker;
|
||||||
|
impl Wake for NoopWaker {
|
||||||
|
fn wake(self: std::sync::Arc<Self>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ready(f: impl Future) -> bool {
|
||||||
|
let f = pin!(f);
|
||||||
|
matches!(
|
||||||
|
f.poll(&mut Context::from_waker(&Arc::new(NoopWaker).into())),
|
||||||
|
Poll::Ready(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mailbox_empty() {
|
||||||
|
let mb = Mailbox::<i32>::new();
|
||||||
|
assert!(!ready(mb.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mailbox_once() {
|
||||||
|
let mb = Mailbox::<i32>::new();
|
||||||
|
pollster::block_on(mb.put(42));
|
||||||
|
assert_eq!(pollster::block_on(mb.get()), 42);
|
||||||
|
assert!(!ready(mb.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mailbox_once_oor() {
|
||||||
|
let mb = Mailbox::<i32>::new();
|
||||||
|
let f = mb.get();
|
||||||
|
pollster::block_on(mb.put(42));
|
||||||
|
assert_eq!(pollster::block_on(f), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mailbox_twice_no_wait() {
|
||||||
|
let mb = Mailbox::<i32>::new();
|
||||||
|
pollster::block_on(mb.put(42));
|
||||||
|
assert!(!ready(mb.put(13)));
|
||||||
|
assert_eq!(pollster::block_on(mb.get()), 42);
|
||||||
|
assert!(!ready(mb.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mailbox_twice_in_order() {
|
||||||
|
let mb = Mailbox::<i32>::new();
|
||||||
|
let f = mb.get();
|
||||||
|
pollster::block_on(mb.put(42));
|
||||||
|
assert_eq!(pollster::block_on(f), 42);
|
||||||
|
let f = mb.get();
|
||||||
|
pollster::block_on(mb.put(13));
|
||||||
|
assert_eq!(pollster::block_on(f), 13);
|
||||||
|
assert!(!ready(mb.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,8 @@ use winit::{
|
||||||
window::{Window, WindowAttributes},
|
window::{Window, WindowAttributes},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod mailbox;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user