unifly_api/model/
entity_id.rs1use serde::{Deserialize, Serialize};
8use std::fmt;
9use std::str::FromStr;
10use uuid::Uuid;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[serde(untagged)]
20pub enum EntityId {
21 Uuid(Uuid),
22 Legacy(String),
23}
24
25impl EntityId {
26 pub fn as_uuid(&self) -> Option<&Uuid> {
27 match self {
28 Self::Uuid(u) => Some(u),
29 Self::Legacy(_) => None,
30 }
31 }
32
33 pub fn as_legacy(&self) -> Option<&str> {
34 match self {
35 Self::Legacy(s) => Some(s),
36 Self::Uuid(_) => None,
37 }
38 }
39}
40
41impl fmt::Display for EntityId {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::Uuid(u) => write!(f, "{u}"),
45 Self::Legacy(s) => write!(f, "{s}"),
46 }
47 }
48}
49
50impl FromStr for EntityId {
51 type Err = std::convert::Infallible;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 Ok(Self::from(s.to_owned()))
55 }
56}
57
58impl From<Uuid> for EntityId {
59 fn from(u: Uuid) -> Self {
60 Self::Uuid(u)
61 }
62}
63
64impl From<String> for EntityId {
65 fn from(s: String) -> Self {
66 match Uuid::parse_str(&s) {
67 Ok(u) => Self::Uuid(u),
68 Err(_) => Self::Legacy(s),
69 }
70 }
71}
72
73impl From<&str> for EntityId {
74 fn from(s: &str) -> Self {
75 Self::from(s.to_owned())
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub struct MacAddress(String);
84
85impl MacAddress {
86 pub fn new(raw: impl AsRef<str>) -> Self {
89 let normalized = raw.as_ref().to_lowercase().replace('-', ":");
90 Self(normalized)
91 }
92
93 pub fn as_str(&self) -> &str {
94 &self.0
95 }
96}
97
98impl fmt::Display for MacAddress {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(f, "{}", self.0)
101 }
102}
103
104impl FromStr for MacAddress {
105 type Err = std::convert::Infallible;
106
107 fn from_str(s: &str) -> Result<Self, Self::Err> {
108 Ok(Self::new(s))
109 }
110}
111
112#[cfg(test)]
113#[allow(clippy::unwrap_used)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn entity_id_from_uuid_string() {
119 let id = EntityId::from("550e8400-e29b-41d4-a716-446655440000".to_owned());
120 assert!(id.as_uuid().is_some());
121 }
122
123 #[test]
124 fn entity_id_from_legacy_string() {
125 let id = EntityId::from("507f1f77bcf86cd799439011".to_owned());
126 assert!(id.as_legacy().is_some());
127 }
128
129 #[test]
130 fn entity_id_display() {
131 let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
132 let id = EntityId::Uuid(uuid);
133 assert_eq!(id.to_string(), "550e8400-e29b-41d4-a716-446655440000");
134 }
135
136 #[test]
137 fn entity_id_from_str() {
138 let id: EntityId = "507f1f77bcf86cd799439011".parse().unwrap();
139 assert!(id.as_legacy().is_some());
140 }
141
142 #[test]
143 fn mac_address_normalizes_dashes() {
144 let mac = MacAddress::new("AA-BB-CC-DD-EE-FF");
145 assert_eq!(mac.as_str(), "aa:bb:cc:dd:ee:ff");
146 }
147
148 #[test]
149 fn mac_address_normalizes_case() {
150 let mac = MacAddress::new("AA:BB:CC:DD:EE:FF");
151 assert_eq!(mac.as_str(), "aa:bb:cc:dd:ee:ff");
152 }
153
154 #[test]
155 fn mac_address_from_str() {
156 let mac: MacAddress = "AA-BB-CC-DD-EE-FF".parse().unwrap();
157 assert_eq!(mac.to_string(), "aa:bb:cc:dd:ee:ff");
158 }
159}