|
1 //! Parsing functions for various type of configuration values. |
|
2 //! |
|
3 //! Returning `None` indicates a syntax error. Using a `Result` would be more |
|
4 //! correct but would take more boilerplate for converting between error types, |
|
5 //! compared to using `.ok()` on inner results of various error types to |
|
6 //! convert them all to options. The `Config::get_parse` method later converts |
|
7 //! those options to results with `ConfigValueParseError`, which contains |
|
8 //! details about where the value came from (but omits details of what’s |
|
9 //! invalid inside the value). |
|
10 |
|
11 pub(super) fn parse_bool(v: &[u8]) -> Option<bool> { |
|
12 match v.to_ascii_lowercase().as_slice() { |
|
13 b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true), |
|
14 b"0" | b"no" | b"false" | b"off" | b"never" => Some(false), |
|
15 _ => None, |
|
16 } |
|
17 } |
|
18 |
|
19 pub(super) fn parse_byte_size(value: &[u8]) -> Option<u64> { |
|
20 let value = std::str::from_utf8(value).ok()?.to_ascii_lowercase(); |
|
21 const UNITS: &[(&str, u64)] = &[ |
|
22 ("g", 1 << 30), |
|
23 ("gb", 1 << 30), |
|
24 ("m", 1 << 20), |
|
25 ("mb", 1 << 20), |
|
26 ("k", 1 << 10), |
|
27 ("kb", 1 << 10), |
|
28 ("b", 1 << 0), // Needs to be last |
|
29 ]; |
|
30 for &(unit, multiplier) in UNITS { |
|
31 // TODO: use `value.strip_suffix(unit)` when we require Rust 1.45+ |
|
32 if value.ends_with(unit) { |
|
33 let value_before_unit = &value[..value.len() - unit.len()]; |
|
34 let float: f64 = value_before_unit.trim().parse().ok()?; |
|
35 if float >= 0.0 { |
|
36 return Some((float * multiplier as f64).round() as u64); |
|
37 } else { |
|
38 return None; |
|
39 } |
|
40 } |
|
41 } |
|
42 value.parse().ok() |
|
43 } |