hyperactor/reference/
name.rs1use serde::Deserialize;
12use serde::Serialize;
13
14use crate::reference::lex::Lexer;
15use crate::reference::lex::ParseError;
16use crate::reference::lex::Token;
17
18pub(crate) const FLICKR_BASE_58: &str =
22 "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
23
24#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
29pub struct Uid(u64);
30
31impl Uid {
32 pub fn generate() -> Self {
34 Self(rand::random())
35 }
36
37 pub(crate) fn zero() -> Self {
38 Self(0)
39 }
40}
41
42impl From<u64> for Uid {
43 fn from(value: u64) -> Self {
44 Self(value)
45 }
46}
47
48impl std::fmt::Display for Uid {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 let mut num = self.0;
51 let base = FLICKR_BASE_58.len() as u64;
52 let mut result = String::with_capacity(12);
53
54 for _pos in 0..12 {
55 let remainder = (num % base) as usize;
56 num /= base;
57 let c = FLICKR_BASE_58.chars().nth(remainder).unwrap();
58 result.push(c);
59 }
60 debug_assert_eq!(num, 0);
61
62 let result = result.chars().rev().collect::<String>();
63 write!(f, "{}", result)
64 }
65}
66
67impl std::str::FromStr for Uid {
68 type Err = ParseError;
69
70 fn from_str(s: &str) -> Result<Self, Self::Err> {
71 let mut lexer = Lexer::new(s);
72 let uid = lexer.next_or_eof().into_uid()?;
73 lexer.expect(Token::Eof)?;
74 Ok(uid)
75 }
76}
77
78#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
81pub struct Ident(String);
82
83impl Ident {
84 pub fn new(value: String) -> Result<Self, String> {
87 let mut chars = value.chars();
88 match chars.next() {
89 None => return Err(value),
90 Some(ch) if !unicode_ident::is_xid_start(ch) && ch != '_' => return Err(value),
91 Some(_) => (),
92 }
93 if chars.all(unicode_ident::is_xid_continue) {
94 Ok(Self(value))
95 } else {
96 Err(value)
97 }
98 }
99}
100
101impl std::fmt::Display for Ident {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 self.0.fmt(f)
104 }
105}
106
107impl std::str::FromStr for Ident {
108 type Err = String;
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 Ident::new(s.to_string())
112 }
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
127pub struct Name {
128 namespace: Ident,
129 base: Ident,
130 uid: Uid,
131}
132
133impl Name {
134 pub fn new(namespace: Ident, base: Ident, uid: Uid) -> Self {
137 Self {
138 namespace,
139 base,
140 uid,
141 }
142 }
143
144 pub fn generate(namespace: Ident, base: Ident) -> Self {
146 Self {
147 namespace,
148 base,
149 uid: Uid::generate(),
150 }
151 }
152}
153
154impl std::fmt::Display for Name {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 write!(f, "{}:{}-{}", self.namespace, self.base, self.uid)
157 }
158}
159
160impl std::str::FromStr for Name {
161 type Err = ParseError;
162
163 fn from_str(s: &str) -> Result<Self, Self::Err> {
164 let mut lexer = Lexer::new(s);
165
166 let namespace = lexer.next_or_eof().into_ident()?;
167 lexer.expect(Token::Colon)?;
168 let base = lexer.next_or_eof().into_ident()?;
169 let uid = lexer.next_or_eof().into_uid()?;
170 lexer.expect(Token::Eof)?;
171
172 Ok(Name {
173 namespace,
174 base,
175 uid,
176 })
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_generate() {
186 assert_ne!(
187 Name::generate("namespace".parse().unwrap(), "base".parse().unwrap(),),
188 Name::generate("namespace".parse().unwrap(), "base".parse().unwrap(),),
189 );
190 }
191
192 #[test]
193 fn test_roundtrip() {
194 let name = Name::new(
195 "namespace".parse().unwrap(),
196 "base".parse().unwrap(),
197 Uid::zero(),
198 );
199 assert_eq!(name.to_string(), "namespace:base-111111111111".to_string());
200 assert_eq!(name.to_string().parse::<Name>().unwrap(), name);
201 }
202
203 #[test]
204 fn test_invalid() {
205 assert_eq!(
206 "namespace:base-lllll".parse::<Name>().unwrap_err(),
207 ParseError::Expected(Token::Uid(Uid::zero()), Token::Error("lllll".to_string()))
208 );
209 }
210}