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
24impl 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 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 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}