serdes_ai_core/
identifier.rs1use chrono::{DateTime, Utc};
7use uuid::Uuid;
8
9#[must_use]
23pub fn generate_tool_call_id() -> String {
24 format!("call_{}", Uuid::new_v4().simple())
25}
26
27#[must_use]
40pub fn generate_run_id() -> String {
41 format!("run_{}", Uuid::new_v4().simple())
42}
43
44#[must_use]
48pub fn generate_message_id() -> String {
49 format!("msg_{}", Uuid::new_v4().simple())
50}
51
52#[must_use]
56pub fn generate_conversation_id() -> String {
57 format!("conv_{}", Uuid::new_v4().simple())
58}
59
60#[must_use]
62pub fn generate_uuid() -> String {
63 Uuid::new_v4().to_string()
64}
65
66#[must_use]
70pub fn generate_short_id() -> String {
71 Uuid::new_v4().simple().to_string()[..8].to_string()
72}
73
74#[must_use]
85pub fn now_utc() -> DateTime<Utc> {
86 Utc::now()
87}
88
89pub fn parse_timestamp(s: &str) -> Result<DateTime<Utc>, chrono::ParseError> {
95 s.parse()
96}
97
98#[must_use]
100pub fn format_timestamp(dt: &DateTime<Utc>) -> String {
101 dt.to_rfc3339()
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
106#[serde(transparent)]
107pub struct ToolCallId(String);
108
109impl ToolCallId {
110 #[must_use]
112 pub fn new() -> Self {
113 Self(generate_tool_call_id())
114 }
115
116 #[must_use]
118 pub fn from_string(s: impl Into<String>) -> Self {
119 Self(s.into())
120 }
121
122 #[must_use]
124 pub fn as_str(&self) -> &str {
125 &self.0
126 }
127}
128
129impl Default for ToolCallId {
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135impl std::fmt::Display for ToolCallId {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 write!(f, "{}", self.0)
138 }
139}
140
141impl From<String> for ToolCallId {
142 fn from(s: String) -> Self {
143 Self(s)
144 }
145}
146
147impl From<&str> for ToolCallId {
148 fn from(s: &str) -> Self {
149 Self(s.to_string())
150 }
151}
152
153impl AsRef<str> for ToolCallId {
154 fn as_ref(&self) -> &str {
155 &self.0
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
161#[serde(transparent)]
162pub struct RunId(String);
163
164impl RunId {
165 #[must_use]
167 pub fn new() -> Self {
168 Self(generate_run_id())
169 }
170
171 #[must_use]
173 pub fn from_string(s: impl Into<String>) -> Self {
174 Self(s.into())
175 }
176
177 #[must_use]
179 pub fn as_str(&self) -> &str {
180 &self.0
181 }
182}
183
184impl Default for RunId {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190impl std::fmt::Display for RunId {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 write!(f, "{}", self.0)
193 }
194}
195
196impl From<String> for RunId {
197 fn from(s: String) -> Self {
198 Self(s)
199 }
200}
201
202impl From<&str> for RunId {
203 fn from(s: &str) -> Self {
204 Self(s.to_string())
205 }
206}
207
208impl AsRef<str> for RunId {
209 fn as_ref(&self) -> &str {
210 &self.0
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
216#[serde(transparent)]
217pub struct ConversationId(String);
218
219impl ConversationId {
220 #[must_use]
222 pub fn new() -> Self {
223 Self(generate_conversation_id())
224 }
225
226 #[must_use]
228 pub fn from_string(s: impl Into<String>) -> Self {
229 Self(s.into())
230 }
231
232 #[must_use]
234 pub fn as_str(&self) -> &str {
235 &self.0
236 }
237}
238
239impl Default for ConversationId {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245impl std::fmt::Display for ConversationId {
246 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247 write!(f, "{}", self.0)
248 }
249}
250
251impl From<String> for ConversationId {
252 fn from(s: String) -> Self {
253 Self(s)
254 }
255}
256
257impl From<&str> for ConversationId {
258 fn from(s: &str) -> Self {
259 Self(s.to_string())
260 }
261}
262
263impl AsRef<str> for ConversationId {
264 fn as_ref(&self) -> &str {
265 &self.0
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_generate_tool_call_id() {
275 let id = generate_tool_call_id();
276 assert!(id.starts_with("call_"));
277 assert_eq!(id.len(), 37);
278 }
279
280 #[test]
281 fn test_generate_run_id() {
282 let id = generate_run_id();
283 assert!(id.starts_with("run_"));
284 }
285
286 #[test]
287 fn test_generate_unique_ids() {
288 let id1 = generate_tool_call_id();
289 let id2 = generate_tool_call_id();
290 assert_ne!(id1, id2);
291 }
292
293 #[test]
294 fn test_tool_call_id_type() {
295 let id = ToolCallId::new();
296 assert!(id.as_str().starts_with("call_"));
297
298 let from_str = ToolCallId::from_string("call_custom");
299 assert_eq!(from_str.as_str(), "call_custom");
300 }
301
302 #[test]
303 fn test_now_utc() {
304 let now = now_utc();
305 let formatted = format_timestamp(&now);
306 let parsed = parse_timestamp(&formatted).unwrap();
307 assert!((now - parsed).num_seconds().abs() <= 1);
309 }
310
311 #[test]
312 fn test_serde_roundtrip() {
313 let id = ToolCallId::new();
314 let json = serde_json::to_string(&id).unwrap();
315 let parsed: ToolCallId = serde_json::from_str(&json).unwrap();
316 assert_eq!(id, parsed);
317 }
318}