Skip to main content

#
typed_derive/
custom.rs

    1use clap::Args;
    2
    3use crate::implicit::BumpLevel;
    4
    5#[derive(Args, Debug)]
    6pub(crate) struct CustomParser {
    7    /// Hand-implement `TypedValueParser`
    8    #[arg(long)]
    9    target_version: Option<TargetVersion>,
    10}
    11
    12/// Enum or custom value
    13#[derive(Clone, Debug)]
    14pub(crate) enum TargetVersion {
    15    Relative(BumpLevel),
    16    Absolute(semver::Version),
    17}
    18
    19impl std::fmt::Display for TargetVersion {
    20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
    21        match self {
    22            TargetVersion::Relative(bump_level) => {
    23                write!(f, "{bump_level}")
    24            }
    25            TargetVersion::Absolute(version) => {
    26                write!(f, "{version}")
    27            }
    28        }
    29    }
    30}
    31
    32impl std::str::FromStr for TargetVersion {
    33    type Err = String;
    34
    35    fn from_str(s: &str) -> Result<Self, Self::Err> {
    36        if let Ok(bump_level) = BumpLevel::from_str(s) {
    37            Ok(TargetVersion::Relative(bump_level))
    38        } else {
    39            Ok(TargetVersion::Absolute(
    40                semver::Version::parse(s).map_err(|e| e.to_string())?,
    41            ))
    42        }
    43    }
    44}
    45
    46/// Default to `TargetVersionParser` for `TargetVersion`, instead of `FromStr`
    47impl clap::builder::ValueParserFactory for TargetVersion {
    48    type Parser = TargetVersionParser;
    49
    50    fn value_parser() -> Self::Parser {
    51        TargetVersionParser
    52    }
    53}
    54
    55#[derive(Copy, Clone)]
    56pub(crate) struct TargetVersionParser;
    57
    58impl clap::builder::TypedValueParser for TargetVersionParser {
    59    type Value = TargetVersion;
    60
    61    fn parse_ref(
    62        &self,
    63        cmd: &clap::Command,
    64        arg: Option<&clap::Arg>,
    65        value: &std::ffi::OsStr,
    66    ) -> Result<Self::Value, clap::Error> {
    67        let inner_parser = <TargetVersion as std::str::FromStr>::from_str;
    68        inner_parser.parse_ref(cmd, arg, value)
    69    }
    70
    71    fn possible_values(
    72        &self,
    73    ) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
    74        let inner_parser = clap::builder::EnumValueParser::<BumpLevel>::new();
    75        #[allow(clippy::needless_collect)] // Erasing a lifetime
    76        inner_parser.possible_values().map(|ps| {
    77            let ps = ps.collect::<Vec<_>>();
    78            let ps: Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_> =
    79                Box::new(ps.into_iter());
    80            ps
    81        })
    82    }
    83}