spinners/utils/
stream.rs

1use std::{io::{Write, stdout, stderr, Result}, time::Instant};
2
3/// Handles the Printing logic for the Spinner
4#[derive(Default, Copy, Clone)]
5pub enum Stream {
6    #[default]
7    Stderr,
8    Stdout,
9}
10impl Stream {
11    /// Matches on self and returns the internal writer
12    fn match_target(&self) -> Box<dyn Write> {
13        match self {
14            Self::Stderr => Box::new(stderr()),
15            Self::Stdout => Box::new(stdout())
16        }
17    }
18
19    /// Writes the message without duration
20    fn print_message(
21            writer: &mut Box<dyn Write>, 
22            frame: &str, 
23            message: &str) -> Result<()>
24    {
25        write!(writer, "\r{} {}", frame, message)?;
26        writer.flush()
27    }
28
29    /// Writes the message with the duration
30    fn print_message_with_duration(
31            writer: &mut Box<dyn Write>, 
32            frame: &str, 
33            message: &str, 
34            start_time: Instant,
35            stop_time: Option<Instant>) -> Result<()> 
36    {
37        let now = stop_time.unwrap_or_else(Instant::now);
38        let duration = now.duration_since(start_time).as_secs_f64();
39        write!(writer, "\r{}{:>10.3} s\t{}", frame, duration, message)?;
40        writer.flush()
41    }
42
43    /// Writes the current message and optionally prints the durations
44    pub fn write(
45            &self,
46            frame: &str, 
47            message: &str, 
48            start_time: Option<Instant>,
49            stop_time: Option<Instant>) -> Result<()>
50    {
51        let mut writer = self.match_target();
52        match start_time {
53            None => Self::print_message(
54                &mut writer, frame, message)?,
55            Some(start_time) => Self::print_message_with_duration(
56                &mut writer, frame, message, start_time, stop_time)?
57        };
58        Ok(())
59    }
60
61    /// Handles the stopping logic given an optional message and symbol
62    pub fn stop(
63            &self,
64            message: Option<&str>,
65            symbol: Option<&str>) -> Result<()> 
66    {
67        let mut writer = self.match_target();
68        match (message, symbol) {
69            // persist with symbol and message
70            (Some(m), Some(s)) => writeln!(writer, "\x1b[2K\r{} {}", s, m),
71
72            // persist with message only
73            (Some(m), None) => writeln!(writer, "\x1b[2K\r{}", m),
74
75            // simple newline
76            _ => writeln!(writer)
77        }?;
78        writer.flush()
79    }
80}