use std::{fmt, marker::PhantomData, str::FromStr};
pub trait Parse {
fn parse_uw<T: FromStrUnwrap>(&self) -> T;
fn idx(&self, index: usize) -> u8;
fn ints_iter<T: FromStrUnwrap>(&self) -> Ints<T>;
fn ints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N];
fn uints_iter<T: FromStrUnwrap>(&self) -> UInts<T>;
fn uints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N];
fn try_between(&self, pre: &str, post: &str) -> Option<&str>;
fn as_parser(&self) -> Parser;
}
impl Parse for str {
#[inline]
#[track_caller]
fn parse_uw<T: FromStrUnwrap>(&self) -> T {
T::parse(self)
}
#[inline]
#[track_caller]
fn idx(&self, index: usize) -> u8 {
self.as_bytes()[index]
}
fn ints_iter<T: FromStrUnwrap>(&self) -> Ints<T> {
Ints {
s: self,
_phantom: PhantomData,
}
}
#[inline]
#[track_caller]
fn ints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N] {
self.ints_iter().collect_n()
}
fn uints_iter<T: FromStrUnwrap>(&self) -> UInts<T> {
UInts {
s: self,
_phantom: PhantomData,
}
}
#[inline]
#[track_caller]
fn uints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N] {
self.uints_iter().collect_n()
}
fn try_between(&self, pre: &str, post: &str) -> Option<&str> {
let start = self.find(pre)? + pre.len();
let rest = &self[start..];
let end = rest.find(post).unwrap_or(rest.len()) + start;
Some(&self[start..end])
}
#[inline]
fn as_parser(&self) -> Parser {
Parser::new(self)
}
}
impl<S> Parse for S
where
S: AsRef<str>,
{
fn parse_uw<T: FromStrUnwrap>(&self) -> T {
self.as_ref().parse_uw()
}
fn idx(&self, index: usize) -> u8 {
self.as_ref().idx(index)
}
fn ints_iter<T: FromStrUnwrap>(&self) -> Ints<T> {
self.as_ref().ints_iter()
}
fn ints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N] {
self.as_ref().ints()
}
fn uints_iter<T: FromStrUnwrap>(&self) -> UInts<T> {
self.as_ref().uints_iter()
}
fn uints<const N: usize, T: FromStrUnwrap>(&self) -> [T; N] {
self.as_ref().uints()
}
fn try_between(&self, pre: &str, post: &str) -> Option<&str> {
self.as_ref().try_between(pre, post)
}
fn as_parser(&self) -> Parser {
self.as_ref().as_parser()
}
}
pub trait FromStrUnwrap {
fn parse(s: &str) -> Self;
}
impl<T> FromStrUnwrap for T
where
T: FromStr,
<T as FromStr>::Err: fmt::Debug,
{
#[inline(always)]
#[track_caller]
fn parse(s: &str) -> Self {
s.parse().unwrap()
}
}
#[derive(Clone, Copy, Debug)]
pub struct Ints<'a, T> {
s: &'a str,
_phantom: PhantomData<T>,
}
impl<'a, T: FromStrUnwrap> Iterator for Ints<'a, T> {
type Item = T;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
fn is_digit_or_sign(ch: u8) -> bool {
ch.is_ascii_digit() || ch == b'-' || ch == b'+'
}
let (s, mut i) = (self.s, 0);
loop {
while i < s.len() && !is_digit_or_sign(s.idx(i)) {
i += 1;
}
if i >= s.len() {
return None;
}
let mut j = i + 1;
while j < s.len() && s.idx(j).is_ascii_digit() {
j += 1;
}
if !s.idx(j - 1).is_ascii_digit() {
i = j;
continue;
}
self.s = &s[j..];
return Some(s[i..j].parse_uw());
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct UInts<'a, T> {
s: &'a str,
_phantom: PhantomData<T>,
}
impl<'a, T: FromStrUnwrap> Iterator for UInts<'a, T> {
type Item = T;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
let (s, mut i) = (self.s, 0);
while i < s.len() && !s.idx(i).is_ascii_digit() {
i += 1;
}
if i >= s.len() {
return None;
}
let mut j = i + 1;
while j < s.len() && s.idx(j).is_ascii_digit() {
j += 1;
}
self.s = &s[j..];
Some(s[i..j].parse_uw())
}
}
pub trait IterUnwrap {
type Item;
fn next_uw(&mut self) -> Self::Item;
fn collect_n<const N: usize>(&mut self) -> [Self::Item; N];
}
impl<I> IterUnwrap for I
where
I: Iterator,
{
type Item = <I as Iterator>::Item;
#[inline]
#[track_caller]
fn next_uw(&mut self) -> Self::Item {
self.next().unwrap()
}
#[track_caller]
fn collect_n<const N: usize>(&mut self) -> [Self::Item; N] {
let arr = [(); N].map(|_| self.next());
for res in &arr {
if res.is_none() {
panic!("not enough elements in the iterator to fill the size `N` array")
}
}
arr.map(|x| x.unwrap())
}
}
#[derive(Clone, Debug)]
pub struct Parser<'a> {
inner: &'a str,
}
impl<'a> Parser<'a> {
#[inline]
pub fn new(s: &'a str) -> Self {
Self { inner: s }
}
#[inline]
#[track_caller]
pub fn skip(&mut self, n: usize) -> Self {
self.inner = &self.inner[n..];
self.clone()
}
#[track_caller]
pub fn take(&mut self, n: usize) -> &str {
let first = &self.inner[..n];
self.inner = &self.inner[n..];
first
}
#[inline]
pub fn rest(self) -> &'a str {
self.inner
}
#[track_caller]
pub fn before(&mut self, suffix: &str) -> &'a str {
let (before, after) = self
.inner
.split_once(suffix)
.expect("`suffix` should be contained in the string");
self.inner = after;
before
}
#[track_caller]
pub fn after(self, prefix: &str) -> &'a str {
let i = self
.inner
.find(prefix)
.expect("`prefix` should be contained in the string")
+ prefix.len();
&self.inner[i..]
}
#[track_caller]
pub fn between(&mut self, prefix: &str, suffix: &str) -> &'a str {
*self = Self {
inner: self.clone().after(prefix),
};
self.before(suffix)
}
}