ruma_common/identifiers/
session_id.rs
1use ruma_macros::IdZst;
4
5use super::IdParseError;
6
7#[repr(transparent)]
12#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
13#[ruma_id(validate = validate_session_id)]
14pub struct SessionId(str);
15
16impl SessionId {
17 #[doc(hidden)]
18 pub const fn _priv_const_new(s: &str) -> Result<&Self, &'static str> {
19 match validate_session_id(s) {
20 Ok(()) => Ok(Self::from_borrowed(s)),
21 Err(IdParseError::MaximumLengthExceeded) => {
22 Err("Invalid Session ID: exceeds 255 bytes")
23 }
24 Err(IdParseError::InvalidCharacters) => {
25 Err("Invalid Session ID: contains invalid characters")
26 }
27 Err(IdParseError::Empty) => Err("Invalid Session ID: empty"),
28 Err(_) => unreachable!(),
29 }
30 }
31}
32
33const fn validate_session_id(s: &str) -> Result<(), IdParseError> {
34 if s.len() > 255 {
35 return Err(IdParseError::MaximumLengthExceeded);
36 } else if contains_invalid_byte(s.as_bytes()) {
37 return Err(IdParseError::InvalidCharacters);
38 } else if s.is_empty() {
39 return Err(IdParseError::Empty);
40 }
41
42 Ok(())
43}
44
45const fn contains_invalid_byte(mut bytes: &[u8]) -> bool {
46 loop {
50 if let Some((byte, rest)) = bytes.split_first() {
51 if byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'=' | b'_' | b'-') {
52 bytes = rest;
53 } else {
54 break true;
55 }
56 } else {
57 break false;
58 }
59 }
60}