Skip to main content

shrub_core/
int_utils.rs

1//! Generic utilities.
2
3use crate::error;
4
5/// Trait for integer types that support parsing from strings with a radix.
6pub trait ParseIntRadix: Sized {
7    /// Parse a string as this integer type using the specified radix.
8    ///
9    /// # Errors
10    ///
11    /// Returns the underlying [`std::num::ParseIntError`] if `s` is empty,
12    /// contains invalid digits for `radix`, or overflows this type.
13    fn from_str_radix(s: &str, radix: u32) -> Result<Self, std::num::ParseIntError>;
14
15    /// Returns the name of the integer type as a static string.
16    fn type_name() -> &'static str;
17}
18
19macro_rules! impl_parse_int_radix {
20    ($t:ty) => {
21        impl ParseIntRadix for $t {
22            fn from_str_radix(s: &str, radix: u32) -> Result<Self, std::num::ParseIntError> {
23                Self::from_str_radix(s, radix)
24            }
25
26            fn type_name() -> &'static str {
27                stringify!($t)
28            }
29        }
30    };
31}
32
33impl_parse_int_radix!(u8);
34impl_parse_int_radix!(u16);
35impl_parse_int_radix!(i32);
36impl_parse_int_radix!(u32);
37impl_parse_int_radix!(usize);
38
39/// Parse the given string as an integer in the specified radix.
40///
41/// # Arguments
42///
43/// * `s` - The string to parse.
44/// * `radix` - The base to use for parsing.
45///
46/// # Type Parameters
47///
48/// * `T` - The integer type to parse. Must implement `ParseIntRadix`.
49///
50/// # Errors
51///
52/// Returns [`crate::error::ErrorKind::IntParseError`] if `s` is not a valid
53/// number in `radix` for the target type, including when it overflows.
54///
55/// # Examples
56///
57/// ```
58/// use shrub_core::int_utils::parse;
59///
60/// let result: u32 = parse("42", 10)?;
61/// assert_eq!(result, 42);
62///
63/// let result: u8 = parse("FF", 16)?;
64/// assert_eq!(result, 255);
65/// # Ok::<(), shrub_core::error::Error>(())
66/// ```
67pub fn parse<T: ParseIntRadix>(s: &str, radix: u32) -> Result<T, error::Error> {
68    T::from_str_radix(s, radix).map_err(|inner| {
69        error::ErrorKind::IntParseError {
70            s: s.to_owned(),
71            int_type_name: T::type_name(),
72            radix,
73            inner,
74        }
75        .into()
76    })
77}