use ruma_macros::IdZst;
use super::IdParseError;
#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
#[ruma_id(validate = validate_session_id)]
pub struct SessionId(str);
impl SessionId {
#[doc(hidden)]
pub const fn _priv_const_new(s: &str) -> Result<&Self, &'static str> {
match validate_session_id(s) {
Ok(()) => Ok(Self::from_borrowed(s)),
Err(IdParseError::MaximumLengthExceeded) => {
Err("Invalid Session ID: exceeds 255 bytes")
}
Err(IdParseError::InvalidCharacters) => {
Err("Invalid Session ID: contains invalid characters")
}
Err(IdParseError::Empty) => Err("Invalid Session ID: empty"),
Err(_) => unreachable!(),
}
}
}
const fn validate_session_id(s: &str) -> Result<(), IdParseError> {
if s.len() > 255 {
return Err(IdParseError::MaximumLengthExceeded);
} else if contains_invalid_byte(s.as_bytes()) {
return Err(IdParseError::InvalidCharacters);
} else if s.is_empty() {
return Err(IdParseError::Empty);
}
Ok(())
}
const fn contains_invalid_byte(mut bytes: &[u8]) -> bool {
loop {
if let Some((byte, rest)) = bytes.split_first() {
if byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'=' | b'_' | b'-') {
bytes = rest;
} else {
break true;
}
} else {
break false;
}
}
}