Show More
@@ -0,0 +1,43 b'' | |||||
|
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 | } |
@@ -11,5 +11,6 b'' | |||||
11 |
|
11 | |||
12 | mod config; |
|
12 | mod config; | |
13 | mod layer; |
|
13 | mod layer; | |
|
14 | mod values; | |||
14 | pub use config::{Config, ConfigValueParseError}; |
|
15 | pub use config::{Config, ConfigValueParseError}; | |
15 | pub use layer::{ConfigError, ConfigParseError}; |
|
16 | pub use layer::{ConfigError, ConfigParseError}; |
@@ -8,6 +8,7 b'' | |||||
8 | // GNU General Public License version 2 or any later version. |
|
8 | // GNU General Public License version 2 or any later version. | |
9 |
|
9 | |||
10 | use super::layer; |
|
10 | use super::layer; | |
|
11 | use super::values; | |||
11 | use crate::config::layer::{ |
|
12 | use crate::config::layer::{ | |
12 | ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, |
|
13 | ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, | |
13 | }; |
|
14 | }; | |
@@ -64,40 +65,6 b' pub struct ConfigValueParseError {' | |||||
64 | pub expected_type: &'static str, |
|
65 | pub expected_type: &'static str, | |
65 | } |
|
66 | } | |
66 |
|
67 | |||
67 | pub fn parse_bool(v: &[u8]) -> Option<bool> { |
|
|||
68 | match v.to_ascii_lowercase().as_slice() { |
|
|||
69 | b"1" | b"yes" | b"true" | b"on" | b"always" => Some(true), |
|
|||
70 | b"0" | b"no" | b"false" | b"off" | b"never" => Some(false), |
|
|||
71 | _ => None, |
|
|||
72 | } |
|
|||
73 | } |
|
|||
74 |
|
||||
75 | pub fn parse_byte_size(value: &[u8]) -> Option<u64> { |
|
|||
76 | let value = str::from_utf8(value).ok()?.to_ascii_lowercase(); |
|
|||
77 | const UNITS: &[(&str, u64)] = &[ |
|
|||
78 | ("g", 1 << 30), |
|
|||
79 | ("gb", 1 << 30), |
|
|||
80 | ("m", 1 << 20), |
|
|||
81 | ("mb", 1 << 20), |
|
|||
82 | ("k", 1 << 10), |
|
|||
83 | ("kb", 1 << 10), |
|
|||
84 | ("b", 1 << 0), // Needs to be last |
|
|||
85 | ]; |
|
|||
86 | for &(unit, multiplier) in UNITS { |
|
|||
87 | // TODO: use `value.strip_suffix(unit)` when we require Rust 1.45+ |
|
|||
88 | if value.ends_with(unit) { |
|
|||
89 | let value_before_unit = &value[..value.len() - unit.len()]; |
|
|||
90 | let float: f64 = value_before_unit.trim().parse().ok()?; |
|
|||
91 | if float >= 0.0 { |
|
|||
92 | return Some((float * multiplier as f64).round() as u64); |
|
|||
93 | } else { |
|
|||
94 | return None; |
|
|||
95 | } |
|
|||
96 | } |
|
|||
97 | } |
|
|||
98 | value.parse().ok() |
|
|||
99 | } |
|
|||
100 |
|
||||
101 | impl Config { |
|
68 | impl Config { | |
102 | /// Load system and user configuration from various files. |
|
69 | /// Load system and user configuration from various files. | |
103 | /// |
|
70 | /// | |
@@ -324,7 +291,7 b' impl Config {' | |||||
324 | section: &[u8], |
|
291 | section: &[u8], | |
325 | item: &[u8], |
|
292 | item: &[u8], | |
326 | ) -> Result<Option<u64>, ConfigValueParseError> { |
|
293 | ) -> Result<Option<u64>, ConfigValueParseError> { | |
327 | self.get_parse(section, item, "byte quantity", parse_byte_size) |
|
294 | self.get_parse(section, item, "byte quantity", values::parse_byte_size) | |
328 | } |
|
295 | } | |
329 |
|
296 | |||
330 | /// Returns an `Err` if the first value found is not a valid boolean. |
|
297 | /// Returns an `Err` if the first value found is not a valid boolean. | |
@@ -335,7 +302,7 b' impl Config {' | |||||
335 | section: &[u8], |
|
302 | section: &[u8], | |
336 | item: &[u8], |
|
303 | item: &[u8], | |
337 | ) -> Result<Option<bool>, ConfigValueParseError> { |
|
304 | ) -> Result<Option<bool>, ConfigValueParseError> { | |
338 | self.get_parse(section, item, "boolean", parse_bool) |
|
305 | self.get_parse(section, item, "boolean", values::parse_bool) | |
339 | } |
|
306 | } | |
340 |
|
307 | |||
341 | /// Returns the corresponding boolean in the config. Returns `Ok(false)` |
|
308 | /// Returns the corresponding boolean in the config. Returns `Ok(false)` |
General Comments 0
You need to be logged in to leave comments.
Login now