#[derive(Debug)]
pub enum CompletionErr {
HasInvalidBytes,
InsufficientInput,
}
#[derive(Debug)]
pub struct IncompleteUtf8Char {
_buffer: [u8; 4],
_len: usize,
}
impl IncompleteUtf8Char {
pub(crate) const fn new(bytes: &[u8]) -> Option<Self> {
let mut buffer = [0, 0, 0, 0];
match bytes {
[] => {}
[a] => {
buffer[0] = *a;
}
[a, b] => {
buffer[0] = *a;
buffer[1] = *b;
}
[a, b, c] => {
buffer[0] = *a;
buffer[1] = *b;
buffer[2] = *c;
}
[a, b, c, d] => {
buffer[0] = *a;
buffer[1] = *b;
buffer[2] = *c;
buffer[3] = *d;
}
_ => return None,
}
Some(Self { _buffer: buffer, _len: bytes.len() })
}
}
#[cfg(feature = "web-socket")]
impl IncompleteUtf8Char {
pub(crate) fn complete<'bytes>(
&mut self,
bytes: &'bytes [u8],
) -> (Result<(), CompletionErr>, &'bytes [u8]) {
let (consumed, complete_err) = self.push_to_build_valid_char(bytes);
let remaining = bytes.get(consumed..).unwrap_or_default();
match complete_err {
None => (Ok(()), remaining),
Some(elem) => (Err(elem), remaining),
}
}
fn push_to_build_valid_char(&mut self, bytes: &[u8]) -> (usize, Option<CompletionErr>) {
let initial_len = self._len;
let to_write_len = {
let unwritten = self._buffer.get_mut(initial_len..).unwrap_or_default();
let to_write_len = unwritten.len().min(bytes.len());
unwritten
.get_mut(..to_write_len)
.unwrap_or_default()
.copy_from_slice(bytes.get(..to_write_len).unwrap_or_default());
to_write_len
};
let new_bytes = {
let len = initial_len.wrapping_add(to_write_len);
self._buffer.get(..len).unwrap_or_default()
};
if let Err(err) = crate::misc::from_utf8_std(new_bytes) {
if err.valid_up_to > 0 {
self._len = err.valid_up_to;
(err.valid_up_to.wrapping_sub(initial_len), None)
} else {
match err.error_len {
None => {
self._len = new_bytes.len();
(to_write_len, Some(CompletionErr::InsufficientInput))
}
Some(invalid_seq_len) => {
self._len = invalid_seq_len;
(invalid_seq_len.wrapping_sub(initial_len), Some(CompletionErr::HasInvalidBytes))
}
}
}
} else {
self._len = new_bytes.len();
(to_write_len, None)
}
}
}