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}