Skip to main content

pistonite_cu/parse/
base_impl.rs

1use std::path::PathBuf;
2
3use super::Parse;
4
5macro_rules! blanket_parse_borrowed {
6    () => {
7        fn parse_borrowed(x: &str) -> crate::Result<Self::Output> {
8            Self::parse_owned(x.to_owned())
9        }
10    };
11}
12macro_rules! blanket {
13    ($($t:ty),* $(,)?) => { $(
14        impl Parse for $t {
15            type Output = Self;
16            fn parse_borrowed(x: &str) -> crate::Result<Self> {
17                use crate::Context as _;
18                <Self as std::str::FromStr>::from_str(x).context(concat!("failed to parse ", stringify!($t)))
19            }
20        }
21    )* };
22}
23
24// bool: empty, 0/1, false/true, case-insensitive
25impl Parse for bool {
26    type Output = Self;
27    #[rustfmt::skip]
28    fn parse_borrowed(x: &str) -> crate::Result<Self> {
29        enum S {
30            Empty, Zero, One,
31            T1, T2, T3, True,
32            F1, F2, F3, F4, False,
33            Error,
34        }
35        let mut s = S::Empty;
36        for c in x.trim().as_bytes() {
37            match s {
38                S::Error => break,
39                S::Empty => match *c {
40                    b'0' => s = S::Zero,
41                    b'1' => s = S::One,
42                    b't' | b'T' => s = S::T1,
43                    b'f' | b'F' => s = S::F1,
44                    _ => { s = S::Error; break; }
45                }
46                S::Zero | S::One | S::True | S::False => { s = S::Error; break; }
47                S::T1 => match *c {
48                    b'r' | b'R' => s = S::T2,
49                    _ => { s = S::Error; break; }
50                }
51                S::T2 => match *c {
52                    b'u' | b'U' => s = S::T3,
53                    _ => { s = S::Error; break; }
54                }
55                S::T3 => match *c {
56                    b'e' | b'E' => s = S::True,
57                    _ => { s = S::Error; break; }
58                }
59                S::F1 => match *c {
60                    b'a' | b'A' => s = S::F2,
61                    _ => { s = S::Error; break; }
62                }
63                S::F2 => match *c {
64                    b'l' | b'L' => s = S::F3,
65                    _ => { s = S::Error; break; }
66                }
67                S::F3 => match *c {
68                    b's' | b'S' => s = S::F4,
69                    _ => { s = S::Error; break; }
70                }
71                S::F4 => match *c {
72                    b'e' | b'E' => s = S::False,
73                    _ => { s = S::Error; break; }
74                }
75            }
76        }
77
78        match s {
79            S::Empty | S::Zero | S::False => Ok(false),
80            S::One | S::True => Ok(true),
81            _ => crate::bail!("invalid bool format"),
82        }
83    }
84}
85
86macro_rules! impl_parse_number {
87    ($t:ty, $parse:ident) => {
88        impl Parse for $t {
89            type Output = Self;
90            #[inline(always)]
91            fn parse_borrowed(x: &str) -> crate::Result<Self> {
92                $parse(x)
93            }
94        }
95    };
96}
97impl_parse_number!(i8, parse_i8);
98impl_parse_number!(i16, parse_i16);
99impl_parse_number!(i32, parse_i32);
100impl_parse_number!(i64, parse_i64);
101impl_parse_number!(i128, parse_i128);
102impl_parse_number!(isize, parse_isize);
103impl_parse_number!(u8, parse_u8);
104impl_parse_number!(u16, parse_u16);
105impl_parse_number!(u32, parse_u32);
106impl_parse_number!(u64, parse_u64);
107impl_parse_number!(u128, parse_u128);
108impl_parse_number!(usize, parse_usize);
109blanket!(f32, f64);
110
111macro_rules! parse_unsigned {
112    ($t:ty, $parse:ident) => {
113        fn $parse(x: &str) -> crate::Result<$t> {
114            let x = x.trim();
115            if x.starts_with('-') {
116                crate::bail!("expecting unsigned integer");
117            }
118            // signed - only allow decimal
119            if x.starts_with('+') {
120                return Ok(x.parse::<$t>()?);
121            }
122            if let Some(x2) = x.strip_prefix('0') {
123                if let Some(hex) = x2.strip_prefix(['x', 'X']) {
124                    return Ok(<$t>::from_str_radix(hex, 16)?);
125                }
126                if let Some(oct) = x2.strip_prefix(['o', 'O']) {
127                    return Ok(<$t>::from_str_radix(oct, 8)?);
128                }
129                if let Some(bin) = x2.strip_prefix(['b', 'B']) {
130                    return Ok(<$t>::from_str_radix(bin, 2)?);
131                }
132            }
133            Ok(x.parse::<$t>()?)
134        }
135    };
136    ($t:ty, $parse:ident, $delegate:ident, $delegate_ty:ty) => {
137        fn $parse(x: &str) -> crate::Result<$t> {
138            let x = $delegate(x)?;
139            if x > <$t>::MAX as $delegate_ty {
140                crate::bail!("input out of range: max={}", <$t>::MAX);
141            }
142            Ok(x as $t)
143        }
144    };
145}
146parse_unsigned!(u8, parse_u8, parse_u32, u32);
147parse_unsigned!(u16, parse_u16, parse_u32, u32);
148parse_unsigned!(u32, parse_u32);
149parse_unsigned!(u64, parse_u64);
150parse_unsigned!(u128, parse_u128);
151fn parse_usize(x: &str) -> crate::Result<usize> {
152    #[cfg(target_pointer_width = "64")]
153    {
154        Ok(parse_u64(x)? as usize)
155    }
156    #[cfg(not(target_pointer_width = "64"))]
157    {
158        parse_unsigned!(usize, parse);
159        parse(x)
160    }
161}
162macro_rules! parse_signed {
163    ($t:ty, $parse:ident) => {
164        fn $parse(x: &str) -> crate::Result<$t> {
165            let x = x.trim();
166            // signed - only allow decimal
167            if x.starts_with(['-', '+']) {
168                return Ok(x.parse::<$t>()?);
169            }
170            if let Some(x2) = x.strip_prefix('0') {
171                if let Some(hex) = x2.strip_prefix(['x', 'X']) {
172                    return Ok(<$t>::from_str_radix(hex, 16)?);
173                }
174                if let Some(oct) = x2.strip_prefix(['o', 'O']) {
175                    return Ok(<$t>::from_str_radix(oct, 8)?);
176                }
177                if let Some(bin) = x2.strip_prefix(['b', 'B']) {
178                    return Ok(<$t>::from_str_radix(bin, 2)?);
179                }
180            }
181            Ok(x.parse::<$t>()?)
182        }
183    };
184    ($t:ty, $parse:ident, $delegate:ident, $delegate_ty:ty) => {
185        fn $parse(x: &str) -> crate::Result<$t> {
186            let x = $delegate(x)?;
187            if x > <$t>::MAX as $delegate_ty || x < <$t>::MIN as $delegate_ty {
188                crate::bail!("input out of range: min={}, max={}", <$t>::MIN, <$t>::MAX);
189            }
190            Ok(x as $t)
191        }
192    };
193}
194parse_signed!(i8, parse_i8, parse_i32, i32);
195parse_signed!(i16, parse_i16, parse_i32, i32);
196parse_signed!(i32, parse_i32);
197parse_signed!(i64, parse_i64);
198parse_signed!(i128, parse_i128);
199fn parse_isize(x: &str) -> crate::Result<isize> {
200    #[cfg(target_pointer_width = "64")]
201    {
202        Ok(parse_i64(x)? as isize)
203    }
204    #[cfg(not(target_pointer_width = "64"))]
205    {
206        parse_signed!(isize, parse);
207        parse(x)
208    }
209}
210
211impl Parse for String {
212    type Output = Self;
213    blanket_parse_borrowed!();
214    fn parse_owned(x: String) -> crate::Result<Self> {
215        Ok(x)
216    }
217}
218
219impl Parse for PathBuf {
220    type Output = Self;
221    blanket_parse_borrowed!();
222    fn parse_owned(x: String) -> crate::Result<Self> {
223        Ok(x.into())
224    }
225}