use combine::parser::byte::{byte, crlf, newline as lf};
use combine::parser::range::{recognize, take_while, take_while1};
use combine::stream::RangeStream;
use combine::*;
pub(crate) unsafe fn from_utf8_unchecked<'b>(
bytes: &'b [u8],
safety_justification: &'static str,
) -> &'b str {
if cfg!(debug_assertions) {
std::str::from_utf8(bytes).expect(safety_justification)
} else {
std::str::from_utf8_unchecked(bytes)
}
}
#[inline]
pub(crate) fn is_wschar(c: u8) -> bool {
matches!(c, b' ' | b'\t')
}
parse!(ws() -> &'a str, {
take_while(is_wschar).map(|b| {
unsafe { from_utf8_unchecked(b, "`is_wschar` filters out on-ASCII") }
})
});
#[inline]
pub(crate) fn is_non_ascii(c: u8) -> bool {
matches!(c, 0x80..=0xff)
}
#[inline]
fn is_non_eol(c: u8) -> bool {
matches!(c, 0x09 | 0x20..=0x7E) | is_non_ascii(c)
}
pub(crate) const COMMENT_START_SYMBOL: u8 = b'#';
parse!(comment() -> &'a [u8], {
recognize((
byte(COMMENT_START_SYMBOL),
take_while(is_non_eol),
))
});
pub(crate) const LF: u8 = b'\n';
pub(crate) const CR: u8 = b'\r';
parse!(newline() -> char, {
choice((lf(), crlf()))
.map(|_| '\n')
.expected("a newline")
});
parse!(ws_newline() -> &'a str, {
recognize(
skip_many(choice((
newline().map(|_| &b"\n"[..]),
take_while1(is_wschar),
))),
).map(|b| {
unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
})
});
parse!(ws_newlines() -> &'a str, {
recognize((
newline(),
ws_newline(),
)).map(|b| {
unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
})
});
parse!(ws_comment_newline() -> &'a [u8], {
recognize(
skip_many(
choice((
skip_many1(
choice((
take_while1(is_wschar),
newline().map(|_| &b"\n"[..]),
))
),
comment().map(|_| ()),
))
)
)
});
parse!(line_ending() -> &'a str, {
choice((
newline().map(|_| "\n"),
eof().map(|_| "")
))
});
parse!(line_trailing() -> &'a [u8], {
recognize((
ws(),
optional(comment()),
)).skip(line_ending())
});