use crate::input::{
code_points::{LF, REVERSE_SOLIDUS},
Filtered, FilteredChar, FilteredCharVec,
};
use super::{errors::Eof, hex_digit::HexDigit, hex_digits::HexDigits, whitespace::Whitespace};
pub enum EscapedCodePoint {
HexDigits(HexDigits<6>),
Other(FilteredChar),
}
impl EscapedCodePoint {
pub(crate) const fn consume_after_reverse_solidus(
stream: Filtered,
) -> Result<(Option<Self>, Filtered), Eof> {
let (fc, mut this) = match stream.next() {
Some(v) => v,
None => return Err(Eof),
};
Ok(match fc.to_char() {
LF => (None, this),
u => {
if let Some(d) = HexDigit::try_new(u) {
let mut hex_digits = HexDigits::new().with(d);
while hex_digits.can_push() {
let d;
(d, this) = HexDigit::consume(this);
if let Some(d) = d {
hex_digits = hex_digits.with(d);
} else {
break;
}
}
if let Some((ws, new_this)) = Whitespace::consume(this.copy()) {
this = new_this;
hex_digits = hex_digits.with_whitespace(ws);
}
(Some(EscapedCodePoint::HexDigits(hex_digits)), this)
} else {
(Some(EscapedCodePoint::Other(fc)), this)
}
}
})
}
pub const fn chars_would_start(chars: FilteredCharVec<2>) -> bool {
match chars.as_slice().to_char_slice() {
[REVERSE_SOLIDUS, b] => *b != LF,
_ => false,
}
}
pub(crate) const fn to_code_point(&self) -> char {
match self {
EscapedCodePoint::HexDigits(hd) => hd.to_code_point(),
EscapedCodePoint::Other(c) => c.to_char(),
}
}
}
#[cfg(test)]
mod tests {
use crate::input::Filtered;
use super::EscapedCodePoint;
const _: () = {
assert!(!EscapedCodePoint::chars_would_start(
Filtered::new("\\").first_n_code_points::<2>()
));
};
}