1use core::fmt;
4
5use crate::{
6 ContentType, ConversationId, CorrelationId, MessageId, RequestId,
7 ids::{IdError, contains_control_char},
8};
9
10#[derive(Clone, Debug, Default, PartialEq)]
13#[non_exhaustive]
14pub struct Metadata {
15 pub correlation: CorrelationMetadata,
17 pub trace: TraceContext,
19 pub routing: RoutingMetadata,
21 pub delivery: DeliveryMetadata,
23 pub tenant_id: Option<String>,
25}
26
27#[derive(Clone, Debug, PartialEq)]
29#[non_exhaustive]
30pub struct CorrelationMetadata {
31 pub correlation_id: Option<CorrelationId>,
33 pub conversation_id: ConversationId,
35 pub causation_id: Option<MessageId>,
37 pub request_id: Option<RequestId>,
39}
40
41impl Default for CorrelationMetadata {
48 fn default() -> Self {
49 Self {
50 correlation_id: None,
51 conversation_id: ConversationId::UNSET,
52 causation_id: None,
53 request_id: None,
54 }
55 }
56}
57
58#[derive(Clone, Debug, Default, PartialEq, Eq)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63#[non_exhaustive]
64pub struct TraceContext {
65 pub traceparent: Option<String>,
67 pub tracestate: Option<String>,
69}
70
71#[derive(Clone, Debug, Default, PartialEq, Eq)]
74#[non_exhaustive]
75pub struct RoutingMetadata {
76 pub source: Option<EndpointAddress>,
78 pub destination: Option<EndpointAddress>,
80 pub reply_to: Option<EndpointAddress>,
82}
83
84#[derive(Clone, Debug, PartialEq, Eq, Hash)]
87pub struct EndpointAddress(String);
88
89impl EndpointAddress {
90 pub const MAX_LEN: usize = 256;
92
93 pub fn parse(s: impl Into<String>) -> Result<Self, IdError> {
101 let s = s.into();
102 if s.is_empty() {
103 return Err(IdError::Empty);
104 }
105 if contains_control_char(&s) {
106 return Err(IdError::ControlCharacter);
107 }
108 if s.len() > Self::MAX_LEN {
109 return Err(IdError::TooLong {
110 len: s.len(),
111 max: Self::MAX_LEN,
112 });
113 }
114 Ok(Self(s))
115 }
116
117 #[must_use]
119 pub fn as_str(&self) -> &str {
120 &self.0
121 }
122}
123
124impl fmt::Display for EndpointAddress {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.write_str(&self.0)
127 }
128}
129
130#[cfg(feature = "serde")]
131impl serde::Serialize for EndpointAddress {
132 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
133 s.collect_str(&self.0)
134 }
135}
136
137#[cfg(feature = "serde")]
138impl<'de> serde::Deserialize<'de> for EndpointAddress {
139 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
140 let raw = String::deserialize(d)?;
141 Self::parse(raw).map_err(serde::de::Error::custom)
142 }
143}
144
145#[derive(Clone, Debug, PartialEq)]
147#[non_exhaustive]
148pub struct DeliveryMetadata {
149 pub content_type: ContentType,
153 pub sent_at: Option<time::OffsetDateTime>,
156 pub expires_at: Option<time::OffsetDateTime>,
160 pub deduplication_id: Option<String>,
163}
164
165impl Default for DeliveryMetadata {
166 fn default() -> Self {
167 Self {
168 content_type: ContentType::JSON,
169 sent_at: None,
170 expires_at: None,
171 deduplication_id: None,
172 }
173 }
174}
175
176#[cfg(feature = "serde")]
177mod serde_impls {
178 use serde::{Deserialize, Serialize};
183
184 use super::{CorrelationMetadata, DeliveryMetadata, Metadata, RoutingMetadata, TraceContext};
185
186 #[derive(Serialize, Deserialize)]
191 #[serde(remote = "Metadata")]
192 struct MetadataDef {
193 #[serde(default)]
194 correlation: CorrelationMetadata,
195 #[serde(default)]
196 trace: TraceContext,
197 #[serde(default)]
198 routing: RoutingMetadata,
199 #[serde(default)]
200 delivery: DeliveryMetadata,
201 #[serde(default)]
202 tenant_id: Option<String>,
203 }
204
205 impl Serialize for Metadata {
206 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
207 MetadataDef::serialize(self, s)
208 }
209 }
210 impl<'de> Deserialize<'de> for Metadata {
211 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
212 MetadataDef::deserialize(d)
213 }
214 }
215
216 impl Serialize for CorrelationMetadata {
217 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
218 #[derive(Serialize)]
220 #[allow(clippy::struct_field_names)]
221 struct Def<'a> {
222 correlation_id: &'a Option<super::CorrelationId>,
223 conversation_id: &'a super::ConversationId,
224 causation_id: &'a Option<super::MessageId>,
225 request_id: &'a Option<super::RequestId>,
226 }
227 Def {
228 correlation_id: &self.correlation_id,
229 conversation_id: &self.conversation_id,
230 causation_id: &self.causation_id,
231 request_id: &self.request_id,
232 }
233 .serialize(s)
234 }
235 }
236 impl<'de> Deserialize<'de> for CorrelationMetadata {
237 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
238 fn default_conversation_id() -> super::ConversationId {
244 super::ConversationId::UNSET
245 }
246
247 #[derive(Deserialize)]
248 #[allow(clippy::struct_field_names)]
249 struct Def {
250 #[serde(default)]
251 correlation_id: Option<super::CorrelationId>,
252 #[serde(default = "default_conversation_id")]
253 conversation_id: super::ConversationId,
254 #[serde(default)]
255 causation_id: Option<super::MessageId>,
256 #[serde(default)]
257 request_id: Option<super::RequestId>,
258 }
259 let def = Def::deserialize(d)?;
260 Ok(CorrelationMetadata {
261 correlation_id: def.correlation_id,
262 conversation_id: def.conversation_id,
263 causation_id: def.causation_id,
264 request_id: def.request_id,
265 })
266 }
267 }
268
269 impl Serialize for RoutingMetadata {
270 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
271 #[derive(Serialize)]
272 struct Def<'a> {
273 source: &'a Option<super::EndpointAddress>,
274 destination: &'a Option<super::EndpointAddress>,
275 reply_to: &'a Option<super::EndpointAddress>,
276 }
277 Def {
278 source: &self.source,
279 destination: &self.destination,
280 reply_to: &self.reply_to,
281 }
282 .serialize(s)
283 }
284 }
285 impl<'de> Deserialize<'de> for RoutingMetadata {
286 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
287 #[derive(Deserialize)]
288 struct Def {
289 #[serde(default)]
290 source: Option<super::EndpointAddress>,
291 #[serde(default)]
292 destination: Option<super::EndpointAddress>,
293 #[serde(default)]
294 reply_to: Option<super::EndpointAddress>,
295 }
296 let def = Def::deserialize(d)?;
297 Ok(RoutingMetadata {
298 source: def.source,
299 destination: def.destination,
300 reply_to: def.reply_to,
301 })
302 }
303 }
304
305 impl Serialize for DeliveryMetadata {
306 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
307 #[derive(Serialize)]
308 struct Def<'a> {
309 content_type: &'a super::ContentType,
310 #[serde(with = "time::serde::rfc3339::option")]
311 sent_at: &'a Option<time::OffsetDateTime>,
312 #[serde(with = "time::serde::rfc3339::option")]
313 expires_at: &'a Option<time::OffsetDateTime>,
314 deduplication_id: &'a Option<String>,
315 }
316 Def {
317 content_type: &self.content_type,
318 sent_at: &self.sent_at,
319 expires_at: &self.expires_at,
320 deduplication_id: &self.deduplication_id,
321 }
322 .serialize(s)
323 }
324 }
325 impl<'de> Deserialize<'de> for DeliveryMetadata {
326 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
327 fn default_content_type() -> super::ContentType {
331 super::ContentType::JSON
332 }
333
334 #[derive(Deserialize)]
335 struct Def {
336 #[serde(default = "default_content_type")]
337 content_type: super::ContentType,
338 #[serde(default, with = "time::serde::rfc3339::option")]
339 sent_at: Option<time::OffsetDateTime>,
340 #[serde(default, with = "time::serde::rfc3339::option")]
341 expires_at: Option<time::OffsetDateTime>,
342 #[serde(default)]
343 deduplication_id: Option<String>,
344 }
345 let def = Def::deserialize(d)?;
346 Ok(DeliveryMetadata {
347 content_type: def.content_type,
348 sent_at: def.sent_at,
349 expires_at: def.expires_at,
350 deduplication_id: def.deduplication_id,
351 })
352 }
353 }
354}