use qubit_utils::nonzero;
use crate::internal::ParseError;
#[derive(Debug, Clone, Copy)]
pub(crate) enum CStringLiteralParseContext<'a> {
CompleteText(#[doc = "The complete UTF-8 source, used to preserve character boundaries in diagnostics."] &'a str),
EofBytes,
StreamingBytes,
}
impl CStringLiteralParseContext<'_> {
#[must_use]
#[inline]
pub(crate) fn is_complete_text(self) -> bool {
matches!(self, Self::CompleteText(_) | Self::EofBytes)
}
#[must_use]
#[inline]
pub(crate) fn is_streaming(self) -> bool {
matches!(self, Self::StreamingBytes)
}
pub(crate) fn trailing_escape_error(self, marker_index: usize, _available: usize) -> ParseError {
match self {
Self::CompleteText(_) | Self::EofBytes => {
crate::c_string_literal_codec::invalid_escape(marker_index, "\\", "incomplete escape sequence").into()
}
Self::StreamingBytes => ParseError::Incomplete { required: nonzero(2) },
}
}
#[must_use]
pub(crate) fn source_character(self, input: &[u8], index: usize) -> char {
match self {
Self::CompleteText(text) => text
.get(index..)
.and_then(|rest| rest.chars().next())
.unwrap_or(char::from(input[index])),
Self::EofBytes | Self::StreamingBytes => char::from(input[index]),
}
}
#[must_use]
#[inline]
pub(crate) fn raw_source_reason(self) -> &'static str {
match self {
Self::CompleteText(_) | Self::EofBytes => {
"raw source character must be printable ASCII or allowed whitespace"
}
Self::StreamingBytes => "raw source byte must be printable ASCII or allowed whitespace",
}
}
#[must_use]
pub(crate) fn escape_fragment(self, input: &[u8], start: usize, end: usize) -> String {
match self {
Self::CompleteText(text) => {
let mut fragment_end = end.min(text.len());
while !text.is_char_boundary(fragment_end) {
fragment_end += 1;
}
text.get(start..fragment_end).unwrap_or("\\").to_owned()
}
Self::EofBytes | Self::StreamingBytes => input[start..end.min(input.len())]
.iter()
.map(|byte| char::from(*byte))
.collect(),
}
}
}