Skip to main content

miden_debug/
input.rs

1use std::{
2    borrow::Cow,
3    path::{Path, PathBuf},
4};
5
6#[derive(Debug, Clone)]
7pub enum InputFile {
8    Real(PathBuf),
9    Stdin(Box<[u8]>),
10}
11
12impl Default for InputFile {
13    fn default() -> Self {
14        Self::Stdin(Box::from([]))
15    }
16}
17
18impl InputFile {
19    pub fn file_name(&self) -> &str {
20        match self {
21            Self::Real(path) => {
22                path.file_name().and_then(|name| name.to_str()).unwrap_or("<noname>")
23            }
24            Self::Stdin(_) => "<noname>",
25        }
26    }
27
28    pub fn bytes(&self) -> Option<Cow<'_, [u8]>> {
29        match self {
30            Self::Real(path) => std::fs::read(path).ok().map(Cow::Owned),
31            Self::Stdin(bytes) => Some(Cow::Borrowed(bytes)),
32        }
33    }
34
35    /// Get an [InputFile] representing the contents of `path`.
36    ///
37    /// This function returns an error if the contents are not a valid supported file type.
38    #[cfg(feature = "std")]
39    pub fn from_path<P: AsRef<Path>>(path: P) -> Self {
40        let path = path.as_ref();
41        Self::Real(path.to_path_buf())
42    }
43
44    /// Get an [InputFile] representing the contents received from standard input.
45    ///
46    /// This function returns an error if the contents are not a valid supported file type.
47    #[cfg(feature = "std")]
48    pub fn from_stdin() -> Result<Self, std::io::Error> {
49        use std::io::Read;
50
51        let mut input = Vec::with_capacity(1024);
52        std::io::stdin().read_to_end(&mut input)?;
53        Ok(Self::Stdin(input.into_boxed_slice()))
54    }
55}
56
57#[cfg(feature = "std")]
58impl clap::builder::ValueParserFactory for InputFile {
59    type Parser = InputFileParser;
60
61    fn value_parser() -> Self::Parser {
62        InputFileParser
63    }
64}
65
66#[doc(hidden)]
67#[derive(Clone)]
68#[cfg(feature = "std")]
69pub struct InputFileParser;
70
71#[cfg(feature = "std")]
72impl clap::builder::TypedValueParser for InputFileParser {
73    type Value = InputFile;
74
75    fn parse_ref(
76        &self,
77        _cmd: &clap::Command,
78        _arg: Option<&clap::Arg>,
79        value: &std::ffi::OsStr,
80    ) -> Result<Self::Value, clap::error::Error> {
81        use clap::error::{Error, ErrorKind};
82
83        let input_file = match value.to_str() {
84            Some("-") => InputFile::from_stdin().map_err(|err| Error::raw(ErrorKind::Io, err))?,
85            Some(_) | None => InputFile::from_path(PathBuf::from(value)),
86        };
87
88        match &input_file {
89            InputFile::Real(path) => {
90                if !path.exists() {
91                    return Err(Error::raw(
92                        ErrorKind::ValueValidation,
93                        format!("invalid input '{}': file does not exist", path.display()),
94                    ));
95                }
96            }
97            InputFile::Stdin(_) => (),
98        }
99
100        Ok(input_file)
101    }
102}