Skip to main content

uvb_core/
user.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// Type-safe user identifier wrapper
5///
6/// This newtype provides compile-time guarantees that:
7/// 1. User IDs cannot be accidentally mixed with other string types
8/// 2. All user-scoped operations explicitly require a UserId
9/// 3. Cross-user operations are caught at compile time
10#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct UserId(String);
13
14impl UserId {
15    /// Create a new UserId from a string
16    pub fn new(id: impl Into<String>) -> Self {
17        Self(id.into())
18    }
19
20    /// Get the user ID as a string slice
21    pub fn as_str(&self) -> &str {
22        &self.0
23    }
24
25    /// Consume the UserId and return the inner String
26    pub fn into_inner(self) -> String {
27        self.0
28    }
29
30    /// Validate that the user ID is well-formed
31    pub fn is_valid(&self) -> bool {
32        !self.0.is_empty() && self.0.len() <= 255
33    }
34}
35
36impl fmt::Display for UserId {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{}", self.0)
39    }
40}
41
42impl AsRef<str> for UserId {
43    fn as_ref(&self) -> &str {
44        &self.0
45    }
46}
47
48impl From<String> for UserId {
49    fn from(s: String) -> Self {
50        Self(s)
51    }
52}
53
54impl From<&str> for UserId {
55    fn from(s: &str) -> Self {
56        Self(s.to_string())
57    }
58}
59
60impl From<UserId> for String {
61    fn from(user_id: UserId) -> Self {
62        user_id.0
63    }
64}
65
66impl PartialEq<str> for UserId {
67    fn eq(&self, other: &str) -> bool {
68        self.0 == other
69    }
70}
71
72impl PartialEq<&str> for UserId {
73    fn eq(&self, other: &&str) -> bool {
74        self.0 == *other
75    }
76}
77
78impl PartialEq<String> for UserId {
79    fn eq(&self, other: &String) -> bool {
80        &self.0 == other
81    }
82}