2022-06-08 13:31:38 +02:00

61 lines
1.8 KiB
Rust

//! Matrix session ID.
use ruma_macros::IdZst;
use super::IdParseError;
/// A session ID.
///
/// Session IDs in Matrix are opaque character sequences of `[0-9a-zA-Z.=_-]`. Their length must
/// must not exceed 255 characters.
#[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 {
// non-const form:
//
// bytes.iter().all(|b| b.is_ascii_alphanumeric() || b".=_-".contains(&b))
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;
}
}
}