emergent_client/types/
message_id.rs1use mti::prelude::*;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6use std::str::FromStr;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct MessageId(MagicTypeId);
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum InvalidMessageId {
20 Parse(MagicTypeIdError),
22 WrongPrefix {
24 expected: &'static str,
25 actual: String,
26 },
27}
28
29impl fmt::Display for InvalidMessageId {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::Parse(e) => write!(f, "invalid message ID: {e}"),
33 Self::WrongPrefix { expected, actual } => {
34 write!(f, "expected prefix '{expected}', got '{actual}'")
35 }
36 }
37 }
38}
39
40impl std::error::Error for InvalidMessageId {}
41
42impl MessageId {
43 pub const PREFIX: &'static str = "msg";
45
46 #[must_use]
48 pub fn new() -> Self {
49 Self(Self::PREFIX.create_type_id::<V7>())
50 }
51
52 pub fn parse(s: &str) -> Result<Self, InvalidMessageId> {
58 let id = MagicTypeId::from_str(s).map_err(InvalidMessageId::Parse)?;
59
60 if id.prefix().as_str() != Self::PREFIX {
61 return Err(InvalidMessageId::WrongPrefix {
62 expected: Self::PREFIX,
63 actual: id.prefix().as_str().to_string(),
64 });
65 }
66
67 Ok(Self(id))
68 }
69
70 #[must_use]
72 pub fn inner(&self) -> &MagicTypeId {
73 &self.0
74 }
75
76 #[must_use]
78 pub fn suffix(&self) -> String {
79 self.0.suffix().to_string()
80 }
81}
82
83impl Default for MessageId {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89impl fmt::Display for MessageId {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "{}", self.0)
92 }
93}
94
95impl FromStr for MessageId {
96 type Err = InvalidMessageId;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 Self::parse(s)
100 }
101}
102
103impl AsRef<MagicTypeId> for MessageId {
104 fn as_ref(&self) -> &MagicTypeId {
105 &self.0
106 }
107}
108
109impl Serialize for MessageId {
110 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
111 where
112 S: Serializer,
113 {
114 self.0.to_string().serialize(serializer)
115 }
116}
117
118impl<'de> Deserialize<'de> for MessageId {
119 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
120 where
121 D: Deserializer<'de>,
122 {
123 let s = String::deserialize(deserializer)?;
124 Self::parse(&s).map_err(serde::de::Error::custom)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn new_creates_valid_message_id() {
134 let id = MessageId::new();
135 assert!(id.to_string().starts_with("msg_"));
136 }
137
138 #[test]
139 fn parse_valid_message_id() {
140 let id_str = MessageId::new().to_string();
141 let parsed = MessageId::parse(&id_str);
142 assert!(parsed.is_ok());
143 }
144
145 #[test]
146 fn parse_wrong_prefix_fails() {
147 let result = MessageId::parse("cor_01h455vb4pex5vsknk084sn02q");
148 assert!(matches!(
149 result,
150 Err(InvalidMessageId::WrongPrefix {
151 expected: "msg",
152 ..
153 })
154 ));
155 }
156
157 #[test]
158 fn parse_invalid_format_fails() {
159 let result = MessageId::parse("not-a-valid-typeid");
160 assert!(matches!(result, Err(InvalidMessageId::Parse(_))));
161 }
162
163 #[test]
164 fn message_ids_are_unique() {
165 let id1 = MessageId::new();
166 let id2 = MessageId::new();
167 assert_ne!(id1, id2);
168 }
169
170 #[test]
171 fn display_format() {
172 let id = MessageId::new();
173 let s = id.to_string();
174 assert!(s.starts_with("msg_"));
175 assert_eq!(s.len(), 30); }
177
178 #[test]
179 fn serde_roundtrip() -> Result<(), serde_json::Error> {
180 let id = MessageId::new();
181 let json = serde_json::to_string(&id)?;
182 let restored: MessageId = serde_json::from_str(&json)?;
183 assert_eq!(id, restored);
184 Ok(())
185 }
186
187 #[test]
188 fn from_str_works() -> Result<(), InvalidMessageId> {
189 let id = MessageId::new();
190 let s = id.to_string();
191 let parsed: MessageId = s.parse()?;
192 assert_eq!(id, parsed);
193 Ok(())
194 }
195}