Skip to main content

pito_tui/
wake.rs

1use std::io;
2use std::sync::Arc;
3use std::sync::atomic::{AtomicU64, Ordering};
4use std::sync::mpsc::Sender;
5use std::thread::{self, JoinHandle};
6
7use crossterm::event::{self, Event};
8
9use crate::activity::Activity;
10use crate::command::Report;
11
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum Wake<E> {
15    Input(Event),
16    Lost(io::Error),
17    Event(usize, E),
18    Loaded(usize, u64, E),
19    Activity(Activity),
20    Command(usize, Report),
21    Stamped(u64, usize, E),
22    Signal(i32),
23}
24
25pub struct Waker<E> {
26    sender: Sender<Wake<E>>,
27    screen: usize,
28    epoch: Option<Arc<AtomicU64>>,
29}
30
31impl<E> Clone for Waker<E> {
32    fn clone(&self) -> Self {
33        Waker {
34            sender: self.sender.clone(),
35            screen: self.screen,
36            epoch: self.epoch.clone(),
37        }
38    }
39}
40
41impl<E> std::fmt::Debug for Waker<E> {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        f.debug_struct("Waker")
44            .field("screen", &self.screen)
45            .finish_non_exhaustive()
46    }
47}
48
49impl<E: Send + 'static> Waker<E> {
50    pub fn new(sender: Sender<Wake<E>>, screen: usize) -> Self {
51        Waker {
52            sender,
53            screen,
54            epoch: None,
55        }
56    }
57
58    pub(crate) fn epoch(mut self, epoch: Arc<AtomicU64>) -> Self {
59        self.epoch = Some(epoch);
60        self
61    }
62
63    pub fn screen(&self) -> usize {
64        self.screen
65    }
66
67    pub fn send(&self, event: E) -> bool {
68        let wake = match &self.epoch {
69            Some(epoch) => Wake::Stamped(epoch.load(Ordering::SeqCst), self.screen, event),
70            None => Wake::Event(self.screen, event),
71        };
72        self.sender.send(wake).is_ok()
73    }
74}
75
76pub fn listen<E: Send + 'static>(sender: Sender<Wake<E>>) -> JoinHandle<()> {
77    thread::spawn(move || {
78        loop {
79            let read = event::read();
80            let failed = read.is_err();
81            let wake = match read {
82                Ok(input) => Wake::Input(input),
83                Err(error) => Wake::Lost(error),
84            };
85            if sender.send(wake).is_err() || failed {
86                return;
87            }
88        }
89    })
90}