Skip to content

Instantly share code, notes, and snippets.

@AnthonyMikh
Last active December 5, 2020 21:55
Show Gist options
  • Save AnthonyMikh/e7ae66c865504b6b1b7b255577ddbffa to your computer and use it in GitHub Desktop.
Save AnthonyMikh/e7ae66c865504b6b1b7b255577ddbffa to your computer and use it in GitHub Desktop.
Разбор ASCII-строк с игнорированием регистра
#[allow(dead_code)]
const fn is_ascii_lowercase(s: &str) -> bool {
let s = s.as_bytes();
let len = s.len();
let mut i = 0;
while i < len {
if !s[i].is_ascii() || s[i].is_ascii_uppercase() {
return false;
}
i += 1;
}
true
}
#[allow(dead_code)]
const fn are_all_ascii_lowercase(ss: &[&str]) -> bool {
let len = ss.len();
let mut i = 0;
while i < len {
if !is_ascii_lowercase(&ss[i]) {
return false;
}
i += 1;
}
true
}
macro_rules! ascii_case_insensitive {
(match $value:ident {
$($(|)? $($pattern:literal)|+ $(if $condition:expr)? => $arm:expr,)*
_ => $catch_all:expr $(,)?
}) => {{
#[deny(const_err)]
const _ARE_ALL_ASCII_LOWERCASE: [(); 1] = [(); are_all_ascii_lowercase(&[$($($pattern,)+)*]) as _];
#[allow(dead_code)]
fn non_repeating(s: &str) {
#[deny(unreachable_patterns)]
match s {
$($(| $pattern)+ => (),)*
_ => (),
}
}
match $value {
$(x if ($(x.eq_ignore_ascii_case($pattern))||+) $(&& $condition)? => $arm,)*
_ => $catch_all,
}
}}
}
#[derive(Debug)]
enum Example {
Foo,
Bar,
FourtyTwo,
}
impl std::str::FromStr for Example {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(ascii_case_insensitive!(match s {
"foo" => Self::Foo,
"bar" if s.as_bytes()[0].is_ascii_lowercase() => Self::Bar,
"fourtytwo" | "fourty_two" | "42" => Self::FourtyTwo,
_ => return Err(s.into()),
}))
}
}
fn main() {
let inputs = [
"foo",
"Foo",
"FOO",
"bar",
"bAr",
"BAR",
"fourtytwo",
"Fourtytwo",
"FOURTYTWO",
"fourty_two",
"fOuRtY_tWo",
"42",
"bogus",
];
for &input in &inputs[..] {
println!("{:?}", input.parse::<Example>());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment