1use clap::Args;
2
3use crate::implicit::BumpLevel;
4
5#[derive(Args, Debug)]
6pub(crate) struct CustomParser {
7 #[arg(long)]
9 target_version: Option<TargetVersion>,
10}
11
12#[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
46impl 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)] 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}