use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Error {
InvalidByte { offset: usize, byte: u8 },
Truncated { offset: usize },
InvalidPadding { offset: usize },
NonCanonical { offset: usize },
InvalidUtf8 { offset: usize },
InvalidUtf16 { offset: usize },
Overflow,
BufferTooSmall { required: usize },
NotFound,
}
impl Error {
pub(crate) fn shifted(self, by: usize) -> Self {
match self {
Error::InvalidByte { offset, byte } => Error::InvalidByte {
offset: offset + by,
byte,
},
Error::Truncated { offset } => Error::Truncated {
offset: offset + by,
},
Error::InvalidPadding { offset } => Error::InvalidPadding {
offset: offset + by,
},
Error::NonCanonical { offset } => Error::NonCanonical {
offset: offset + by,
},
Error::InvalidUtf8 { offset } => Error::InvalidUtf8 {
offset: offset + by,
},
Error::InvalidUtf16 { offset } => Error::InvalidUtf16 {
offset: offset + by,
},
other => other,
}
}
pub(crate) const fn unexpected(byte: u8, offset: usize) -> Self {
if byte == b'=' {
Error::InvalidPadding { offset }
} else {
Error::InvalidByte { offset, byte }
}
}
pub fn offset(&self) -> Option<usize> {
match *self {
Error::InvalidByte { offset, .. }
| Error::Truncated { offset }
| Error::InvalidPadding { offset }
| Error::NonCanonical { offset }
| Error::InvalidUtf8 { offset }
| Error::InvalidUtf16 { offset } => Some(offset),
Error::Overflow | Error::BufferTooSmall { .. } | Error::NotFound => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::InvalidByte { offset, byte } => {
write!(f, "invalid byte 0x{byte:02x} at offset {offset}")
}
Error::Truncated { offset } => write!(f, "input truncated at offset {offset}"),
Error::InvalidPadding { offset } => write!(f, "invalid padding at offset {offset}"),
Error::NonCanonical { offset } => {
write!(f, "non-canonical encoding at offset {offset}")
}
Error::InvalidUtf8 { offset } => write!(f, "invalid UTF-8 at offset {offset}"),
Error::InvalidUtf16 { offset } => write!(f, "invalid UTF-16 at offset {offset}"),
Error::Overflow => f.write_str("value overflows the target integer"),
Error::BufferTooSmall { required } => {
write!(f, "output buffer too small, {required} bytes required")
}
Error::NotFound => f.write_str("no encoded block found"),
}
}
}
impl std::error::Error for Error {}
pub(crate) trait ToStr {
fn to_str(&self) -> Result<&str, Error>;
}
impl ToStr for [u8] {
#[inline]
fn to_str(&self) -> Result<&str, Error> {
simdutf8::compat::from_utf8(self).map_err(|err| Error::InvalidUtf8 {
offset: err.valid_up_to(),
})
}
}