ttycarousel/
sync.rs

1use crate::{carousel::TaskResult, Options};
2use std::fmt;
3use std::io::{self, Write};
4use std::sync::atomic;
5use std::sync::Mutex;
6use std::thread;
7
8lazy_static::lazy_static! {
9    static ref TASK: Mutex<Option<thread::JoinHandle<TaskResult>>> = <_>::default();
10}
11
12static ACTIVE: atomic::AtomicBool = atomic::AtomicBool::new(false);
13
14#[inline]
15fn print_flush(buf: &[u8]) {
16    let mut stdout = io::stdout();
17    let _r = stdout.write_all(buf);
18    let _r = stdout.flush();
19}
20
21#[inline]
22pub fn spawn0(prompt: impl fmt::Display) {
23    spawn(prompt, Options::default());
24}
25
26/// # Panics
27///
28/// Will panic if the mutex is poisoned
29pub fn spawn(prompt: impl fmt::Display, opts: Options) {
30    if ACTIVE.load(atomic::Ordering::SeqCst) {
31        stop();
32    }
33    ACTIVE.store(true, atomic::Ordering::SeqCst);
34    if atty::is(atty::Stream::Stdout) {
35        print_flush(format!("{}  ", prompt).as_bytes());
36        let task = thread::spawn(move || rotate(opts));
37        TASK.lock().unwrap().replace(task);
38    } else {
39        print_flush(format!("{}...  ", prompt).as_bytes());
40        let _r = io::stdout().flush();
41    }
42}
43
44#[inline]
45pub fn stop() {
46    stop_carousel(Some(""));
47}
48
49#[inline]
50pub fn stop_with(res: impl fmt::Display) {
51    stop_carousel(Some(res));
52}
53
54#[inline]
55pub fn stop_clear() {
56    stop_carousel(None::<&str>);
57}
58
59/// # Panics
60///
61/// Will panic if the mutex is poisoned
62pub fn stop_carousel(res: Option<impl fmt::Display>) {
63    ACTIVE.store(false, atomic::Ordering::SeqCst);
64    if let Some(task) = TASK.lock().unwrap().take() {
65        let _r = task.join();
66    }
67    if let Some(s) = res {
68        crate::carousel::cleanup(s);
69    } else {
70        print_flush(crate::carousel::CLREOL);
71    }
72}
73
74fn rotate(opts: Options) -> TaskResult {
75    let mut c = crate::carousel::Carousel::new(opts);
76    let mut stdout = io::stdout();
77    while ACTIVE.load(atomic::Ordering::Relaxed) {
78        stdout.write_all(c.rotate())?;
79        stdout.flush()?;
80        thread::sleep(opts.delay);
81    }
82    Ok(())
83}