clap_stdin/
maybe_stdin.rs

1use std::str::FromStr;
2
3use super::{Source, StdinError};
4
5/// Wrapper struct to parse arg values from `stdin`
6///
7/// `MaybeStdin` can wrap any type that matches the trait bounds for `Arg`: `FromStr` and `Clone`
8/// ```rust
9/// use std::path::PathBuf;
10/// use clap::Parser;
11/// use clap_stdin::MaybeStdin;
12///
13/// #[derive(Debug, Parser)]
14/// struct Args {
15///     path: MaybeStdin<PathBuf>,
16/// }
17///
18/// if let Ok(args) = Args::try_parse() {
19///     println!("path={}", args.path.display());
20/// }
21/// ```
22///
23/// ```sh
24/// $ pwd | ./example -
25/// /current/working/dir
26/// ```
27#[derive(Clone)]
28pub struct MaybeStdin<T> {
29    inner: T,
30    is_stdin: bool,
31}
32
33impl<T> MaybeStdin<T> {
34    /// Was this value read from stdin
35    pub fn is_stdin(&self) -> bool {
36        self.is_stdin
37    }
38}
39
40impl<T> FromStr for MaybeStdin<T>
41where
42    T: FromStr,
43    <T as FromStr>::Err: std::fmt::Display,
44{
45    type Err = StdinError;
46
47    fn from_str(s: &str) -> Result<Self, Self::Err> {
48        let source = Source::from_str(s)?;
49        let is_stdin = matches!(source, Source::Stdin);
50        T::from_str(source.get_value()?.trim())
51            .map_err(|e| StdinError::FromStr(format!("{e}")))
52            .map(|val| Self {
53                inner: val,
54                is_stdin,
55            })
56    }
57}
58
59impl<T> MaybeStdin<T> {
60    /// Extract the inner value from the wrapper
61    pub fn into_inner(self) -> T {
62        self.inner
63    }
64}
65
66impl<T> std::fmt::Display for MaybeStdin<T>
67where
68    T: std::fmt::Display,
69{
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        self.inner.fmt(f)
72    }
73}
74
75impl<T> std::fmt::Debug for MaybeStdin<T>
76where
77    T: std::fmt::Debug,
78{
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        self.inner.fmt(f)
81    }
82}
83
84impl<T> std::ops::Deref for MaybeStdin<T> {
85    type Target = T;
86
87    fn deref(&self) -> &Self::Target {
88        &self.inner
89    }
90}
91
92impl<T> std::ops::DerefMut for MaybeStdin<T> {
93    fn deref_mut(&mut self) -> &mut Self::Target {
94        &mut self.inner
95    }
96}