Created
November 9, 2024 08:14
-
-
Save thomcc/2230b4bf4ba0180afe5108406dd84a47 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //! From a library I never finished. I should still make it it's own crate TBH. | |
| macro_rules! parse_env { | |
| ($var_name:literal as $typ:ident) => {{ | |
| const { | |
| match $crate::parse_env::dispatch::$typ(::core::env!($var_name).as_bytes(), ::core::None) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number, or is out of range for `", | |
| ::core::stringify!($typ), | |
| "`.", | |
| )); | |
| } | |
| } | |
| } | |
| }}; | |
| ($var_name:literal as $typ:ident in $range:expr) => {{ | |
| const { | |
| match $crate::parse_env::parse_bounded::$typ( | |
| ::core::env!($var_name).as_bytes(), | |
| ::core::None, | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).start()), | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).end_incl()), | |
| ) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number (`", | |
| ::core::stringify!($typ), | |
| "`), or is out of the range`", | |
| ::core::stringify!($range), | |
| "`." | |
| )); | |
| } | |
| } | |
| } | |
| }}; | |
| ($var_name:literal as $typ:ident else $default:expr) => {{ | |
| const { | |
| const __ENVPARSE_DEFAULT: $typ = $default; | |
| match ::core::option_env!($var_name) { | |
| ::core::None => __ENVPARSE_DEFAULT, | |
| ::core::Some(s) => { | |
| match $crate::parse_env::dispatch::$typ( | |
| s.as_bytes(), | |
| ::core::Some(__ENVPARSE_DEFAULT), | |
| ) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number, or is out of range for `", | |
| ::core::stringify!($typ), | |
| "`." | |
| )); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }}; | |
| ($var_name:literal as $typ:ident (in $range:expr) else $default:expr) => {{ | |
| const { | |
| const __ENVPARSE_DEFAULT: $typ = $default; | |
| match ::core::option_env!($var_name) { | |
| ::core::None => __ENVPARSE_DEFAULT, | |
| ::core::Some(s) => { | |
| match $crate::parse_env::parse_bounded::$typ( | |
| s.as_bytes(), | |
| ::core::Some(__ENVPARSE_DEFAULT), | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).start()), | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).end_incl()), | |
| ) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number (`", | |
| ::core::stringify!($typ), | |
| "`), or is out of the range`", | |
| ::core::stringify!($range), | |
| "`." | |
| )); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }}; | |
| (try $var_name:literal as $typ:ident) => {{ | |
| const { | |
| match ::core::option_env!($var_name) { | |
| ::core::None => ::core::None, | |
| ::core::Some(s) if s.is_empty() => ::core::None, | |
| ::core::Some(s) => { | |
| match $crate::parse_env::dispatch::$typ(s.as_bytes(), ::core::None) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number, or is out of range for `", | |
| ::core::stringify!($typ), | |
| "`." | |
| )); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }}; | |
| (try $var_name:literal as $typ:ident in $range:expr) => {{ | |
| const { | |
| match ::core::option_env!($var_name) { | |
| ::core::None => ::core::None, | |
| ::core::Some(s) if s.is_empty() => ::core::None, | |
| ::core::Some(s) => { | |
| match $crate::parse_env::parse_bounded::$typ( | |
| s.as_bytes(), | |
| ::core::None, | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).start()), | |
| ::core::Some($crate::parse_env::RangeWrap($range, ::core::marker::PhantomData<$typ>).end_incl()), | |
| ) { | |
| ::core::Some(v) => v, | |
| ::core::None => { | |
| ::core::panic!(::core::concat!( | |
| "error: the value in ", | |
| ::core::stringify!($s), | |
| " doesn't parse as a number (`", | |
| ::core::stringify!($typ), | |
| "`), or is out of the range`", | |
| ::core::stringify!($range), | |
| "`.", | |
| )); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }}; | |
| } | |
| pub(crate) use parse_env; | |
| #[derive(Copy, Clone)] | |
| pub(crate) struct RangeWrap<R, T>(pub(crate) R, core::marker::PhantomData<T>); | |
| macro_rules! def_to_inclusive { | |
| ($t:ident, $min:expr) => { | |
| impl RangeWrap<core::ops::Range<$t>, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| self.0.start | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| self.0.end - 1 | |
| } | |
| } | |
| impl RangeWrap<core::ops::RangeFrom<$t>, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| self.0.start | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| $t::MAX | |
| } | |
| } | |
| impl RangeWrap<core::ops::RangeTo<$t>, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| $min | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| self.0.end - 1 | |
| } | |
| } | |
| impl RangeWrap<core::ops::RangeInclusive<$t>, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| *self.0.start() | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| *self.0.end() | |
| } | |
| } | |
| impl RangeWrap<core::ops::RangeToInclusive<$t>, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| $min | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| self.0.end | |
| } | |
| } | |
| impl RangeWrap<core::ops::RangeFull, $t> { | |
| pub(crate) const fn start(&self) -> $t { | |
| $min | |
| } | |
| pub(crate) const fn end_incl(&self) -> $t { | |
| $t::MAX | |
| } | |
| } | |
| }; | |
| } | |
| def_to_inclusive!(u8, 0); | |
| def_to_inclusive!(u16, 0); | |
| def_to_inclusive!(u32, 0); | |
| def_to_inclusive!(u64, 0); | |
| def_to_inclusive!(u128, 0); | |
| def_to_inclusive!(usize, 0); | |
| def_to_inclusive!(i8, i8::MIN); | |
| def_to_inclusive!(i16, i16::MIN); | |
| def_to_inclusive!(i32, i32::MIN); | |
| def_to_inclusive!(i64, i64::MIN); | |
| def_to_inclusive!(i128, i128::MIN); | |
| def_to_inclusive!(isize, isize::MIN); | |
| #[non_exhaustive] | |
| #[derive(Clone, Copy, Debug, PartialEq)] | |
| pub(crate) enum ParseError { | |
| Empty, | |
| UnexpectedSign, | |
| InvalidDigit, | |
| NoDigits, | |
| IntOverflow, | |
| OutOfRange, | |
| UnknownBoolValue, | |
| } | |
| pub(crate) const fn number_parse(s: &[u8], skip_sign: bool) -> Result<(u128, bool), ParseError> { | |
| let (mut pos, end) = match trim_ws(s) { | |
| Some((start, end)) => (start, end), | |
| None => return Err(ParseError::Empty), | |
| }; | |
| let neg = match s[pos] { | |
| b'-' if !skip_sign => return Err(ParseError::UnexpectedSign), | |
| c @ b'-' | c @ b'+' => { | |
| pos += 1; | |
| c == b'-' | |
| } | |
| _ => false, | |
| }; | |
| if pos == end { | |
| return Err(ParseError::NoDigits); | |
| } | |
| let radix = if pos + 2 <= end { | |
| let (radix, len) = match (s[pos], s[pos + 1]) { | |
| (b'0', b'x') | (b'0', b'X') => (16, 2), | |
| (b'0', b'o') | (b'0', b'O') => (8, 2), | |
| (b'0', b'b') | (b'0', b'B') => (2, 2), | |
| _ => (10, 0), | |
| }; | |
| pos += len; | |
| radix | |
| } else { | |
| 10 | |
| }; | |
| let mut accum = 0u128; | |
| let mut ever_saw_digits = false; | |
| while pos < end { | |
| let d = s[pos]; | |
| pos += 1; | |
| let value = match (d, radix) { | |
| (b'0'..=b'1', 2) | (b'0'..=b'7', 8) | (b'0'..=b'9', 10 | 16) => (d - b'0') as u128, | |
| (b'a'..=b'f', 16) => (d - b'a') as u128 + 10, | |
| (b'A'..=b'F', 16) => (d - b'A') as u128 + 10, | |
| (b'_', _) => continue, | |
| _ => return Err(ParseError::InvalidDigit), | |
| }; | |
| ever_saw_digits = true; | |
| match accum.checked_mul(radix) { | |
| None => return Err(ParseError::IntOverflow), | |
| Some(shift) => match shift.checked_add(value) { | |
| None => return Err(ParseError::IntOverflow), | |
| Some(val) => accum = val, | |
| }, | |
| } | |
| } | |
| if ever_saw_digits { | |
| Ok((accum, neg)) | |
| } else { | |
| Err(ParseError::NoDigits) | |
| } | |
| } | |
| const fn trim_ws(s: &[u8]) -> Option<(usize, usize)> { | |
| let mut start = 0; | |
| if s.is_empty() || s.len() <= start { | |
| return None; | |
| } | |
| while start < s.len() && s[start].is_ascii_whitespace() { | |
| start += 1; | |
| } | |
| if start == s.len() { | |
| return None; | |
| } | |
| let mut end = s.len() - 1; | |
| while end > start && s[end].is_ascii_whitespace() { | |
| end -= 1; | |
| } | |
| end += 1; | |
| if end <= start { | |
| None | |
| } else { | |
| Some((start, end)) | |
| } | |
| } | |
| pub(crate) const fn parse_unsigned( | |
| s: &[u8], | |
| incl_min: u128, | |
| incl_max: u128, | |
| clamp: bool, | |
| ) -> Result<u128, ParseError> { | |
| let val = match number_parse(s, false) { | |
| Ok((n, _)) => n, | |
| Err(e) => match e { | |
| ParseError::IntOverflow if clamp => incl_max, | |
| ParseError::UnexpectedSign if clamp => incl_min, | |
| e => return Err(e), | |
| }, | |
| }; | |
| if val < incl_min { | |
| return if clamp { | |
| Ok(incl_min) | |
| } else { | |
| Err(ParseError::OutOfRange) | |
| }; | |
| } | |
| if val > incl_max { | |
| return if clamp { | |
| Ok(incl_max) | |
| } else { | |
| Err(ParseError::OutOfRange) | |
| }; | |
| } | |
| Ok(val) | |
| } | |
| pub(crate) const fn parse_signed( | |
| s: &[u8], | |
| incl_min: i128, | |
| incl_max: i128, | |
| clamp: bool, | |
| ) -> Result<i128, ParseError> { | |
| const I128_MIN_MAGNITUDE: u128 = (i128::MAX as u128) + 1; | |
| let val = match number_parse(s, true) { | |
| Ok((n, true)) if n == I128_MIN_MAGNITUDE => i128::MIN, | |
| Ok((n, true)) if n <= (i128::MAX as u128) => -(n as i128), | |
| Ok((_, true)) if clamp => incl_min, | |
| Ok((n, false)) if n <= (i128::MAX as u128) => n as i128, | |
| Ok((_, false)) if clamp => incl_max, | |
| Ok((_, _)) => return Err(ParseError::OutOfRange), | |
| Err(e) => return Err(e), | |
| }; | |
| if val < incl_min { | |
| return if clamp { | |
| Ok(incl_min) | |
| } else { | |
| Err(ParseError::OutOfRange) | |
| }; | |
| } | |
| if val > incl_max { | |
| return if clamp { | |
| Ok(incl_max) | |
| } else { | |
| Err(ParseError::OutOfRange) | |
| }; | |
| } | |
| Ok(val) | |
| } | |
| pub(crate) const fn parse_bool(s: &[u8]) -> Result<bool, ParseError> { | |
| let (i, e) = match trim_ws(s) { | |
| Some(tup) => tup, | |
| None => return Err(ParseError::Empty), | |
| }; | |
| const fn icase(c: u8) -> u8 { | |
| c.to_ascii_lowercase() | |
| } | |
| let len = e.saturating_sub(i); | |
| match len { | |
| 0 => Err(ParseError::Empty), | |
| 1 => match s[i].to_ascii_lowercase() { | |
| b'1' | b't' | b'y' => Ok(true), | |
| b'0' | b'f' | b'n' => Ok(false), | |
| _ => Err(ParseError::UnknownBoolValue), | |
| }, | |
| 2 => match (icase(s[i]), icase(s[i + 1])) { | |
| (b'n', b'o') => Ok(false), | |
| (b'o', b'n') => Ok(true), | |
| _ => Err(ParseError::UnknownBoolValue), | |
| }, | |
| 3 => match (icase(s[i]), icase(s[i + 1]), icase(s[i + 2])) { | |
| (b'o', b'f', b'f') => Ok(false), | |
| (b'y', b'e', b's') => Ok(true), | |
| _ => Err(ParseError::UnknownBoolValue), | |
| }, | |
| 4 => match ( | |
| icase(s[i]), | |
| icase(s[i + 1]), | |
| icase(s[i + 2]), | |
| icase(s[i + 3]), | |
| ) { | |
| (b't', b'r', b'u', b'e') => Ok(true), | |
| _ => Err(ParseError::UnknownBoolValue), | |
| }, | |
| 5 => match ( | |
| icase(s[i]), | |
| icase(s[i + 1]), | |
| icase(s[i + 2]), | |
| icase(s[i + 3]), | |
| icase(s[i + 4]), | |
| ) { | |
| (b'f', b'a', b'l', b's', b'e') => Ok(false), | |
| _ => Err(ParseError::UnknownBoolValue), | |
| }, | |
| _ => Err(ParseError::UnknownBoolValue), | |
| } | |
| } | |
| macro_rules! unwrap_or { | |
| ($o:expr, $or:expr) => { | |
| match $o { | |
| Some(inner) => inner, | |
| None => $or, | |
| } | |
| }; | |
| } | |
| mod parse_bounded { | |
| use super::{parse_signed, parse_unsigned, ParseError::Empty}; | |
| // unsigned | |
| pub(crate) const fn usize( | |
| s: &[u8], | |
| default: Option<usize>, | |
| min: Option<usize>, | |
| max: Option<usize>, | |
| clamp: bool, | |
| ) -> Option<usize> { | |
| match parse_unsigned( | |
| s, | |
| unwrap_or!(min, 0) as u128, | |
| unwrap_or!(max, usize::MAX) as u128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as usize), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn u8( | |
| s: &[u8], | |
| default: Option<u8>, | |
| min: Option<u8>, | |
| max: Option<u8>, | |
| clamp: bool, | |
| ) -> Option<u8> { | |
| match parse_unsigned( | |
| s, | |
| unwrap_or!(min, 0) as u128, | |
| unwrap_or!(max, u8::MAX) as u128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as u8), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn u16( | |
| s: &[u8], | |
| default: Option<u16>, | |
| min: Option<u16>, | |
| max: Option<u16>, | |
| clamp: bool, | |
| ) -> Option<u16> { | |
| match parse_unsigned( | |
| s, | |
| unwrap_or!(min, 0) as u128, | |
| unwrap_or!(max, u16::MAX) as u128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as u16), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn u32( | |
| s: &[u8], | |
| default: Option<u32>, | |
| min: Option<u32>, | |
| max: Option<u32>, | |
| clamp: bool, | |
| ) -> Option<u32> { | |
| match parse_unsigned( | |
| s, | |
| unwrap_or!(min, 0) as u128, | |
| unwrap_or!(max, u32::MAX) as u128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as u32), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn u64( | |
| s: &[u8], | |
| default: Option<u64>, | |
| min: Option<u64>, | |
| max: Option<u64>, | |
| clamp: bool, | |
| ) -> Option<u64> { | |
| match parse_unsigned( | |
| s, | |
| unwrap_or!(min, 0) as u128, | |
| unwrap_or!(max, u64::MAX) as u128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as u64), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn u128( | |
| s: &[u8], | |
| default: Option<u128>, | |
| min: Option<u128>, | |
| max: Option<u128>, | |
| clamp: bool, | |
| ) -> Option<u128> { | |
| match parse_unsigned(s, unwrap_or!(min, 0), unwrap_or!(max, u128::MAX), clamp) { | |
| Ok(v) => Some(v), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| // signed | |
| pub(crate) const fn isize( | |
| s: &[u8], | |
| default: Option<isize>, | |
| min: Option<isize>, | |
| max: Option<isize>, | |
| clamp: bool, | |
| ) -> Option<isize> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, isize::MIN) as i128, | |
| unwrap_or!(max, isize::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as isize), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn i8( | |
| s: &[u8], | |
| default: Option<i8>, | |
| min: Option<i8>, | |
| max: Option<i8>, | |
| clamp: bool, | |
| ) -> Option<i8> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, i8::MIN) as i128, | |
| unwrap_or!(max, i8::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as i8), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn i16( | |
| s: &[u8], | |
| default: Option<i16>, | |
| min: Option<i16>, | |
| max: Option<i16>, | |
| clamp: bool, | |
| ) -> Option<i16> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, i16::MIN) as i128, | |
| unwrap_or!(max, i16::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as i16), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn i32( | |
| s: &[u8], | |
| default: Option<i32>, | |
| min: Option<i32>, | |
| max: Option<i32>, | |
| clamp: bool, | |
| ) -> Option<i32> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, i32::MIN) as i128, | |
| unwrap_or!(max, i32::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as i32), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn i64( | |
| s: &[u8], | |
| default: Option<i64>, | |
| min: Option<i64>, | |
| max: Option<i64>, | |
| clamp: bool, | |
| ) -> Option<i64> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, i64::MIN) as i128, | |
| unwrap_or!(max, i64::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as i64), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| pub(crate) const fn i128( | |
| s: &[u8], | |
| default: Option<i128>, | |
| min: Option<i128>, | |
| max: Option<i128>, | |
| clamp: bool, | |
| ) -> Option<i128> { | |
| match parse_signed( | |
| s, | |
| unwrap_or!(min, i128::MIN) as i128, | |
| unwrap_or!(max, i128::MAX) as i128, | |
| clamp, | |
| ) { | |
| Ok(v) => Some(v as i128), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| } | |
| pub(crate) mod dispatch { | |
| use super::ParseError::Empty; | |
| pub(crate) const fn usize(s: &[u8], default: Option<usize>) -> Option<usize> { | |
| super::parse_bounded::usize(s, default, None, None, false) | |
| } | |
| pub(crate) const fn u8(s: &[u8], default: Option<u8>) -> Option<u8> { | |
| super::parse_bounded::u8(s, default, None, None, false) | |
| } | |
| pub(crate) const fn u16(s: &[u8], default: Option<u16>) -> Option<u16> { | |
| super::parse_bounded::u16(s, default, None, None, false) | |
| } | |
| pub(crate) const fn u32(s: &[u8], default: Option<u32>) -> Option<u32> { | |
| super::parse_bounded::u32(s, default, None, None, false) | |
| } | |
| pub(crate) const fn u64(s: &[u8], default: Option<u64>) -> Option<u64> { | |
| super::parse_bounded::u64(s, default, None, None, false) | |
| } | |
| pub(crate) const fn u128(s: &[u8], default: Option<u128>) -> Option<u128> { | |
| super::parse_bounded::u128(s, default, None, None, false) | |
| } | |
| pub(crate) const fn isize(s: &[u8], default: Option<isize>) -> Option<isize> { | |
| super::parse_bounded::isize(s, default, None, None, false) | |
| } | |
| pub(crate) const fn i8(s: &[u8], default: Option<i8>) -> Option<i8> { | |
| super::parse_bounded::i8(s, default, None, None, false) | |
| } | |
| pub(crate) const fn i16(s: &[u8], default: Option<i16>) -> Option<i16> { | |
| super::parse_bounded::i16(s, default, None, None, false) | |
| } | |
| pub(crate) const fn i32(s: &[u8], default: Option<i32>) -> Option<i32> { | |
| super::parse_bounded::i32(s, default, None, None, false) | |
| } | |
| pub(crate) const fn i64(s: &[u8], default: Option<i64>) -> Option<i64> { | |
| super::parse_bounded::i64(s, default, None, None, false) | |
| } | |
| pub(crate) const fn i128(s: &[u8], default: Option<i128>) -> Option<i128> { | |
| super::parse_bounded::i128(s, default, None, None, false) | |
| } | |
| pub(crate) const fn bool(s: &[u8], default: Option<bool>) -> Option<bool> { | |
| match super::parse_bool(s) { | |
| Ok(v) => Some(v), | |
| Err(Empty) => default, | |
| _ => None, | |
| } | |
| } | |
| } | |
| #[cfg(test)] | |
| mod test { | |
| extern crate alloc; | |
| use super::*; | |
| use ParseError::*; | |
| #[test] | |
| fn test_trim_empty() { | |
| assert_eq!(trim_ws(b""), None); | |
| assert_eq!(trim_ws(b" \t\n\r"), None); | |
| assert_eq!(trim_ws(b" \t\n\r"), None); | |
| for i in 0..15 { | |
| for c in [" ", "\t", "\n", "\r"] { | |
| let s = c.repeat(i); | |
| assert_eq!( | |
| trim_ws(s.as_bytes()), | |
| None, | |
| "string of {} spaces (type = {:?}): {:?}", | |
| s.len(), | |
| c, | |
| s, | |
| ); | |
| for c2 in [" ", "\t", "\n", "\r"] { | |
| let cc = alloc::format!("{}{}", c, c2); | |
| let s2 = cc.repeat(i); | |
| assert_eq!( | |
| trim_ws(s.as_bytes()), | |
| None, | |
| "string of {} spaces (type = {:?}): {:?}", | |
| s2.len(), | |
| cc, | |
| s2, | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| #[test] | |
| fn test_trim() { | |
| fn check(s: &str, r: core::ops::Range<usize>) { | |
| assert_eq!( | |
| trim_ws(s.as_bytes()), | |
| Some((r.start, r.end)), | |
| "trim {:?}", | |
| (s, r) | |
| ); | |
| let (sr, se) = trim_ws(s.as_bytes()).unwrap(); | |
| assert_eq!( | |
| s.get(sr..se), | |
| Some(s.trim()), | |
| "trim smoke {:?}", | |
| (s, r, sr..se), | |
| ); | |
| } | |
| for i in 1..10 { | |
| let s = "a".repeat(i); | |
| let r = 0..s.len(); | |
| check(&s, r.clone()); | |
| for i in 0..15 { | |
| for p1 in [" ", "\t", "\r", "\n"] { | |
| for p2 in [" ", "\t", "\r", "\n"] { | |
| let pad = alloc::format!("{}{}", p1, p2).repeat(i); | |
| check(&alloc::format!("{}{}", s, pad), r.clone()); | |
| let padded_r = r.start + pad.len()..r.end + pad.len(); | |
| check(&alloc::format!("{}{}", pad, s), padded_r.clone()); | |
| check(&alloc::format!("{}{}{}", pad, s, pad), padded_r.clone()); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fn mixcase(s: &str, b: bool) -> alloc::string::String { | |
| s.chars() | |
| .enumerate() | |
| .map(|(i, c)| { | |
| if (i % 2 == 0) ^ b { | |
| c.to_uppercase().collect::<alloc::string::String>() | |
| } else { | |
| c.to_lowercase().collect::<alloc::string::String>() | |
| } | |
| }) | |
| .collect() | |
| } | |
| #[test] | |
| fn test_parse_unsigned() { | |
| #[track_caller] | |
| fn check(s: &str, res: Result<u128, ParseError>) { | |
| assert_eq!( | |
| parse_unsigned(s.as_ref(), 0, u128::MAX, false), | |
| res, | |
| "input: {:?}", | |
| (s, res), | |
| ); | |
| } | |
| #[track_caller] | |
| fn ok1(s: &str, v: u128) { | |
| check(s, Ok(v)); | |
| } | |
| #[track_caller] | |
| fn err1(s: &str, e: ParseError) { | |
| check(s, Err(e)) | |
| } | |
| #[track_caller] | |
| fn ok(s: &str, v: u128) { | |
| ok1(s, v); | |
| ok1(&s.to_uppercase(), v); | |
| ok1(&s.to_lowercase(), v); | |
| ok1(&mixcase(s, true), v); | |
| ok1(&mixcase(s, false), v); | |
| ok1(&alloc::format!(" {}", s), v); | |
| ok1(&alloc::format!("{} ", s), v); | |
| ok1(&alloc::format!(" {} ", s), v); | |
| ok1(&alloc::format!("{} ", s), v); | |
| ok1(&alloc::format!(" {}", s), v); | |
| ok1(&alloc::format!(" {} ", s), v); | |
| if !s.contains("+") { | |
| ok1(&alloc::format!("+{}", s), v); | |
| ok1(&alloc::format!("+{} ", s), v); | |
| ok1(&alloc::format!(" +{}", s), v); | |
| ok1(&alloc::format!(" +{} ", s), v); | |
| ok1(&alloc::format!("+{} ", s), v); | |
| ok1(&alloc::format!(" +{}", s), v); | |
| ok1(&alloc::format!(" +{} ", s), v); | |
| } | |
| } | |
| #[track_caller] | |
| fn err(s: &str, e: ParseError) { | |
| err1(s, e); | |
| err1(&s.to_uppercase(), e); | |
| err1(&s.to_lowercase(), e); | |
| err1(&alloc::format!("{} ", s), e); | |
| err1(&alloc::format!(" {}", s), e); | |
| err1(&alloc::format!(" {} ", s), e); | |
| err1(&alloc::format!("{} ", s), e); | |
| err1(&alloc::format!(" {}", s), e); | |
| err1(&alloc::format!(" {} ", s), e); | |
| if !s.contains("+") && !s.contains("-") && !s.is_empty() { | |
| err1(&alloc::format!("+{}", s), e); | |
| err1(&alloc::format!("+{} ", s), e); | |
| err1(&alloc::format!(" +{}", s), e); | |
| err1(&alloc::format!(" +{} ", s), e); | |
| err1(&alloc::format!("+{} ", s), e); | |
| err1(&alloc::format!(" +{}", s), e); | |
| err1(&alloc::format!(" +{} ", s), e); | |
| } | |
| } | |
| ok("0x1234abcd", 0x1234abcd); | |
| ok("0x__12_34__a__b__c__d__", 0x1234abcd); | |
| ok("1234567890", 1234567890); | |
| ok("0o12345670", 0o12345670); | |
| ok("0b101010", 0b101010); | |
| ok("0xabcdef0123456789", 0xabcdef0123456789); | |
| ok("0o3777777777777777777777777777777777777777777", u128::MAX); | |
| ok("0xffffffffffffffffffffffffffffffff", u128::MAX); | |
| ok("0Xffffffffffffffffffffffffffffffff", u128::MAX); | |
| ok("340282366920938463463374607431768211455", u128::MAX); | |
| ok("0o3777777777777777777777777777777777777777777", u128::MAX); | |
| ok("0xffffffffffffffffffffffffffffffff", u128::MAX); | |
| ok("0Xffffffffffffffffffffffffffffffff", u128::MAX); | |
| ok( | |
| "0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | |
| u128::MAX, | |
| ); | |
| ok("0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff", u128::MAX); | |
| ok("0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff___", u128::MAX); | |
| ok( | |
| "0x__f_f_f_f_ffff_ffff_ffff_ffff_ffff_ffff_ffff___", | |
| u128::MAX, | |
| ); | |
| err("", Empty); | |
| err("-30", UnexpectedSign); | |
| err("-", UnexpectedSign); | |
| err("", Empty); | |
| err("0x1234g", InvalidDigit); | |
| err("0xg1234", InvalidDigit); | |
| err("0x1234g1234", InvalidDigit); | |
| err("123a", InvalidDigit); | |
| err("a123", InvalidDigit); | |
| err("123a123", InvalidDigit); | |
| err("0o8", InvalidDigit); | |
| err("0o128", InvalidDigit); | |
| err("0o12812", InvalidDigit); | |
| err("0o12a12", InvalidDigit); | |
| err("0b2", InvalidDigit); | |
| err("0b00200", InvalidDigit); | |
| err("0b002", InvalidDigit); | |
| err("0b200", InvalidDigit); | |
| err("0b121", InvalidDigit); | |
| err("0b12", InvalidDigit); | |
| err("0b21", InvalidDigit); | |
| err("0o", NoDigits); | |
| err("0o_", NoDigits); | |
| err("0o__", NoDigits); | |
| err("0x", NoDigits); | |
| err("0x_", NoDigits); | |
| err("0x___", NoDigits); | |
| err("0b", NoDigits); | |
| err("0b_", NoDigits); | |
| err("0b__", NoDigits); | |
| err("_0b", InvalidDigit); | |
| err("0o4000000000000000000000000000000000000000000", IntOverflow); | |
| err("0xffffffffffffffffffffffffffffffff0", IntOverflow); | |
| err("0xf0fffffffffffffffffffffffffffffff0", IntOverflow); | |
| assert_eq!(parse_unsigned(b"200", 100, 1000, false), Ok(200)); | |
| assert_eq!(parse_unsigned(b"1000", 100, 1000, false), Ok(1000)); | |
| assert_eq!(parse_unsigned(b"100", 100, 1000, false), Ok(100)); | |
| assert_eq!(parse_unsigned(b"500", 600, 700, false), Err(OutOfRange),); | |
| assert_eq!(parse_unsigned(b"500", 200, 300, false), Err(OutOfRange),); | |
| assert_eq!(parse_unsigned(b"500", 600, 700, true), Ok(600)); | |
| assert_eq!(parse_unsigned(b"500", 200, 300, true), Ok(300)); | |
| assert_eq!(parse_unsigned(b"250", 200, 300, true), Ok(250)); | |
| assert_eq!(parse_unsigned(b"500", 200, u128::MAX, true), Ok(500)); | |
| assert_eq!(parse_unsigned(b"250", 0, 300, true), Ok(250)); | |
| assert_eq!(parse_unsigned(b"0", 0, 200, true), Ok(0)); | |
| assert_eq!(parse_unsigned(b"-1", 0, 200, true), Ok(0)); | |
| assert_eq!(parse_unsigned(b"0", 1, 255, true), Ok(1)); | |
| assert_eq!(parse_unsigned(b"-1", 1, 255, true), Ok(1)); | |
| assert_eq!(parse_unsigned(b"0", 0, u128::MAX, true), Ok(0)); | |
| assert_eq!(parse_unsigned(b"-1", 0, u128::MAX, true), Ok(0)); | |
| assert_eq!(parse_unsigned(b"-1", 0, u128::MAX, true), Ok(0)); | |
| assert_eq!(parse_unsigned(b"1000", 1, 255, false), Err(OutOfRange)); | |
| assert_eq!(parse_unsigned(b"1000", 1, 255, true), Ok(255)); | |
| assert_eq!( | |
| parse_unsigned( | |
| b"0o4000000000000000000000000000000000000000000", | |
| 0, | |
| u128::MAX, | |
| true, | |
| ), | |
| Ok(u128::MAX), | |
| ); | |
| assert_eq!( | |
| parse_unsigned(b"0xffffffffffffffffffffffffffffffff0", 0, u128::MAX, true), | |
| Ok(u128::MAX), | |
| ); | |
| assert_eq!( | |
| parse_unsigned(b"0xf0fffffffffffffffffffffffffffffff0", 0, u128::MAX, true), | |
| Ok(u128::MAX), | |
| ); | |
| assert_eq!( | |
| parse_unsigned( | |
| b"0o4000000000000000000000000000000000000000000", | |
| 0, | |
| 50, | |
| true, | |
| ), | |
| Ok(50), | |
| ); | |
| assert_eq!( | |
| parse_unsigned(b"0xffffffffffffffffffffffffffffffff0", 0, 50, true), | |
| Ok(50), | |
| ); | |
| assert_eq!( | |
| parse_unsigned(b"0xf0fffffffffffffffffffffffffffffff0", 0, 50, true,), | |
| Ok(50), | |
| ); | |
| } | |
| #[test] | |
| fn test_parse_signed() { | |
| #[track_caller] | |
| fn check(s: &str, res: Result<i128, ParseError>) { | |
| assert_eq!( | |
| parse_signed(s.as_ref(), i128::MIN, i128::MAX, false), | |
| res, | |
| "input: {:?}", | |
| (s, res), | |
| ); | |
| } | |
| #[track_caller] | |
| fn ok1(s: &str, v: i128) { | |
| check(s, Ok(v)); | |
| } | |
| #[track_caller] | |
| fn err1(s: &str, e: ParseError) { | |
| check(s, Err(e)) | |
| } | |
| #[track_caller] | |
| fn ok(s: &str, v: i128) { | |
| ok1(s, v); | |
| ok1(&s.to_uppercase(), v); | |
| ok1(&s.to_lowercase(), v); | |
| ok1(&mixcase(s, true), v); | |
| ok1(&mixcase(s, false), v); | |
| ok1(&alloc::format!(" {}", s), v); | |
| ok1(&alloc::format!("{} ", s), v); | |
| ok1(&alloc::format!(" {} ", s), v); | |
| ok1(&alloc::format!("{} ", s), v); | |
| ok1(&alloc::format!(" {}", s), v); | |
| ok1(&alloc::format!(" {} ", s), v); | |
| if !s.contains("+") && !s.contains("-") { | |
| assert!(v >= 0, "bug in test {:?}", (s, v)); | |
| ok1(&alloc::format!("+{}", s), v); | |
| ok1(&alloc::format!("+{} ", s), v); | |
| ok1(&alloc::format!(" +{}", s), v); | |
| ok1(&alloc::format!(" +{} ", s), v); | |
| ok1(&alloc::format!("+{} ", s), v); | |
| ok1(&alloc::format!(" +{}", s), v); | |
| ok1(&alloc::format!(" +{} ", s), v); | |
| if let Some(n) = v.checked_neg() { | |
| ok1(&alloc::format!("-{} ", s), n); | |
| ok1(&alloc::format!("-{} ", s), n); | |
| ok1(&alloc::format!(" -{}", s), n); | |
| ok1(&alloc::format!(" -{} ", s), n); | |
| ok1(&alloc::format!("-{} ", s), n); | |
| ok1(&alloc::format!(" -{}", s), n); | |
| ok1(&alloc::format!(" -{} ", s), n); | |
| } | |
| } | |
| } | |
| #[track_caller] | |
| fn err(s: &str, e: ParseError) { | |
| err1(s, e); | |
| err1(&s.to_uppercase(), e); | |
| err1(&s.to_lowercase(), e); | |
| err1(&alloc::format!("{} ", s), e); | |
| err1(&alloc::format!(" {}", s), e); | |
| err1(&alloc::format!(" {} ", s), e); | |
| err1(&alloc::format!("{} ", s), e); | |
| err1(&alloc::format!(" {}", s), e); | |
| err1(&alloc::format!(" {} ", s), e); | |
| if !s.contains("+") && !s.contains("-") && !s.is_empty() { | |
| err1(&alloc::format!("+{} ", s), e); | |
| err1(&alloc::format!(" +{}", s), e); | |
| err1(&alloc::format!(" +{} ", s), e); | |
| err1(&alloc::format!("+{} ", s), e); | |
| err1(&alloc::format!(" +{}", s), e); | |
| err1(&alloc::format!(" +{} ", s), e); | |
| } | |
| } | |
| ok("0", 0); | |
| ok("1", 1); | |
| ok("100", 100); | |
| ok("0o0", 0); | |
| ok("0o__0__", 0); | |
| ok("0x1234abcd", 0x1234abcd); | |
| ok("0x__12_34__a__b__c__d__", 0x1234abcd); | |
| ok("170141183460469231731687303715884105727", i128::MAX); | |
| ok("-170141183460469231731687303715884105728", i128::MIN); | |
| ok("0x7fffffffffffffffffffffffffffffff", i128::MAX); | |
| ok("-0x80000000000000000000000000000000", i128::MIN); | |
| ok( | |
| "0b1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | |
| i128::MAX, | |
| ); | |
| ok( | |
| "-0b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | |
| i128::MIN, | |
| ); | |
| ok("0o1777777777777777777777777777777777777777777", i128::MAX); | |
| ok("-0o2000000000000000000000000000000000000000000", i128::MIN); | |
| ok("170141183460469231731687303715884105726", i128::MAX - 1); | |
| ok("-170141183460469231731687303715884105727", i128::MIN + 1); | |
| ok("-1234567890", -1234567890); | |
| ok("-0o12345670", -0o12345670); | |
| ok("-0b101010", -0b101010); | |
| ok("-0xabcdef0123456789", -0xabcdef0123456789); | |
| err("170141183460469231731687303715884105728", OutOfRange); | |
| err("1701411834604692317316873037158841057270", IntOverflow); | |
| err("", Empty); | |
| err("-", NoDigits); | |
| err("0x1234z", InvalidDigit); | |
| err("123f", InvalidDigit); | |
| err("0x1234z", InvalidDigit); | |
| err("123f", InvalidDigit); | |
| err("0o", NoDigits); | |
| err("0o_", NoDigits); | |
| err("0o__", NoDigits); | |
| err("0x", NoDigits); | |
| err("0x_", NoDigits); | |
| err("0x___", NoDigits); | |
| err("0b", NoDigits); | |
| err("0b_", NoDigits); | |
| err("0b__", NoDigits); | |
| err("_0b", InvalidDigit); | |
| err("0o4000000000000000000000000000000000000000000", IntOverflow); | |
| err("0x7fffffffffffffffffffffffffffffff0", IntOverflow); | |
| err("0x70fffffffffffffffffffffffffffffff0", IntOverflow); | |
| err("0o3777777777777777777777777777777777777777777", OutOfRange); | |
| err("0xffffffffffffffffffffffffffffffff", OutOfRange); | |
| err( | |
| "0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", | |
| OutOfRange, | |
| ); | |
| err("170141183460469231731687303715884105728", OutOfRange); | |
| err("-170141183460469231731687303715884105729", OutOfRange); | |
| assert_eq!(parse_signed(b"0", -1000, 1000, false), Ok(0),); | |
| assert_eq!(parse_signed(b"1000", -1000, 1000, false), Ok(1000),); | |
| assert_eq!(parse_signed(b"-1000", -1000, 1000, false), Ok(-1000),); | |
| assert_eq!( | |
| parse_signed(b"1000", i128::MIN, 999, false), | |
| Err(OutOfRange), | |
| ); | |
| assert_eq!(parse_signed(b"1000", 999, i128::MAX, true), Ok(1000),); | |
| assert_eq!(parse_signed(b"1000", i128::MIN, 999, true), Ok(999),); | |
| assert_eq!( | |
| parse_signed(b"-1000", -999, i128::MAX, false), | |
| Err(OutOfRange), | |
| ); | |
| assert_eq!(parse_signed(b"-1000", -999, i128::MAX, true), Ok(-999),); | |
| assert_eq!(parse_signed(b"-1001", -1000, 1000, false), Err(OutOfRange),); | |
| assert_eq!(parse_signed(b"1001", -1000, 1000, false), Err(OutOfRange),); | |
| assert_eq!(parse_signed(b"-1001", -1000, 1000, true), Ok(-1000)); | |
| assert_eq!(parse_signed(b"1001", -1000, 1000, true), Ok(1000)); | |
| assert_eq!(parse_signed(b"1001", -1000, 1000, true), Ok(1000)); | |
| assert_eq!(parse_signed(b"500", 600, 700, true), Ok(600)); | |
| assert_eq!(parse_signed(b"500", 200, 300, true), Ok(300)); | |
| assert_eq!(parse_signed(b"500", 200, i128::MAX, true), Ok(500)); | |
| assert_eq!(parse_signed(b"250", 200, 300, true), Ok(250)); | |
| assert_eq!(parse_signed(b"500", 200, i128::MAX, true), Ok(500)); | |
| assert_eq!(parse_signed(b"250", i128::MIN, 300, true), Ok(250)); | |
| assert_eq!(parse_signed(b"150", -300, 200, true), Ok(150)); | |
| assert_eq!(parse_signed(b"-150", -300, 200, true), Ok(-150)); | |
| assert_eq!(parse_signed(b"300", -300, 200, true), Ok(200)); | |
| assert_eq!(parse_signed(b"-400", -300, 200, true), Ok(-300)); | |
| assert_eq!(parse_signed(b"-250", -300, -200, true), Ok(-250)); | |
| assert_eq!(parse_signed(b"-500", -200, i128::MAX, true), Ok(-200)); | |
| assert_eq!(parse_signed(b"-250", -300, i128::MAX, true), Ok(-250)); | |
| assert_eq!(parse_signed(b"0", i128::MIN, 200, true), Ok(0)); | |
| assert_eq!(parse_signed(b"-1", i128::MIN, 200, true), Ok(-1)); | |
| assert_eq!(parse_signed(b"0", 1, 255, true), Ok(1)); | |
| assert_eq!(parse_signed(b"-1", 1, 255, true), Ok(1)); | |
| assert_eq!(parse_signed(b"0", i128::MIN, i128::MAX, true), Ok(0)); | |
| assert_eq!(parse_signed(b"-1", i128::MIN, i128::MAX, true), Ok(-1)); | |
| assert_eq!(parse_signed(b"1", i128::MIN, i128::MAX, true), Ok(1)); | |
| assert_eq!(parse_signed(b"1000", 1, 255, false), Err(OutOfRange)); | |
| assert_eq!(parse_signed(b"-1000", 1, 255, false), Err(OutOfRange)); | |
| assert_eq!(parse_signed(b"-1000", -255, 255, false), Err(OutOfRange)); | |
| assert_eq!(parse_signed(b"1000", 1, 255, true), Ok(255)); | |
| assert_eq!(parse_signed(b"-1000", 1, 255, true), Ok(1)); | |
| assert_eq!(parse_signed(b"-1000", -255, 255, true), Ok(-255)); | |
| assert_eq!(parse_signed(b"1000", 1, 255, true), Ok(255)); | |
| assert_eq!(parse_signed(b"1000", -255, -1, true), Ok(-1)); | |
| assert_eq!(parse_signed(b"-1000", -255, -1, true), Ok(-255)); | |
| assert_eq!( | |
| parse_signed( | |
| b"0o3777777777777777777777777777777777777777777", | |
| i128::MIN, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(i128::MAX) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"0o3777777777777777777777777777777777777777777", | |
| i128::MIN, | |
| 30, | |
| true | |
| ), | |
| Ok(30) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"0o3777777777777777777777777777777777777777777", | |
| i128::MIN, | |
| -30, | |
| true | |
| ), | |
| Ok(-30) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"0xffffffffffffffffffffffffffffffff", | |
| i128::MIN, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(i128::MAX) | |
| ); | |
| assert_eq!( | |
| parse_signed(b"0xffffffffffffffffffffffffffffffff", i128::MIN, 30, true), | |
| Ok(30) | |
| ); | |
| assert_eq!( | |
| parse_signed(b"0xffffffffffffffffffffffffffffffff", i128::MIN, -30, true), | |
| Ok(-30) | |
| ); | |
| assert_eq!(parse_signed(b"0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", i128::MIN, i128::MAX, true), Ok(i128::MAX)); | |
| assert_eq!(parse_signed(b"0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", i128::MIN, 30, true), Ok(30)); | |
| assert_eq!(parse_signed(b"0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", i128::MIN, -30, true), Ok(-30)); | |
| assert_eq!( | |
| parse_signed( | |
| b"170141183460469231731687303715884105728", | |
| i128::MIN, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(i128::MAX) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"170141183460469231731687303715884105728", | |
| i128::MIN, | |
| 30, | |
| true | |
| ), | |
| Ok(30) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"170141183460469231731687303715884105728", | |
| i128::MIN, | |
| -30, | |
| true | |
| ), | |
| Ok(-30) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"170141183460469231731687303715884105728", | |
| 10, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(i128::MAX) | |
| ); | |
| assert_eq!( | |
| parse_signed(b"170141183460469231731687303715884105728", 10, 30, true), | |
| Ok(30) | |
| ); | |
| assert_eq!( | |
| parse_signed(b"170141183460469231731687303715884105728", -30, 10, true), | |
| Ok(10) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| i128::MIN, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(i128::MIN) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| i128::MIN, | |
| 30, | |
| true | |
| ), | |
| Ok(i128::MIN) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| i128::MIN, | |
| -30, | |
| true | |
| ), | |
| Ok(i128::MIN) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| i128::MIN, | |
| 10, | |
| true | |
| ), | |
| Ok(i128::MIN) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| 30, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(30) | |
| ); | |
| assert_eq!( | |
| parse_signed( | |
| b"-170141183460469231731687303715884105729", | |
| -30, | |
| i128::MAX, | |
| true | |
| ), | |
| Ok(-30) | |
| ); | |
| } | |
| #[test] | |
| fn test_parse_bool() { | |
| #[track_caller] | |
| fn check(s: &str, res: Result<bool, ParseError>) { | |
| assert_eq!(parse_bool(s.as_ref()), res, "input: {:?}", (s, res),); | |
| } | |
| #[track_caller] | |
| fn ok(s: &str, res: bool) { | |
| check(s, Ok(res)); | |
| check(&alloc::format!("{} ", s), Ok(res)); | |
| check(&alloc::format!(" {}", s), Ok(res)); | |
| check(&alloc::format!(" {} ", s), Ok(res)); | |
| check(&s.to_lowercase(), Ok(res)); | |
| check(&s.to_uppercase(), Ok(res)); | |
| check(&mixcase(s, true), Ok(res)); | |
| check(&mixcase(s, false), Ok(res)); | |
| } | |
| #[track_caller] | |
| fn err(s: &str, e: ParseError) { | |
| check(s, Err(e)); | |
| check(&alloc::format!("{} ", s), Err(e)); | |
| check(&alloc::format!(" {}", s), Err(e)); | |
| check(&alloc::format!(" {} ", s), Err(e)); | |
| check(&s.to_lowercase(), Err(e)); | |
| check(&s.to_uppercase(), Err(e)); | |
| check(&mixcase(s, true), Err(e)); | |
| check(&mixcase(s, false), Err(e)); | |
| } | |
| ok("t", true); | |
| ok("f", false); | |
| ok("y", true); | |
| ok("n", false); | |
| ok("1", true); | |
| ok("0", false); | |
| ok("true", true); | |
| ok("false", false); | |
| ok("on", true); | |
| ok("off", false); | |
| ok("yes", true); | |
| ok("no", false); | |
| err("", Empty); | |
| err("foo", UnknownBoolValue); | |
| err("x", UnknownBoolValue); | |
| err("01", UnknownBoolValue); | |
| err("abc", UnknownBoolValue); | |
| err("defg", UnknownBoolValue); | |
| err("true1", UnknownBoolValue); | |
| err("0true1", UnknownBoolValue); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment