core_crypto/mls/session/
user_id.rs1use super::{Error, Result};
2
3#[derive(Debug, Clone, Copy, Eq, PartialEq, derive_more::Deref)]
17pub struct UserId<'a>(&'a [u8]);
18
19impl UserId<'_> {
20 const USER_ID_DELIMITER: u8 = b':';
21}
22
23impl<'a> TryFrom<&'a str> for UserId<'a> {
24 type Error = Error;
25
26 fn try_from(client_id: &'a str) -> Result<Self> {
27 client_id.as_bytes().try_into()
28 }
29}
30
31impl<'a> TryFrom<&'a [u8]> for UserId<'a> {
32 type Error = Error;
33
34 fn try_from(id: &'a [u8]) -> Result<Self> {
35 let found = id
36 .splitn(2, |&b| b == Self::USER_ID_DELIMITER)
37 .next()
38 .ok_or(Error::InvalidUserId)?;
39 if found.len() == id.len() {
40 return Err(Error::InvalidUserId);
41 }
42 Ok(Self(found))
43 }
44}
45
46impl TryFrom<UserId<'_>> for String {
47 type Error = Error;
48
49 fn try_from(uid: UserId<'_>) -> Result<Self> {
50 Ok(std::str::from_utf8(&uid).map_err(|_| Error::InvalidUserId)?.to_string())
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[macro_rules_attribute::apply(smol_macros::test)]
59 async fn should_parse_client_id() {
60 let user_id = "LcksJb74Tm6N12cDjFy7lQ:8e6424430d3b28be@world.com";
61 let user_id = UserId::try_from(user_id).unwrap();
62 assert_eq!(user_id, UserId("LcksJb74Tm6N12cDjFy7lQ".as_bytes()));
63 }
64
65 #[macro_rules_attribute::apply(smol_macros::test)]
66 async fn should_fail_when_invalid() {
67 let user_id = "LcksJb74Tm6N12cDjFy7lQ/8e6424430d3b28be@world.com";
68 let user_id = UserId::try_from(user_id);
69 assert!(matches!(user_id.unwrap_err(), Error::InvalidUserId));
70 }
71}