1pub mod orderer;
2
3pub use orderer::{CausalOrderer, OrderedEnvelope};
4
5use uuid::Uuid;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub struct MessageId(Uuid);
10
11impl MessageId {
12 #[must_use]
14 pub fn new() -> Self {
15 Self(Uuid::new_v4())
16 }
17
18 #[must_use]
20 pub const fn from_uuid(uuid: Uuid) -> Self {
21 Self(uuid)
22 }
23
24 #[must_use]
26 pub const fn as_uuid(self) -> Uuid {
27 self.0
28 }
29}
30
31impl Default for MessageId {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct CausalContext {
40 pub parent: Option<MessageId>,
42 pub parent_chain: Vec<MessageId>,
44}
45
46impl CausalContext {
47 #[must_use]
49 pub const fn root() -> Self {
50 Self {
51 parent: None,
52 parent_chain: Vec::new(),
53 }
54 }
55
56 #[must_use]
67 pub fn child_of(parent: MessageId) -> Self {
68 Self::from_parent_chain(vec![parent])
69 }
70
71 #[must_use]
73 pub fn child_of_context(parent: MessageId, parent_context: &Self) -> Self {
74 let mut parent_chain = Vec::with_capacity(parent_context.parent_chain.len() + 1);
75 parent_chain.push(parent);
76 parent_chain.extend_from_slice(&parent_context.parent_chain);
77 Self::from_parent_chain(parent_chain)
78 }
79
80 #[must_use]
82 pub fn from_parent_chain(parent_chain: Vec<MessageId>) -> Self {
83 let parent = parent_chain.first().copied();
84 Self {
85 parent,
86 parent_chain,
87 }
88 }
89
90 #[must_use]
92 pub fn parent_chain(&self) -> &[MessageId] {
93 &self.parent_chain
94 }
95
96 #[must_use]
98 pub fn happened_before(&self, ancestor_id: MessageId) -> bool {
99 self.parent_chain.contains(&ancestor_id)
100 }
101}
102
103impl Default for CausalContext {
104 fn default() -> Self {
105 Self::root()
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::{CausalContext, MessageId};
112
113 #[test]
114 fn root_context_has_no_parent() {
115 assert_eq!(CausalContext::root().parent, None);
116 assert!(CausalContext::root().parent_chain().is_empty());
117 }
118
119 #[test]
120 fn child_context_carries_parent_reference() {
121 let parent = MessageId::new();
122 let context = CausalContext::child_of(parent);
123
124 assert_eq!(context.parent, Some(parent));
125 assert_eq!(context.parent_chain(), &[parent]);
126 }
127
128 #[test]
129 fn generated_message_ids_are_unique() {
130 let first = MessageId::new();
131 let second = MessageId::new();
132
133 assert_ne!(first, second);
134 }
135
136 #[test]
137 fn happened_before_follows_full_parent_chain() {
138 let a_id = MessageId::new();
139 let a_context = CausalContext::root();
140
141 let b_id = MessageId::new();
142 let b_context = CausalContext::child_of(a_id);
143
144 let c_id = MessageId::new();
145 let c_context = CausalContext::child_of_context(b_id, &b_context);
146
147 let d_context = CausalContext::root();
148
149 assert!(c_context.happened_before(a_id));
150 assert!(c_context.happened_before(b_id));
151 assert_eq!(c_context.parent_chain(), &[b_id, a_id]);
152 assert!(!a_context.happened_before(c_id));
153 assert!(!d_context.happened_before(a_id));
154 }
155}