lints

`rustc` lints.
git clone https://git.philomathiclife.com/repos/lints
Log | Files | Refs | README

args.rs (4895B)


      1 use super::{
      2     ExitCode,
      3     io::{self, Write as _},
      4 };
      5 use std::ffi::OsString;
      6 /// Unit tests.
      7 #[cfg(test)]
      8 mod tests;
      9 /// Error from parsing CLI arguments.
     10 #[cfg_attr(test, derive(Debug, PartialEq))]
     11 pub(crate) enum E {
     12     /// No arguments exist including the name of the program which is assumed to be the first argument.
     13     NoArgs,
     14     /// The contained string is not an argument that is supported.
     15     UnknownArg(OsString),
     16 }
     17 impl E {
     18     /// Writes `self` to `stderr`.
     19     pub(crate) fn into_exit_code(self) -> ExitCode {
     20         let mut stderr = io::stderr().lock();
     21         match self {
     22             Self::NoArgs => writeln!(
     23                 stderr,
     24                 "No arguments were passed including the first argument which is assumed to be the name of the program. See lints help for more information."
     25             ),
     26             Self::UnknownArg(arg) => writeln!(
     27                 stderr,
     28                 "Unrecognized argument '{}' was passed. See lints help for more information.",
     29                 arg.display()
     30             ),
     31         }.map_or(ExitCode::FAILURE, |()| ExitCode::FAILURE)
     32     }
     33 }
     34 /// The command passed.
     35 #[cfg_attr(test, derive(Debug, PartialEq))]
     36 #[derive(Clone, Copy)]
     37 pub(crate) enum Cmd {
     38     /// `"allow"` all lints.
     39     Allow(Opts),
     40     /// `"deny"`.
     41     Deny(Opts),
     42     /// `"help"`.
     43     Help,
     44     /// `"version"`.
     45     Version,
     46 }
     47 /// Options to process lints.
     48 #[cfg_attr(test, derive(Debug, PartialEq))]
     49 #[derive(Clone, Copy, Default)]
     50 pub(crate) struct Opts {
     51     /// `--all` was passed.
     52     pub all_lints: bool,
     53     /// `--allow-undefined-lints` was passed.
     54     pub allow_undefined_lints: bool,
     55     /// `-` was passed.
     56     pub read_stdin: bool,
     57 }
     58 impl Opts {
     59     /// Add options from `opts` to `self`.
     60     ///
     61     /// Returns `None` iff successful; otherwise returns the problematic argument.
     62     fn add<I: Iterator<Item = OsString>>(
     63         &mut self,
     64         mut opts: I,
     65         arg: OsString,
     66     ) -> Option<OsString> {
     67         /// `b'-'`.
     68         const DASH: u8 = b'-';
     69         /// `b"--all"`.
     70         const ALL: &[u8] = b"--all".as_slice();
     71         /// `b"--allow-undefined-lints"`.
     72         const ALLOW_UNDEFINED_LINTS: &[u8] = b"--allow-undefined-lints".as_slice();
     73         match arg.as_encoded_bytes() {
     74             &[DASH] => {
     75                 if self.read_stdin {
     76                     Err(())
     77                 } else {
     78                     self.read_stdin = true;
     79                     Ok(())
     80                 }
     81             }
     82             ALL => {
     83                 if self.all_lints || self.read_stdin {
     84                     Err(())
     85                 } else {
     86                     self.all_lints = true;
     87                     Ok(())
     88                 }
     89             }
     90             ALLOW_UNDEFINED_LINTS => {
     91                 if self.allow_undefined_lints || self.read_stdin {
     92                     Err(())
     93                 } else {
     94                     self.allow_undefined_lints = true;
     95                     Ok(())
     96                 }
     97             }
     98             _ => Err(()),
     99         }
    100         .map_or(Some(arg), |()| {
    101             opts.next().and_then(|opt| self.add(opts, opt))
    102         })
    103     }
    104 }
    105 impl Cmd {
    106     /// Parses the CLI arguments.
    107     pub(crate) fn try_from_args<I: IntoIterator<Item = OsString>>(iter: I) -> Result<Self, E> {
    108         let mut args = iter.into_iter();
    109         args.next().ok_or(E::NoArgs).and_then(|_| {
    110             args.next().map_or_else(
    111                 || Ok(Self::Deny(Opts::default())),
    112                 |cmd| match cmd.as_encoded_bytes() {
    113                     b"allow" => args.next().map_or_else(
    114                         || Ok(Self::Allow(Opts::default())),
    115                         |arg| {
    116                             let mut opts = Opts::default();
    117                             opts.add(args, arg)
    118                                 .map_or(Ok(Self::Allow(opts)), |opt| Err(E::UnknownArg(opt)))
    119                         },
    120                     ),
    121                     b"deny" => args.next().map_or_else(
    122                         || Ok(Self::Deny(Opts::default())),
    123                         |arg| {
    124                             let mut opts = Opts::default();
    125                             opts.add(args, arg)
    126                                 .map_or(Ok(Self::Deny(opts)), |opt| Err(E::UnknownArg(opt)))
    127                         },
    128                     ),
    129                     b"help" => args
    130                         .next()
    131                         .map_or(Ok(Self::Help), |opt| Err(E::UnknownArg(opt))),
    132                     b"version" => args
    133                         .next()
    134                         .map_or(Ok(Self::Version), |opt| Err(E::UnknownArg(opt))),
    135                     _ => {
    136                         let mut opts = Opts::default();
    137                         opts.add(args, cmd)
    138                             .map_or(Ok(Self::Deny(opts)), |opt| Err(E::UnknownArg(opt)))
    139                     }
    140                 },
    141             )
    142         })
    143     }
    144 }