process_stream/
item.rs

1use std::{fmt, io, ops::Deref};
2
3/// [`crate::Process`] stream output
4#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
5#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
6pub enum ProcessItem {
7    /// A stdout chunk printed by the process.
8    Output(String),
9    /// A stderr chunk printed by the process or internal error message
10    Error(String),
11    /// Indication that the process exit successful
12    Exit(String),
13}
14
15impl Deref for ProcessItem {
16    type Target = str;
17
18    fn deref(&self) -> &Self::Target {
19        match self {
20            ProcessItem::Output(s) => s,
21            ProcessItem::Error(s) => s,
22            ProcessItem::Exit(s) => s,
23        }
24    }
25}
26
27impl fmt::Display for ProcessItem {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        self.deref().fmt(f)
30    }
31}
32
33impl fmt::Debug for ProcessItem {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        match self {
36            Self::Output(out) => write!(f, "[Output] {out}"),
37            Self::Error(err) => write!(f, "[Error] {err}"),
38            Self::Exit(code) => write!(f, "[Exit] {code}"),
39        }
40    }
41}
42impl From<(bool, io::Result<String>)> for ProcessItem {
43    fn from(v: (bool, io::Result<String>)) -> Self {
44        match v.1 {
45            Ok(line) if v.0 => Self::Output(line),
46            Ok(line) => Self::Error(line),
47            Err(e) => Self::Error(e.to_string()),
48        }
49    }
50}
51
52impl ProcessItem {
53    /// Returns `true` if the process item is [`Output`].
54    ///
55    /// [`Output`]: ProcessItem::Output
56    #[must_use]
57    pub fn is_output(&self) -> bool {
58        matches!(self, Self::Output(..))
59    }
60
61    /// Returns `true` if the process item is [`Error`].
62    ///
63    /// [`Error`]: ProcessItem::Error
64    #[must_use]
65    pub fn is_error(&self) -> bool {
66        matches!(self, Self::Error(..))
67    }
68
69    /// Returns `true` if the process item is [`Exit`].
70    ///
71    /// [`Exit`]: ProcessItem::Exit
72    #[must_use]
73    pub fn is_exit(&self) -> bool {
74        matches!(self, Self::Exit(..))
75    }
76
77    /// Returns Some(`true`) if the process item is [`Exit`] and returned 0
78    ///
79    /// [`Exit`]: ProcessItem::Exit
80    #[must_use]
81    pub fn is_success(&self) -> Option<bool> {
82        self.as_exit().map(|s| s.trim() == "0")
83    }
84
85    /// Return exit code if [`ProcessItem`] is [`ProcessItem::Exit`]
86    pub fn as_exit(&self) -> Option<&String> {
87        if let Self::Exit(v) = self {
88            Some(v)
89        } else {
90            None
91        }
92    }
93
94    /// Return inner reference [`String`] value if [`ProcessItem`] is [`ProcessItem::Error`]
95    pub fn as_error(&self) -> Option<&String> {
96        if let Self::Error(v) = self {
97            Some(v)
98        } else {
99            None
100        }
101    }
102
103    /// Return inner reference [`String`] value if [`ProcessItem`] is [`ProcessItem::Output`]
104    pub fn as_output(&self) -> Option<&String> {
105        if let Self::Output(v) = self {
106            Some(v)
107        } else {
108            None
109        }
110    }
111}