1use std::cmp::Ordering;
4use std::collections::HashSet;
5use std::default::Default;
6use std::str::FromStr;
7
8use uuid::UUID;
9
10use crate::{Atom, Frame, FrameOrd, Op, Terminator, CRDT};
11
12pub struct Set;
18
19impl Set {
20 pub fn insert<'a>(state: &Frame<'a>, value: Atom) -> Option<Frame<'a>> {
22 state.peek().map(|op| {
23 let &Op { ref ty, ref object, .. } = op;
24
25 Frame::compress(vec![Op {
26 ty: ty.clone(),
27 object: object.clone(),
28 event: UUID::now(),
29 location: UUID::zero(),
30 atoms: vec![value].into(),
31 term: Terminator::Raw,
32 }])
33 })
34 }
35
36 pub fn remove<'a>(state: Frame<'a>, value: &Atom) -> Option<Frame<'a>> {
39 Some(Frame::compress(
40 state
41 .filter_map(|op| {
42 let Op { ty, object, event, location, atoms, .. } = op;
43
44 if atoms.get(0) == Some(value) && location.is_zero() {
45 Some(Op {
46 ty: ty,
47 object: object,
48 event: UUID::now(),
49 location: event,
50 atoms: Default::default(),
51 term: Terminator::Raw,
52 })
53 } else {
54 None
55 }
56 })
57 .collect::<Vec<_>>(),
58 ))
59 }
60}
61
62impl CRDT for Set {
63 type T = HashSet<Atom>;
64
65 fn new<'a>(obj: UUID) -> Frame<'a> {
66 Frame::compress(vec![Op {
67 ty: UUID::from_str("set").unwrap(),
68 object: obj,
69 event: UUID::now(),
70 location: UUID::zero(),
71 atoms: Default::default(),
72 term: Terminator::Header,
73 }])
74 }
75
76 fn reduce<'a>(
77 state: Frame<'a>, updates: Vec<Frame<'a>>,
78 ) -> Option<Frame<'a>> {
79 super::merge::<SetOrd>(state, updates)
80 }
81
82 fn map<'a>(state: Frame<'a>) -> Option<Self::T> {
83 use crate::Terminator::*;
84 use std::iter::FromIterator;
85
86 Some(HashSet::from_iter(state.filter_map(|mut op| {
87 match op {
88 Op { term: Header, .. } | Op { term: Query, .. } => None,
89 Op { ref location, ref mut atoms, .. }
90 if location.is_zero() && atoms.len() == 1 =>
91 {
92 Some(atoms.pop().unwrap())
93 }
94 Op { .. } => None,
95 }
96 })))
97 }
98}
99
100#[derive(Debug)]
101struct SetOrd<'a>(Frame<'a>);
102
103impl<'a> FrameOrd<'a> for SetOrd<'a> {
104 fn primary_cmp(a: &Op, b: &Op) -> Ordering {
105 let a = if a.location.is_zero() { &a.event } else { &a.location };
106 let b = if b.location.is_zero() { &b.event } else { &b.location };
107 UUID::weak_cmp(b, a)
108 }
109
110 fn secondary_cmp(a: &Op, b: &Op) -> Ordering {
111 UUID::weak_cmp(&b.location, &a.location)
112 }
113
114 fn peek(&self) -> Option<&Op> {
115 self.0.peek()
116 }
117}
118
119impl<'a> Iterator for SetOrd<'a> {
120 type Item = Op;
121
122 fn next(&mut self) -> Option<Op> {
123 self.0.next()
124 }
125}
126
127impl<'a> From<Frame<'a>> for SetOrd<'a> {
128 fn from(frame: Frame<'a>) -> Self {
129 SetOrd(frame)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn set_basic_1() {
139 let f1 = Frame::parse("*set#test1@1=1;");
140 let f2 = Frame::parse("*set#test1@2=2;");
141 let exp = Frame::parse("*set#test1@2:0!:0=2@1=1");
142 let r = Set::reduce(f1, vec![f2]).unwrap();
143
144 eprintln!(
145 "expected: {:?}",
146 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
147 );
148 eprintln!(
149 " got: {:?}",
150 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
151 );
152 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
153 }
154
155 #[test]
156 fn set_basic_2() {
157 let f1 = Frame::parse("*set#test2@1!@=1");
158 let f2 = Frame::parse("*set#test2@2:1;");
159 let exp = Frame::parse("*set#test2@2!:1,");
160 let r = Set::reduce(f1, vec![f2]).unwrap();
161
162 eprintln!(
163 "expected: {:?}",
164 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
165 );
166 eprintln!(
167 " got: {:?}",
168 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
169 );
170 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
171 }
172
173 #[test]
174 fn set_basic_3() {
175 let f1 = Frame::parse("*set#test3@3:1;");
176 let f2 = Frame::parse("*set#test3@4:2;");
177 let exp = Frame::parse("*set#test3@4:3!:2,@3:1,");
178 let r = Set::reduce(f1, vec![f2]).unwrap();
179
180 eprintln!(
181 "expected: {:?}",
182 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
183 );
184 eprintln!(
185 " got: {:?}",
186 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
187 );
188 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
189 }
190
191 #[test]
192 fn set_basic_4() {
193 let f1 = Frame::parse("*set#test4@2:0!@=2@1=1");
194 let f2 = Frame::parse("*set#test4@5!@=5@3:2,@4:1,");
195 let exp = Frame::parse("*set#test4@5:0!@=5@3:2,@4:1,");
196 let r = Set::reduce(f1, vec![f2]).unwrap();
197
198 eprintln!(
199 "expected: {:?}",
200 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
201 );
202 eprintln!(
203 " got: {:?}",
204 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
205 );
206 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
207 }
208
209 #[test]
210 fn set_basic_5() {
211 let f1 = Frame::parse("*set#test5@2:0!@=2@1=1");
212 let f2 = Frame::parse("*set#test5@4!@3:2,@4:1,");
213 let f3 = Frame::parse("*set#test5@5:0!@=5");
214 let exp = Frame::parse("*set#test5@5:0!@5=5@3:2,@4:1,");
215 let r = Set::reduce(f1, vec![f2, f3]).unwrap();
216
217 eprintln!(
218 "expected: {:?}",
219 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
220 );
221 eprintln!(
222 " got: {:?}",
223 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
224 );
225 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
226 }
227
228 #[test]
229 fn set_basic_6() {
230 let f1 = Frame::parse("*set#test6@3!@:2,@4:1,");
231 let f2 = Frame::parse("*set#test6@5:0!@=5");
232 let f3 = Frame::parse("*set#test6@2!@=2@1=1");
233 let exp = Frame::parse("*set#test6@5:0!@5=5@3:2,@4:1,");
234 let r = Set::reduce(f1, vec![f2, f3]).unwrap();
235
236 eprintln!(
237 "expected: {:?}",
238 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
239 );
240 eprintln!(
241 " got: {:?}",
242 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
243 );
244 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
245 }
246
247 #[test]
248 fn set_basic_7() {
249 let f1 = Frame::parse("*set#mice@1YKDY54a01+1YKDY5!@>mouse$1YKDY5");
250 let f2 = Frame::parse("*set#mice@1YKDXO3201+1YKDXO!@>mouse$1YKDXO@(WBF901(WBY>mouse$1YKDWBY@[67H01[6>mouse$1YKDW6@(Uh4j01(Uh>mouse$1YKDUh@(S67V01(S6>mouse$1YKDS6@(Of(N3:1YKDN3DS01+1YKDN3,@(MvBV01(IuJ:0>mouse$1YKDIuJ@(LF:1YKDIuEY01+1YKDIuJ,:{A601,@(Io5l01[oA:0>mouse$1YKDIoA@[l7_01[l>mouse$1YKDIl@(57(4B:1YKD4B3f01+1YKD4B,@(0bB401+1YKCsd:0>mouse$1YKCsd @1YKCu6+:1YKCsd7Q01+1YKCsd,");
251 let exp = Frame::parse("*set#mice@1YKDY54a01+1YKDY5!@(Y54a01(Y5>mouse$1YKDY5@(XO3201(XO>mouse$1YKDXO@(WBF901(WBY>mouse$1YKDWBY@[67H01[6>mouse$1YKDW6@(Uh4j01(Uh>mouse$1YKDUh@(S67V01(S6>mouse$1YKDS6@(Of(N3:1YKDN3DS01+1YKDN3,@(MvBV01(IuJ:0>mouse$1YKDIuJ@(LF:1YKDIuEY01+1YKDIuJ,:{A601,@(Io5l01[oA:0>mouse$1YKDIoA@[l7_01[l>mouse$1YKDIl@(57(4B:1YKD4B3f01+1YKD4B,@(0bB401+1YKCsd:0>mouse$1YKCsd @1YKCu6+:1YKCsd7Q01+1YKCsd,");
252 let r = Set::reduce(f1, vec![f2]).unwrap();
253
254 eprintln!(
255 "expected: {:#?}",
256 exp.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
257 );
258 eprintln!(
259 " got: {:#?}",
260 r.clone().map(|x| format!("{} ", x)).collect::<Vec<_>>()
261 );
262 assert_eq!(exp.collect::<Vec<_>>(), r.collect::<Vec<_>>());
263 }
264
265 #[test]
266 fn map_basic_7() {
267 use std::str::FromStr;
268
269 let frm = Frame::parse("*set#mice@1YKDY54a01+1YKDY5!@(Y54a01(Y5>mouse$1YKDY5@(XO3201(XO>mouse$1YKDXO@(WBF901(WBY>mouse$1YKDWBY@[67H01[6>mouse$1YKDW6@(Uh4j01(Uh>mouse$1YKDUh@(S67V01(S6>mouse$1YKDS6@(Of(N3:1YKDN3DS01+1YKDN3,@(MvBV01(IuJ:0>mouse$1YKDIuJ@(LF:1YKDIuEY01+1YKDIuJ,:{A601,@(Io5l01[oA:0>mouse$1YKDIoA@[l7_01[l>mouse$1YKDIl@(57(4B:1YKD4B3f01+1YKD4B,@(0bB401+1YKCsd:0>mouse$1YKCsd@1YKCu6+:1YKCsd7Q01+1YKCsd,");
270 let r = Set::map(frm).unwrap();
271 let mut exp = HashSet::default();
272
273 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDY5").unwrap()));
274 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDXO").unwrap()));
275 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDWBY").unwrap()));
276 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDW6").unwrap()));
277 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDUh").unwrap()));
278 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDS6").unwrap()));
279 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDIuJ").unwrap()));
280 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDIoA").unwrap()));
281 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKDIl").unwrap()));
282 exp.insert(Atom::UUID(UUID::from_str("mouse$1YKCsd").unwrap()));
283
284 assert_eq!(exp, r);
285 }
286
287 #[test]
288 fn map_empty() {
289 let frm = Set::new(UUID::now());
290 let r = Set::map(frm).unwrap();
291 let exp = HashSet::default();
292
293 assert_eq!(exp, r);
294 }
295
296 #[test]
297 fn map_insert_remove() {
298 use std::iter::FromIterator;
299
300 let st0 = Set::new(UUID::now());
302 let exp0 = HashSet::default();
303 assert_eq!(exp0, Set::map(st0.clone()).unwrap());
304
305 let ch1 = Set::insert(&st0, Atom::Integer(1)).unwrap();
307 let st1 = Set::reduce(st0, vec![ch1]).unwrap();
308 let exp1 = HashSet::from_iter(vec![Atom::Integer(1)].into_iter());
309 assert_eq!(exp1, Set::map(st1.clone()).unwrap());
310
311 let ch2 = Set::insert(&st1, Atom::Integer(1)).unwrap();
313 let st2 = Set::reduce(st1, vec![ch2]).unwrap();
314 let exp2 = HashSet::from_iter(vec![Atom::Integer(1)].into_iter());
315 assert_eq!(exp2, Set::map(st2.clone()).unwrap());
316
317 let ch3 = Set::insert(&st2, Atom::Integer(2)).unwrap();
319 let st3 = Set::reduce(st2, vec![ch3]).unwrap();
320 let exp3 = HashSet::from_iter(
321 vec![Atom::Integer(1), Atom::Integer(2)].into_iter(),
322 );
323 assert_eq!(exp3, Set::map(st3.clone()).unwrap());
324
325 let ch4 = Set::remove(st3.clone(), &Atom::Integer(1)).unwrap();
327 let st4 = Set::reduce(st3, vec![ch4]).unwrap();
328 let exp4 = HashSet::from_iter(vec![Atom::Integer(2)].into_iter());
329 assert_eq!(exp4, Set::map(st4.clone()).unwrap());
330
331 let ch5 = Set::insert(&st4, Atom::Integer(1)).unwrap();
333 let st5 = Set::reduce(st4, vec![ch5]).unwrap();
334 let exp5 = HashSet::from_iter(
335 vec![Atom::Integer(1), Atom::Integer(2)].into_iter(),
336 );
337 assert_eq!(exp5, Set::map(st5.clone()).unwrap());
338
339 let ch6 = Set::remove(st5.clone(), &Atom::Integer(1)).unwrap();
341 let st6 = Set::reduce(st5, vec![ch6]).unwrap();
342 let exp6 = HashSet::from_iter(vec![Atom::Integer(2)].into_iter());
343 eprintln!("{:?}", st6);
344 assert_eq!(exp6, Set::map(st6.clone()).unwrap());
345
346 let ch7 = Set::remove(st6.clone(), &Atom::Integer(2)).unwrap();
348 let st7 = Set::reduce(st6, vec![ch7]).unwrap();
349 let exp7 = HashSet::default();
350 assert_eq!(exp7, Set::map(st7).unwrap());
351 }
352}