Skip to main content

flood_tide/
macro_util.rs

1//! Utilities for argparse macro.
2
3use crate::Opt;
4use core::cmp::Ordering;
5
6#[cfg(feature = "no_std")]
7use alloc::string::{String, ToString};
8
9pub const fn str_cmp(a: &str, b: &str) -> Ordering {
10    let (a, b) = (a.as_bytes(), b.as_bytes());
11    let mut i = 0;
12    let min_len = if a.len() < b.len() { a.len() } else { b.len() };
13
14    while i < min_len {
15        if a[i] != b[i] {
16            return if a[i] < b[i] {
17                Ordering::Less
18            } else {
19                Ordering::Greater
20            };
21        }
22        i += 1;
23    }
24
25    if a.len() < b.len() {
26        Ordering::Less
27    } else if a.len() > b.len() {
28        Ordering::Greater
29    } else {
30        Ordering::Equal
31    }
32}
33
34pub const fn opt_cmp(a: &Opt, b: &Opt) -> Ordering {
35    match str_cmp(a.lon, b.lon) {
36        Ordering::Less => Ordering::Less,
37        Ordering::Greater => Ordering::Greater,
38        Ordering::Equal => {
39            if a.sho < b.sho {
40                Ordering::Less
41            } else if a.sho > b.sho {
42                Ordering::Greater
43            } else {
44                if a.num < b.num {
45                    Ordering::Less
46                } else if a.num > b.num {
47                    Ordering::Greater
48                } else {
49                    Ordering::Equal
50                }
51            }
52        }
53    }
54}
55
56pub const fn sort_opts<const N: usize>(mut opts: [Opt; N]) -> [Opt; N] {
57    let mut gap = N / 2;
58    while gap > 0 {
59        let mut i = gap;
60        while i < N {
61            let temp = opts[i];
62            let mut j = i;
63            while j >= gap {
64                match opt_cmp(&opts[j - gap], &temp) {
65                    Ordering::Greater => {
66                        opts[j] = opts[j - gap];
67                        j -= gap;
68                    }
69                    _ => break,
70                }
71            }
72            opts[j] = temp;
73            i += 1;
74        }
75        gap /= 2;
76    }
77    opts
78}
79
80pub const fn count_short_opts<const N: usize>(opts: &[Opt; N]) -> usize {
81    let mut i = 0;
82    let mut count = 0;
83    while i < N {
84        if opts[i].sho != 0 {
85            count += 1;
86        }
87        i += 1;
88    }
89    count
90}
91
92pub const fn gen_sho_idx<const N: usize, const M: usize>(opts: &[Opt; N]) -> [(u8, usize); M] {
93    let mut res = [(0, 0); M];
94    let mut i = 0;
95    let mut count = 0;
96    while i < N {
97        if opts[i].sho != 0 {
98            res[count] = (opts[i].sho, i);
99            count += 1;
100        }
101        i += 1;
102    }
103    // sort res by sho (u8)
104    let mut gap = M / 2;
105    while gap > 0 {
106        let mut i = gap;
107        while i < M {
108            let temp = res[i];
109            let mut j = i;
110            while j >= gap {
111                if res[j - gap].0 > temp.0 {
112                    res[j] = res[j - gap];
113                    j -= gap;
114                } else {
115                    break;
116                }
117            }
118            res[j] = temp;
119            i += 1;
120        }
121        gap /= 2;
122    }
123    res
124}
125
126/// Trait for setting field from option value.
127pub trait ArgparseSet {
128    fn argparse_set(&mut self, val: Option<&str>, name: &str) -> Result<(), crate::OptParseError>;
129}
130
131impl ArgparseSet for bool {
132    fn argparse_set(&mut self, _val: Option<&str>, _name: &str) -> Result<(), crate::OptParseError> {
133        *self = true;
134        Ok(())
135    }
136}
137
138impl ArgparseSet for String {
139    fn argparse_set(&mut self, val: Option<&str>, _name: &str) -> Result<(), crate::OptParseError> {
140        if let Some(s) = val {
141            *self = s.to_string();
142        }
143        Ok(())
144    }
145}
146
147impl ArgparseSet for Option<String> {
148    fn argparse_set(&mut self, val: Option<&str>, _name: &str) -> Result<(), crate::OptParseError> {
149        if let Some(s) = val {
150            *self = Some(s.to_string());
151        } else {
152            *self = None;
153        }
154        Ok(())
155    }
156}
157
158macro_rules! impl_argparse_set_parse {
159    ($($t:ty),*) => {
160        $(
161            impl ArgparseSet for $t {
162                fn argparse_set(&mut self, val: Option<&str>, name: &str) -> Result<(), crate::OptParseError> {
163                    if let Some(s) = val {
164                        match s.parse::<$t>() {
165                            Ok(v) => {
166                                *self = v;
167                                Ok(())
168                            }
169                            Err(_) => {
170                                #[cfg(any(feature = "option_argument", feature = "dox"))]
171                                return Err(crate::OptParseError::invalid_option_argument(name, s));
172                                #[cfg(not(any(feature = "option_argument", feature = "dox")))]
173                                return Err(crate::OptParseError::invalid_option(name));
174                            }
175                        }
176                    } else {
177                        Ok(())
178                    }
179                }
180            }
181        )*
182    };
183}
184
185impl_argparse_set_parse!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64, usize, isize);