aoc-rs-2021/src/parsing.rs
Jan Christian Grünhage 577e2a2c78 simplify number parsing
2021-12-13 07:34:41 +01:00

63 lines
1.7 KiB
Rust

use num::Num;
use std::fmt::Debug;
use yap::{IntoTokens, Tokens};
pub fn space(tokens: &mut impl Tokens<Item = char>) -> bool {
tokens.token(' ')
}
pub fn newline(tokens: &mut impl Tokens<Item = char>) -> bool {
tokens.tokens("\r\n".into_tokens()) || tokens.token('\n')
}
pub fn parse_number<T: Num>(tokens: &mut impl Tokens<Item = char>) -> Option<T> {
parse_number_with_radix(tokens, 10, None)
}
pub fn parse_digit<T: Num>(tokens: &mut impl Tokens<Item = char>) -> Option<T> {
parse_number_with_radix(tokens, 10, Some(1))
}
pub fn parse_number_with_radix<T: Num>(
tokens: &mut impl Tokens<Item = char>,
base: u32,
limit: Option<usize>,
) -> Option<T> {
tokens.skip_tokens_while(|t| *t == ' ');
let mut remaining = limit.map(|x| x as isize).unwrap_or(isize::MAX);
let digits: String = tokens
.tokens_while(|c| {
remaining -= 1;
c.is_digit(base) && remaining >= 0
})
.collect();
(!digits.is_empty())
.then(|| T::from_str_radix(&digits, base).ok())
.flatten()
}
pub fn parse_n<T: Debug, P: Tokens<Item = char>, const N: usize>(
tokens: &mut P,
parser: &dyn Fn(&mut P) -> Option<T>,
separator: &dyn Fn(&mut P) -> bool,
) -> Option<[T; N]> {
tokens
.sep_by(parser, separator)
.collect::<Vec<T>>()
.try_into()
.ok()
}
#[cfg(test)]
mod test {
use yap::IntoTokens;
#[test]
fn parse_digit() {
let mut tokens = "1234".into_tokens();
assert_eq!(Some(1), super::parse_digit(&mut tokens));
assert_eq!(Some(2), super::parse_digit(&mut tokens));
assert_eq!(Some(3), super::parse_digit(&mut tokens));
assert_eq!(Some(4), super::parse_digit(&mut tokens));
}
}