use std::convert::TryInto;
use crate::utils::ParseLineBreak;
use crate::{Input, Parse, ParseInfallible};
use super::{Indents, While};
#[inline]
pub(crate) fn is_ws(c: char) -> bool {
matches!(c, ' ' | '\t')
}
pub(crate) struct ParseSpacesU8;
pub(crate) struct ParseSpaces;
pub(crate) struct ParseOneWS;
pub(crate) struct ParseNSpaces(pub u8);
pub(crate) struct ParseAtMostNSpaces(pub u8);
impl Parse for ParseOneWS {
type Output = ();
fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
if let Some(b' ' | b'\t') = input.rest().bytes().next() {
input.bump(1);
Some(())
} else {
None
}
}
}
impl Parse for ParseSpacesU8 {
type Output = u8;
#[inline]
fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
let mut res = 0usize;
let mut len = 0;
let rest = input.rest();
for c in rest.bytes() {
match c {
b' ' => {
res += 1;
len += 1;
}
b'\t' => {
res += 4;
len += 1;
}
_ => break,
}
}
if len > 0 {
input.bump(len);
}
res.try_into().ok()
}
}
impl ParseInfallible for ParseSpaces {
type Output = ();
#[inline]
fn parse_infallible(&self, input: &mut Input) -> Self::Output {
input.parse_i(While(is_ws));
}
}
impl Parse for ParseNSpaces {
type Output = ();
fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
let mut visual_spaces = 0u8;
let mut bytes = 0;
for c in input.rest().bytes() {
match c {
b' ' => {
visual_spaces += 1;
bytes += 1;
}
b'\t' => {
visual_spaces += 4;
bytes += 1;
}
_ => break,
}
if visual_spaces >= self.0 {
input.bump(bytes);
return Some(());
}
}
None
}
}
impl Parse for ParseAtMostNSpaces {
type Output = u8;
fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
let mut visual_spaces = 0u8;
let mut bytes = 0;
for c in input.rest().bytes() {
match c {
b' ' => {
visual_spaces += 1;
bytes += 1;
}
b'\t' => {
visual_spaces += 4;
bytes += 1;
}
_ => break,
}
if visual_spaces == self.0 {
break;
}
}
if bytes > 0 {
input.bump(bytes);
}
Some(visual_spaces)
}
}
pub(crate) struct ParseWs<'a>(pub Indents<'a>);
impl ParseInfallible for ParseWs<'_> {
type Output = ();
fn parse_infallible(&self, input: &mut Input) -> Self::Output {
input.parse_i(While(is_ws));
while matches!(input.peek_char(), Some('\n' | '\r')) {
if input.parse(ParseLineBreak(self.0)).is_none() {
break;
}
input.parse_i(While(is_ws));
}
}
}
pub(crate) struct ParseWsNoBlankLinkes<'a>(pub Indents<'a>);
impl Parse for ParseWsNoBlankLinkes<'_> {
type Output = ();
fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
input.parse_i(While(is_ws));
if input.parse(ParseLineBreak(self.0)).is_some() {
input.parse_i(While(is_ws));
if matches!(input.peek_char(), Some('\n' | '\r')) {
return None;
}
}
Some(())
}
}