1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6macro_rules! impl_id_type {
8 ($name:ident) => {
9 impl fmt::Display for $name {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 write!(f, "{}", self.0)
12 }
13 }
14
15 impl From<&str> for $name {
16 fn from(s: &str) -> Self {
17 $name::new(s)
18 }
19 }
20
21 impl From<String> for $name {
22 fn from(s: String) -> Self {
23 $name::new(s)
24 }
25 }
26 };
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
34pub struct SpeakerId(String);
35
36impl SpeakerId {
37 pub fn new(id: impl Into<String>) -> Self {
39 let id = id.into();
40 let normalized = id.strip_prefix("uuid:").unwrap_or(&id);
41 Self(normalized.to_string())
42 }
43
44 pub fn as_str(&self) -> &str {
45 &self.0
46 }
47}
48
49impl_id_type!(SpeakerId);
50
51#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
55pub struct GroupId(String);
56
57impl GroupId {
58 pub fn new(id: impl Into<String>) -> Self {
59 Self(id.into())
60 }
61
62 pub fn as_str(&self) -> &str {
63 &self.0
64 }
65}
66
67impl_id_type!(GroupId);
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_speaker_id_strips_uuid_prefix() {
75 let id = SpeakerId::new("uuid:RINCON_123456789");
76 assert_eq!(id.as_str(), "RINCON_123456789");
77 }
78
79 #[test]
80 fn test_speaker_id_without_prefix() {
81 let id = SpeakerId::new("RINCON_123456789");
82 assert_eq!(id.as_str(), "RINCON_123456789");
83 }
84
85 #[test]
86 fn test_speaker_id_equality() {
87 let id1 = SpeakerId::new("uuid:RINCON_123");
88 let id2 = SpeakerId::new("RINCON_123");
89 assert_eq!(id1, id2);
90 }
91
92 #[test]
93 fn test_group_id() {
94 let id = GroupId::new("RINCON_123:0");
95 assert_eq!(id.as_str(), "RINCON_123:0");
96 }
97
98 #[test]
99 fn test_display() {
100 assert_eq!(format!("{}", SpeakerId::new("RINCON_123")), "RINCON_123");
101 assert_eq!(format!("{}", GroupId::new("RINCON_123:0")), "RINCON_123:0");
102 }
103}