1use std::{any::Any, sync::mpsc, thread, thread::JoinHandle};
4
5use thiserror::Error;
6
7#[derive(Error, Debug)]
12#[error("sending event on a stopped runloop")]
13pub struct Error;
14
15pub(crate) trait Handle {
17 type Event;
18
19 fn handle(&mut self, event: Self::Event, context: &mut Context);
21
22 #[inline]
24 fn run(self) -> Runloop<Self::Event>
25 where
26 Self: Sized + Send + 'static,
27 Self::Event: Send + 'static,
28 {
29 Runloop::run(self)
30 }
31}
32
33#[derive(Debug)]
35pub(crate) struct Context {
36 is_stopped: bool,
37}
38
39impl Context {
40 #[inline]
41 fn new() -> Self {
42 Self { is_stopped: false }
43 }
44
45 #[inline]
47 pub(crate) fn stop(&mut self) {
48 self.is_stopped = true;
49 }
50
51 #[inline]
53 pub(crate) fn is_stopped(&self) -> bool {
54 self.is_stopped
55 }
56}
57
58pub(crate) struct Runloop<Event> {
59 sender: mpsc::Sender<Event>,
60 thread_handle: JoinHandle<()>,
61}
62
63impl<Event> Runloop<Event>
64where
65 Event: Send + 'static,
66{
67 pub(crate) fn run<H>(mut handler: H) -> Self
69 where
70 H: Handle<Event = Event> + Send + 'static,
71 {
72 let (sender, receiver) = mpsc::channel();
73
74 let thread_handle = thread::spawn(move || {
75 let mut context = Context::new();
76 while !context.is_stopped() && let Ok(event) = receiver.recv() {
77 handler.handle(event, &mut context);
78 }
79 });
80
81 Self { sender, thread_handle }
82 }
83
84 #[inline]
88 pub(crate) fn on(&self, event: Event) -> Result<(), Error> {
89 self.sender.send(event).map_err(|_| Error)
90 }
91
92 #[inline]
97 pub(crate) fn join(self) -> Result<(), Box<dyn Any + Send + 'static>> {
98 self.thread_handle.join()
99 }
100}