Skip to main content

fpr_cli/
parse.rs

1use crate::com::*;
2
3pub const PFX: &'static str = "--";
4#[derive(Debug)]
5pub struct Key<'a> {
6    pub k: Option<&'a str>,
7    pub v: Vec<&'a str>,
8    pub used: bool,
9}
10#[derive(Debug)]
11pub struct ParsedArgs<'c> {
12    pub k: Vec<Key<'c>>,
13}
14
15impl<'c> ParsedArgs<'c> {
16    pub fn consume(&mut self, name: &str) -> Option<&Vec<&'c str>> {
17        let k = self
18            .k
19            .iter_mut()
20            .find(|k| k.k.map(|k| k == name).unwrap_or(false))?;
21        assert!(
22            !k.used,
23            "A token should not ever be consumed twice. Probably a duplicate argument: {name}"
24        );
25        k.used = true;
26        Some(&k.v)
27    }
28}
29
30impl<'c> ParsedArgs<'c> {
31    pub fn new(args: &[&'c str]) -> Self {
32        let mut last: Option<&str> = None;
33        let r = ParsedArgs {
34            k: args
35                .iter()
36                .map(|a| {
37                    if a.starts_with(PFX) {
38                        last = Some(a);
39                    }
40                    (last, *a)
41                })
42                .into_group_map()
43                .into_iter()
44                .map(|(k, v)| Key {
45                    k,
46                    v: if k.is_some() { v[1..].into() } else { v },
47                    used: false,
48                })
49                .collect(),
50        };
51
52        r
53    }
54}
55
56pub enum Init<C, T: Display> {
57    None,
58    Const(T),
59    Dyn(fn(&C) -> T),
60}
61
62impl<C, T: Display> Init<C, T> {
63    pub fn get(self, c: &C) -> Option<T> {
64        match self {
65            Init::None => None,
66            Init::Const(v) => Some(v),
67            Init::Dyn(f) => Some(f(&c)),
68        }
69    }
70    fn to_string(self, c: &C) -> String {
71        match self.get(c) {
72            Some(s) => format!(" (default: {s})"),
73            None => format!(""),
74        }
75    }
76}
77
78#[derive(Error, Debug)]
79pub enum ErrArg {
80    #[error("Failed while parsing values for '{arg}': {e}")]
81    Val { arg: String, e: ErrVal },
82    #[error("'{arg}' must be one value.")]
83    OnlyOne { arg: String },
84    #[error("'{arg}' is required.")]
85    Required { arg: String },
86    #[error("'{arg}' requires at least one value.")]
87    AtLeastOne { arg: String },
88}
89
90pub trait Parse2<'a, 'b, C>
91where
92    Self: Sized,
93    Self::I: Display,
94{
95    type I;
96    fn parse2(
97        i: Init<C, Self::I>,
98        k: &'static str,
99        c: &C,
100        p: &mut ParsedArgs<'b>,
101    ) -> Result<Self, ErrArg>;
102    fn desc2(i: Init<C, Self::I>, d: &'static str, k: &'static str, c: &C) -> [String; 4];
103    fn default2(c: &C, i: Init<C, Self::I>) -> Self;
104}
105
106impl<'a, 'b, C, T: Parse<'a> + Default> Parse2<'b, 'a, C> for T {
107    type I = T;
108    fn parse2(
109        i: Init<C, Self::I>,
110        k: &'static str,
111        c: &C,
112        p: &mut ParsedArgs<'a>,
113    ) -> Result<Self, ErrArg> {
114        match p.consume(k) {
115            Some(args) => {
116                if args.len() != 1 {
117                    Err(ErrArg::OnlyOne { arg: k.into() })
118                } else {
119                    Ok(T::parse(&args[0]).map_err(|e| ErrArg::Val { arg: k.into(), e })?)
120                }
121            }
122            None => Ok(i.get(c).ok_or(ErrArg::Required { arg: k.into() })?),
123        }
124    }
125
126    fn desc2(i: Init<C, Self>, d: &'static str, k: &'static str, c: &C) -> [String; 4] {
127        [
128            k.into(),
129            format!("Req<{}>", T::desc()),
130            d.into(),
131            i.to_string(c),
132        ]
133    }
134    fn default2(c: &C, i: Init<C, Self::I>) -> Self {
135        i.get(c).unwrap_or(Self::default())
136    }
137}
138
139impl<'a, 'b, Ctx, T: Parse<'a>> Parse2<'b, 'a, Ctx> for Option<T> {
140    type I = T;
141    fn parse2(
142        i: Init<Ctx, T>,
143        k: &'static str,
144        c: &Ctx,
145        p: &mut ParsedArgs<'a>,
146    ) -> Result<Self, ErrArg> {
147        match p.consume(k) {
148            Some(args) => {
149                if args.len() != 1 {
150                    Err(ErrArg::OnlyOne { arg: k.into() })
151                } else {
152                    Ok(Some(
153                        T::parse(&args[0]).map_err(|e| ErrArg::Val { arg: k.into(), e })?,
154                    ))
155                }
156            }
157            None => Ok(match i.get(c) {
158                Some(e) => Some(e),
159                None => None,
160            }),
161        }
162    }
163    fn desc2(i: Init<Ctx, T>, d: &'static str, k: &'static str, c: &Ctx) -> [String; 4] {
164        [
165            k.into(),
166            format!("Opt<{}>", T::desc()),
167            d.into(),
168            i.to_string(c),
169        ]
170    }
171    fn default2(c: &Ctx, i: Init<Ctx, Self::I>) -> Self {
172        match i.get(c) {
173            Some(i) => Some(i),
174            None => None,
175        }
176    }
177}
178
179impl<'a, 'b, Ctx, T: Parse<'a> + Display> Parse2<'b, 'a, Ctx> for Vec<T> {
180    type I = DisplayVec<T>;
181    fn parse2(
182        i: Init<Ctx, Self::I>,
183        k: &'static str,
184        c: &Ctx,
185        p: &mut ParsedArgs<'a>,
186    ) -> Result<Self, ErrArg> {
187        match p.consume(k) {
188            Some(args) => {
189                let args = args
190                    .iter()
191                    .map(|a| T::parse(a).map_err(|e| ErrArg::Val { arg: k.into(), e }))
192                    .process_results(|i| i.collect_vec())?;
193                if args.is_empty() {
194                    Err(ErrArg::OnlyOne { arg: k.into() })?;
195                }
196                Ok(args)
197            }
198            None => Ok(match i.get(c) {
199                Some(e) => e.into(),
200                None => vec![],
201            }),
202        }
203    }
204
205    fn desc2(i: Init<Ctx, Self::I>, d: &'static str, k: &'static str, c: &Ctx) -> [String; 4] {
206        [
207            k.into(),
208            format!("Vec<{}>", T::desc()),
209            d.into(),
210            i.to_string(c),
211        ]
212    }
213    fn default2(c: &Ctx, i: Init<Ctx, Self::I>) -> Self {
214        match i.get(c) {
215            Some(v) => v.0,
216            None => Self::default(),
217        }
218    }
219}
220
221#[derive(Debug)]
222pub struct OptVec<T: Display>(pub Vec<T>);
223impl<T: Display> From<Vec<T>> for OptVec<T> {
224    fn from(v: Vec<T>) -> Self {
225        Self(v)
226    }
227}
228impl<T: Display> From<DisplayVec<T>> for OptVec<T> {
229    fn from(v: DisplayVec<T>) -> Self {
230        Self(v.0)
231    }
232}
233impl<'a, 'b, Ctx, T: Parse<'a>> Parse2<'b, 'a, Ctx> for OptVec<T> {
234    type I = DisplayVec<T>;
235    fn parse2(
236        i: Init<Ctx, Self::I>,
237        k: &'static str,
238        c: &Ctx,
239        p: &mut ParsedArgs<'a>,
240    ) -> Result<Self, ErrArg> {
241        match p.consume(k) {
242            Some(args) => {
243                let args = args
244                    .iter()
245                    .map(|a| T::parse(a).map_err(|e| ErrArg::Val { arg: k.into(), e }))
246                    .process_results(|i| i.collect_vec())?;
247                Ok(args.into())
248            }
249            None => Ok(match i.get(c) {
250                Some(e) => e.into(),
251                None => vec![].into(),
252            }),
253        }
254    }
255
256    fn desc2(i: Init<Ctx, Self::I>, d: &'static str, k: &'static str, c: &Ctx) -> [String; 4] {
257        [
258            k.into(),
259            format!("Vec<{}>", T::desc()),
260            d.into(),
261            i.to_string(c),
262        ]
263    }
264    fn default2(c: &Ctx, i: Init<Ctx, Self::I>) -> Self {
265        Self::from(match i.get(c) {
266            Some(v) => v.0,
267            None => <Vec<T>>::default(),
268        })
269    }
270}
271impl Display for DirExist {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        write!(f, "{}", self.s)
274    }
275}
276impl Display for FileExist {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278        write!(f, "{}", self.s)
279    }
280}