Skip to main content

cli_stream/
error.rs

1//! Typed errors for the streaming engine.
2
3/// Why [`Command::stream`](crate::Command::stream) or
4/// [`ProcessHandle::cancel`](crate::ProcessHandle::cancel) failed.
5///
6/// Carries the real underlying [`std::io::Error`] as a source (via
7/// [`std::error::Error::source`]) rather than a pre-formatted string, so a
8/// caller can downcast or inspect the OS error (e.g. distinguish
9/// `NotFound` — the binary isn't on `PATH` — from `PermissionDenied`).
10/// `#[non_exhaustive]` so adding a variant later isn't a breaking change.
11#[derive(Debug, thiserror::Error)]
12#[non_exhaustive]
13pub enum StreamError {
14    /// The child process could not be spawned: the binary isn't on `PATH`,
15    /// isn't executable, or the OS refused. `source` is the spawn `io::Error`
16    /// (commonly `NotFound`).
17    #[error("failed to spawn {program}: {source}")]
18    Spawn {
19        /// The program that failed to launch (as passed to the engine).
20        program: String,
21        /// The OS error from `Command::spawn`.
22        #[source]
23        source: std::io::Error,
24    },
25
26    /// Writing to the child's stdin failed — most often because it has already
27    /// exited, so the pipe is gone. A caller waiting on an answer needs to hear
28    /// this rather than block forever.
29    #[error("writing to the child's stdin failed: {source}")]
30    Write {
31        /// The OS error from the write or flush.
32        #[source]
33        source: std::io::Error,
34    },
35
36    /// The spawned child didn't expose a piped stdout/stderr. Shouldn't
37    /// happen given the engine requests `Stdio::piped()`, but `Child`'s pipe
38    /// accessors return `Option`, so the case is represented rather than
39    /// `unwrap`ped.
40    #[error("child {stream} pipe was not captured")]
41    PipeNotCaptured {
42        /// Which stream was missing — `"stdin"`, `"stdout"` or `"stderr"`.
43        stream: &'static str,
44    },
45
46    /// Cancellation couldn't acquire the child lock because it was poisoned
47    /// (a thread panicked while holding it). The process may still be
48    /// running; the caller can retry or give up.
49    #[error("cancel failed: the child lock was poisoned")]
50    CancelLockPoisoned,
51}