command_error/
output_conversion_error.rs

1use std::fmt::Debug;
2use std::fmt::Display;
3
4#[cfg(doc)]
5use std::process::Command;
6#[cfg(doc)]
7use std::process::Output;
8
9use crate::CommandDisplay;
10#[cfg(doc)]
11use crate::CommandExt;
12#[cfg(feature = "miette")]
13use miette::Diagnostic;
14#[cfg(doc)]
15use utf8_command::Utf8Output;
16
17/// An error produced when attempting to convert [`Command`] [`Output`] to a custom format (such as
18/// [`Utf8Output`]).
19///
20/// Produced by methods like [`CommandExt::output_checked_with`] and
21/// [`CommandExt::output_checked_utf8`].
22///
23/// ```
24/// # use pretty_assertions::assert_eq;
25/// # use indoc::indoc;
26/// # use std::process::Command;
27/// # use std::process::Output;
28/// # use std::process::ExitStatus;
29/// # use command_error::Utf8ProgramAndArgs;
30/// # use command_error::CommandDisplay;
31/// # use command_error::OutputConversionError;
32/// let mut command = Command::new("sh");
33/// command.args(["-c", "echo puppy doggy"]);
34/// let displayed: Utf8ProgramAndArgs = (&command).into();
35/// let mut output = command.output().unwrap();
36/// output.stdout[5] = 0xc0; // Invalid UTF-8 byte.
37/// let inner: Result<utf8_command::Utf8Output, _> = output.try_into();
38/// let error = OutputConversionError::new(
39///     Box::new(displayed),
40///     Box::new(inner.unwrap_err())
41/// );
42/// assert_eq!(
43///     error.to_string(),
44///     "Failed to convert `sh` output: \
45///     Stdout contained invalid utf-8 sequence of 1 bytes from index 5: \
46///     \"puppy�doggy\\n\""
47/// );
48/// ```
49pub struct OutputConversionError {
50    command: Box<dyn CommandDisplay + Send + Sync>,
51    inner: Box<dyn Display + Send + Sync>,
52}
53
54impl OutputConversionError {
55    /// Construct a new [`OutputConversionError`].
56    pub fn new(
57        command: Box<dyn CommandDisplay + Send + Sync>,
58        inner: Box<dyn Display + Send + Sync>,
59    ) -> Self {
60        Self { command, inner }
61    }
62}
63
64impl Debug for OutputConversionError {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        f.debug_struct("OutputConversionError")
67            .field("program", &self.command.program())
68            .field("inner", &self.inner.to_string())
69            .finish()
70    }
71}
72
73impl Display for OutputConversionError {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        write!(
76            f,
77            "Failed to convert `{}` output: {}",
78            self.command.program_quoted(),
79            self.inner
80        )
81    }
82}
83
84impl std::error::Error for OutputConversionError {}
85
86#[cfg(feature = "miette")]
87impl Diagnostic for OutputConversionError {}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use static_assertions::assert_impl_all;
93
94    assert_impl_all!(OutputConversionError: Send, Sync);
95}