1use std::collections::HashMap;
6
7use serde::{Deserialize, Serialize};
8
9pub trait Message {
15 fn name(&self) -> &'static str;
17}
18
19pub type Metadata = HashMap<String, String>;
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Envelope<T>
29where
30 T: Message,
31{
32 pub message: T,
34 pub metadata: Metadata,
36}
37
38impl<T> Envelope<T>
39where
40 T: Message,
41{
42 #[must_use]
44 pub fn with_metadata(mut self, key: String, value: String) -> Self {
45 self.metadata.insert(key, value);
46 self
47 }
48}
49
50impl<T> From<T> for Envelope<T>
51where
52 T: Message,
53{
54 fn from(message: T) -> Self {
55 Envelope {
56 message,
57 metadata: Metadata::default(),
58 }
59 }
60}
61
62impl<T> PartialEq for Envelope<T>
63where
64 T: Message + PartialEq,
65{
66 fn eq(&self, other: &Envelope<T>) -> bool {
67 self.message == other.message
68 }
69}
70
71#[cfg(test)]
72pub(crate) mod tests {
73 use super::*;
74
75 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
76 pub(crate) struct StringMessage(pub(crate) &'static str);
77
78 impl Message for StringMessage {
79 fn name(&self) -> &'static str {
80 "string_payload"
81 }
82 }
83
84 #[test]
85 fn message_with_metadata_does_not_affect_equality() {
86 let message = Envelope {
87 message: StringMessage("hello"),
88 metadata: Metadata::default(),
89 };
90
91 let new_message = message
92 .clone()
93 .with_metadata("hello_world".into(), "test".into())
94 .with_metadata("test_number".into(), 1.to_string());
95
96 println!("Message: {message:?}");
97 println!("New message: {new_message:?}");
98
99 assert_eq!(message, new_message);
101 }
102}