use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseError {
InvalidLength { expected: usize, got: usize },
InvalidChar { position: usize, byte: u8 },
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, got } => {
write!(f, "invalid length: expected {}, got {}", expected, got)
}
Self::InvalidChar { position, byte } => {
write!(
f,
"invalid character 0x{:02x} at position {}",
byte, position
)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UuidParseError {
InvalidLength { expected: usize, got: usize },
InvalidChar { position: usize, byte: u8 },
InvalidFormat,
}
impl fmt::Display for UuidParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, got } => {
write!(f, "invalid length: expected {}, got {}", expected, got)
}
Self::InvalidChar { position, byte } => {
write!(
f,
"invalid character 0x{:02x} at position {}",
byte, position
)
}
Self::InvalidFormat => write!(f, "invalid UUID format (expected dashes at 8-13-18-23)"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for UuidParseError {}
impl From<ParseError> for UuidParseError {
#[inline]
fn from(e: ParseError) -> Self {
match e {
ParseError::InvalidLength { expected, got } => Self::InvalidLength { expected, got },
ParseError::InvalidChar { position, byte } => Self::InvalidChar { position, byte },
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecodeError {
InvalidLength { expected: usize, got: usize },
InvalidChar { position: usize, byte: u8 },
Overflow,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, got } => {
write!(f, "invalid length: expected {}, got {}", expected, got)
}
Self::InvalidChar { position, byte } => {
write!(
f,
"invalid character 0x{:02x} at position {}",
byte, position
)
}
Self::Overflow => write!(f, "value overflows target type"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}
impl From<ParseError> for DecodeError {
#[inline]
fn from(e: ParseError) -> Self {
match e {
ParseError::InvalidLength { expected, got } => Self::InvalidLength { expected, got },
ParseError::InvalidChar { position, byte } => Self::InvalidChar { position, byte },
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeIdParseError {
InvalidLength { expected: usize, got: usize },
InvalidChar { position: usize, byte: u8 },
InvalidFormat,
InvalidPrefix,
}
impl fmt::Display for TypeIdParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, got } => {
write!(f, "invalid length: expected max {}, got {}", expected, got)
}
Self::InvalidChar { position, byte } => {
write!(
f,
"invalid character 0x{:02x} at position {}",
byte, position
)
}
Self::InvalidFormat => {
write!(f, "invalid TypeId format (expected prefix_suffix)")
}
Self::InvalidPrefix => {
write!(f, "invalid prefix: must be non-empty lowercase ASCII [a-z]")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for TypeIdParseError {}
impl From<ParseError> for TypeIdParseError {
#[inline]
fn from(e: ParseError) -> Self {
match e {
ParseError::InvalidLength { expected, got } => Self::InvalidLength { expected, got },
ParseError::InvalidChar { position, byte } => Self::InvalidChar { position, byte },
}
}
}
#[allow(dead_code)] #[inline]
pub(crate) const fn validate_hex(b: u8, position: usize) -> Result<u8, ParseError> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'a'..=b'f' => Ok(b - b'a' + 10),
b'A'..=b'F' => Ok(b - b'A' + 10),
_ => Err(ParseError::InvalidChar { position, byte: b }),
}
}
const CROCKFORD32_INVALID: u8 = 0xFF;
pub(crate) static CROCKFORD32_DECODE: [u8; 256] = {
let mut table = [CROCKFORD32_INVALID; 256];
table[b'0' as usize] = 0;
table[b'1' as usize] = 1;
table[b'2' as usize] = 2;
table[b'3' as usize] = 3;
table[b'4' as usize] = 4;
table[b'5' as usize] = 5;
table[b'6' as usize] = 6;
table[b'7' as usize] = 7;
table[b'8' as usize] = 8;
table[b'9' as usize] = 9;
table[b'A' as usize] = 10;
table[b'B' as usize] = 11;
table[b'C' as usize] = 12;
table[b'D' as usize] = 13;
table[b'E' as usize] = 14;
table[b'F' as usize] = 15;
table[b'G' as usize] = 16;
table[b'H' as usize] = 17;
table[b'J' as usize] = 18;
table[b'K' as usize] = 19;
table[b'M' as usize] = 20;
table[b'N' as usize] = 21;
table[b'P' as usize] = 22;
table[b'Q' as usize] = 23;
table[b'R' as usize] = 24;
table[b'S' as usize] = 25;
table[b'T' as usize] = 26;
table[b'V' as usize] = 27;
table[b'W' as usize] = 28;
table[b'X' as usize] = 29;
table[b'Y' as usize] = 30;
table[b'Z' as usize] = 31;
table[b'a' as usize] = 10;
table[b'b' as usize] = 11;
table[b'c' as usize] = 12;
table[b'd' as usize] = 13;
table[b'e' as usize] = 14;
table[b'f' as usize] = 15;
table[b'g' as usize] = 16;
table[b'h' as usize] = 17;
table[b'j' as usize] = 18;
table[b'k' as usize] = 19;
table[b'm' as usize] = 20;
table[b'n' as usize] = 21;
table[b'p' as usize] = 22;
table[b'q' as usize] = 23;
table[b'r' as usize] = 24;
table[b's' as usize] = 25;
table[b't' as usize] = 26;
table[b'v' as usize] = 27;
table[b'w' as usize] = 28;
table[b'x' as usize] = 29;
table[b'y' as usize] = 30;
table[b'z' as usize] = 31;
table[b'O' as usize] = 0; table[b'o' as usize] = 0;
table[b'I' as usize] = 1; table[b'i' as usize] = 1;
table[b'L' as usize] = 1; table[b'l' as usize] = 1;
table
};
#[inline]
pub(crate) fn validate_crockford32(b: u8, position: usize) -> Result<u8, ParseError> {
let val = CROCKFORD32_DECODE[b as usize];
if val == CROCKFORD32_INVALID {
Err(ParseError::InvalidChar { position, byte: b })
} else {
Ok(val)
}
}
#[inline]
pub(crate) const fn validate_base62(b: u8, position: usize) -> Result<u8, ParseError> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'A'..=b'Z' => Ok(b - b'A' + 10),
b'a'..=b'z' => Ok(b - b'a' + 36),
_ => Err(ParseError::InvalidChar { position, byte: b }),
}
}
#[inline]
pub(crate) const fn validate_base36(b: u8, position: usize) -> Result<u8, ParseError> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'a'..=b'z' => Ok(b - b'a' + 10),
b'A'..=b'Z' => Ok(b - b'A' + 10),
_ => Err(ParseError::InvalidChar { position, byte: b }),
}
}