rings_core/dht/entry/
crdt.rs1use std::collections::BTreeMap;
21use std::collections::BTreeSet;
22
23use serde::Deserialize;
24use serde::Serialize;
25
26use crate::algebra::JoinSemilattice;
27use crate::dht::Did;
28use crate::error::Error;
29use crate::error::Result;
30use crate::message::Encoded;
31
32#[derive(
39 Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
40)]
41pub struct EntryVersion {
42 #[serde(alias = "epoch_ms")]
44 pub logical_time_ms: u128,
45 pub actor: Did,
47 #[serde(default)]
49 pub operation: Did,
50}
51
52impl EntryVersion {
53 pub fn new(logical_time_ms: u128, actor: Did, operation: Did) -> Self {
55 Self {
56 logical_time_ms,
57 actor,
58 operation,
59 }
60 }
61
62 pub fn issued_by(actor: Did, operation: Did) -> Self {
64 Self::new(crate::utils::get_epoch_ms(), actor, operation)
65 }
66
67 pub(super) fn after(self, floor: Option<Self>) -> Self {
68 let Some(floor) = floor else {
69 return self;
70 };
71 if self > floor {
72 return self;
73 }
74 Self {
75 logical_time_ms: floor.logical_time_ms.saturating_add(1),
76 actor: self.actor,
77 operation: self.operation,
78 }
79 }
80}
81
82#[derive(
84 Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
85)]
86pub struct EntryDot {
87 pub version: EntryVersion,
89 pub index: u32,
91}
92
93impl EntryDot {
94 pub(super) fn for_index(version: EntryVersion, index: usize) -> Result<Self> {
95 let index = u32::try_from(index).map_err(|_| Error::EntryDotIndexOutOfBounds { index })?;
96 Ok(Self { version, index })
97 }
98}
99
100#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
106pub struct EntryCrdt {
107 pub register: Option<EntryVersion>,
109 pub dots: Vec<EntryDot>,
112 pub tombstones: Vec<EntryDot>,
114}
115
116impl EntryCrdt {
117 pub(super) fn has_write_witness(&self) -> bool {
118 self.register.is_some() || !self.dots.is_empty()
119 }
120
121 pub(super) fn legacy_floor(&self) -> EntryVersion {
123 self.register.unwrap_or_default()
124 }
125}
126
127#[derive(Clone, Debug, Default, PartialEq, Eq)]
129pub struct DataTopicBuffer {
130 pub(super) register: Option<EntryVersion>,
131 pub(super) values: BTreeMap<Encoded, EntryDot>,
132 pub(super) removes: BTreeSet<EntryDot>,
133}
134
135impl DataTopicBuffer {
136 pub(super) fn new(
137 register: Option<EntryVersion>,
138 mut values: BTreeMap<Encoded, EntryDot>,
139 mut removes: BTreeSet<EntryDot>,
140 ) -> Self {
141 if let Some(floor) = register {
142 values.retain(|_, dot| dot.version >= floor);
143 removes.retain(|dot| dot.version >= floor);
144 }
145 values.retain(|_, dot| !removes.contains(dot));
146 Self {
147 register,
148 values,
149 removes,
150 }
151 }
152}
153
154impl JoinSemilattice for DataTopicBuffer {
155 fn join(mut self, other: Self) -> Self {
156 self.register = self.register.max(other.register);
157 self.removes.extend(other.removes);
158 for (value, dot) in other.values {
159 self.values
160 .entry(value)
161 .and_modify(|current| *current = (*current).max(dot))
162 .or_insert(dot);
163 }
164 Self::new(self.register, self.values, self.removes)
165 }
166}
167
168#[derive(Clone, Debug, Default, PartialEq, Eq)]
170pub struct RelayMessageSet {
171 pub(super) adds: DataTopicBuffer,
172 pub(super) removes: BTreeSet<EntryDot>,
173}
174
175impl RelayMessageSet {
176 pub(super) fn new(mut adds: DataTopicBuffer, removes: BTreeSet<EntryDot>) -> Self {
177 let mut removes = removes;
178 removes.extend(adds.removes.iter().copied());
179 adds = DataTopicBuffer::new(adds.register, adds.values, removes.clone());
180 Self { adds, removes }
181 }
182}
183
184impl JoinSemilattice for RelayMessageSet {
185 fn join(mut self, other: Self) -> Self {
186 self.adds = self.adds.join(other.adds);
187 self.removes.extend(other.removes);
188 Self::new(self.adds, self.removes)
189 }
190}