1use crate::branch::btree_range_for_crdt;
9use crate::value::{Conflicted, CrdtId, Value};
10use crate::{OpLog, Primitive, ROOT_CRDT_ID, LV};
11
12pub struct MapRef<'a> {
17 oplog: &'a OpLog,
18 crdt_id: LV,
19}
20
21impl<'a> MapRef<'a> {
22 pub(crate) fn new(oplog: &'a OpLog, crdt_id: LV) -> Self {
23 Self { oplog, crdt_id }
24 }
25
26 pub fn id(&self) -> CrdtId {
28 CrdtId(self.crdt_id)
29 }
30
31 pub fn is_root(&self) -> bool {
33 self.crdt_id == ROOT_CRDT_ID
34 }
35
36 pub fn get(&self, key: &str) -> Option<Value> {
41 let info = self.oplog.map_keys.get(&(self.crdt_id, key.into()))?;
42 let state = self.oplog.get_state_for_register(info);
43 Some(state.value.into())
44 }
45
46 pub fn get_conflicted(&self, key: &str) -> Option<Conflicted<Value>> {
50 let info = self.oplog.map_keys.get(&(self.crdt_id, key.into()))?;
51 let state = self.oplog.get_state_for_register(info);
52 Some(Conflicted {
53 value: state.value.into(),
54 conflicts: state.conflicts_with.into_iter().map(|rv| rv.into()).collect(),
55 })
56 }
57
58 pub fn contains_key(&self, key: &str) -> bool {
60 self.oplog.map_keys.contains_key(&(self.crdt_id, key.into()))
61 }
62
63 pub fn keys(&self) -> impl Iterator<Item = &str> {
65 btree_range_for_crdt(&self.oplog.map_keys, self.crdt_id)
66 .map(|((_, key), _)| key.as_str())
67 }
68
69 pub fn len(&self) -> usize {
71 btree_range_for_crdt(&self.oplog.map_keys, self.crdt_id).count()
72 }
73
74 pub fn is_empty(&self) -> bool {
76 self.len() == 0
77 }
78
79 pub fn get_map(&self, key: &str) -> Option<MapRef<'a>> {
81 let value = self.get(key)?;
82 match value {
83 Value::Map(id) => Some(MapRef::new(self.oplog, id.0)),
84 _ => None,
85 }
86 }
87
88 pub fn get_text(&self, key: &str) -> Option<TextRef<'a>> {
90 let value = self.get(key)?;
91 match value {
92 Value::Text(id) => Some(TextRef::new(self.oplog, id.0)),
93 _ => None,
94 }
95 }
96
97 pub fn get_set(&self, key: &str) -> Option<SetRef<'a>> {
99 let value = self.get(key)?;
100 match value {
101 Value::Set(id) => Some(SetRef::new(self.oplog, id.0)),
102 _ => None,
103 }
104 }
105
106 pub fn get_register(&self, key: &str) -> Option<RegisterRef<'a>> {
108 let value = self.get(key)?;
109 match value {
110 Value::Register(id) => Some(RegisterRef::new(self.oplog, id.0)),
111 _ => None,
112 }
113 }
114
115 pub fn iter(&self) -> impl Iterator<Item = (&str, Value)> + 'a {
117 btree_range_for_crdt(&self.oplog.map_keys, self.crdt_id)
118 .map(|((_, key), info)| {
119 let state = self.oplog.get_state_for_register(info);
120 (key.as_str(), state.value.into())
121 })
122 }
123
124 pub fn keys_owned(&self) -> Vec<String> {
126 self.keys().map(|s| s.to_string()).collect()
127 }
128
129 pub fn entries_owned(&self) -> Vec<(String, Value)> {
131 self.iter().map(|(k, v)| (k.to_string(), v)).collect()
132 }
133}
134
135pub struct TextRef<'a> {
141 oplog: &'a OpLog,
142 crdt_id: LV,
143}
144
145impl<'a> TextRef<'a> {
146 pub(crate) fn new(oplog: &'a OpLog, crdt_id: LV) -> Self {
147 Self { oplog, crdt_id }
148 }
149
150 pub fn id(&self) -> CrdtId {
152 CrdtId(self.crdt_id)
153 }
154
155 pub fn content(&self) -> String {
160 self.oplog.checkout_text(self.crdt_id).to_string()
161 }
162
163 pub fn slice(&self, range: std::ops::Range<usize>) -> String {
186 let rope = self.oplog.checkout_text(self.crdt_id);
187 let borrowed = rope.borrow();
188 borrowed.slice_chars(range).collect()
189 }
190
191 pub fn chars(&self) -> impl Iterator<Item = char> {
196 let rope = self.oplog.checkout_text(self.crdt_id);
200 let borrowed = rope.borrow();
201 borrowed.chars().collect::<Vec<_>>().into_iter()
202 }
203
204 pub fn len(&self) -> usize {
206 self.oplog.checkout_text(self.crdt_id).len_chars()
207 }
208
209 pub fn is_empty(&self) -> bool {
211 self.len() == 0
212 }
213}
214
215pub struct SetRef<'a> {
219 oplog: &'a OpLog,
220 crdt_id: LV,
221}
222
223impl<'a> SetRef<'a> {
224 pub(crate) fn new(oplog: &'a OpLog, crdt_id: LV) -> Self {
225 Self { oplog, crdt_id }
226 }
227
228 pub fn id(&self) -> CrdtId {
230 CrdtId(self.crdt_id)
231 }
232
233 pub fn contains(&self, value: &Value) -> bool {
235 let primitive: Primitive = value.clone().into();
236 let set_data = self.oplog.checkout_set(self.crdt_id);
237 set_data.contains(&primitive)
238 }
239
240 pub fn contains_str(&self, s: &str) -> bool {
242 let primitive = Primitive::Str(s.into());
243 let set_data = self.oplog.checkout_set(self.crdt_id);
244 set_data.contains(&primitive)
245 }
246
247 pub fn contains_int(&self, n: i64) -> bool {
249 let primitive = Primitive::I64(n);
250 let set_data = self.oplog.checkout_set(self.crdt_id);
251 set_data.contains(&primitive)
252 }
253
254 pub fn len(&self) -> usize {
256 self.oplog.checkout_set(self.crdt_id).len()
257 }
258
259 pub fn is_empty(&self) -> bool {
261 self.len() == 0
262 }
263
264 pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
266 self.oplog.checkout_set(self.crdt_id)
267 .into_iter()
268 .map(|p| p.into())
269 }
270
271 pub fn to_vec(&self) -> Vec<Value> {
273 self.iter().collect()
274 }
275}
276
277pub struct RegisterRef<'a> {
281 oplog: &'a OpLog,
282 crdt_id: LV,
283}
284
285impl<'a> RegisterRef<'a> {
286 pub(crate) fn new(oplog: &'a OpLog, crdt_id: LV) -> Self {
287 Self { oplog, crdt_id }
288 }
289
290 pub fn id(&self) -> CrdtId {
292 CrdtId(self.crdt_id)
293 }
294
295 pub fn get(&self) -> Option<Value> {
299 let state = self.oplog.checkout_register(self.crdt_id);
300 Some(state.value.into())
301 }
302
303 pub fn get_conflicted(&self) -> Option<Conflicted<Value>> {
305 let state = self.oplog.checkout_register(self.crdt_id);
306 Some(Conflicted {
307 value: state.value.into(),
308 conflicts: state.conflicts_with.into_iter().map(|rv| rv.into()).collect(),
309 })
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use uuid::Uuid;
316 use crate::Document;
317
318 #[test]
319 fn test_map_ref_basic() {
320 let mut doc = Document::new();
321 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
322
323 doc.transact(alice, |tx| {
324 tx.root().set("key", "value");
325 tx.root().set("num", 42);
326 });
327
328 let root = doc.root();
329 assert!(root.contains_key("key"));
330 assert!(!root.contains_key("missing"));
331
332 let val = root.get("key").unwrap();
333 assert_eq!(val.as_str(), Some("value"));
334
335 let num = root.get("num").unwrap();
336 assert_eq!(num.as_int(), Some(42));
337 }
338
339 #[test]
340 fn test_map_ref_nested() {
341 let mut doc = Document::new();
342 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
343
344 doc.transact(alice, |tx| {
345 tx.root().create_map("nested");
346 });
347
348 doc.transact(alice, |tx| {
349 if let Some(mut nested) = tx.get_map_mut(&["nested"]) {
350 nested.set("inner", "value");
351 }
352 });
353
354 let nested = doc.root().get_map("nested").unwrap();
355 let inner = nested.get("inner").unwrap();
356 assert_eq!(inner.as_str(), Some("value"));
357 }
358
359 #[test]
360 fn test_text_ref_slice() {
361 let mut doc = Document::new();
362 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
363
364 doc.transact(alice, |tx| {
365 let id = tx.root().create_text("content");
366 tx.text_by_id(id).unwrap().insert(0, "Hello, world!");
367 });
368
369 let text = doc.root().get_text("content").unwrap();
370
371 assert_eq!(text.content(), "Hello, world!");
373
374 assert_eq!(text.slice(0..5), "Hello");
376 assert_eq!(text.slice(7..12), "world");
377 assert_eq!(text.slice(0..0), "");
378 assert_eq!(text.slice(5..7), ", ");
379 }
380
381 #[test]
382 fn test_text_ref_slice_unicode() {
383 let mut doc = Document::new();
384 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
385
386 doc.transact(alice, |tx| {
387 let id = tx.root().create_text("emoji");
388 tx.text_by_id(id).unwrap().insert(0, "🎉🎊🎈");
390 });
391
392 let text = doc.root().get_text("emoji").unwrap();
393
394 assert_eq!(text.len(), 3);
396
397 assert_eq!(text.slice(0..1), "🎉");
399 assert_eq!(text.slice(1..2), "🎊");
400 assert_eq!(text.slice(2..3), "🎈");
401 }
402
403 #[test]
404 fn test_text_ref_chars() {
405 let mut doc = Document::new();
406 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
407
408 doc.transact(alice, |tx| {
409 let id = tx.root().create_text("content");
410 tx.text_by_id(id).unwrap().insert(0, "abc");
411 });
412
413 let text = doc.root().get_text("content").unwrap();
414 let chars: Vec<char> = text.chars().collect();
415
416 assert_eq!(chars, vec!['a', 'b', 'c']);
417 }
418
419 #[test]
420 fn test_map_ref_keys_owned() {
421 let mut doc = Document::new();
422 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
423
424 doc.transact(alice, |tx| {
425 tx.root().set("b", 2i64);
426 tx.root().set("a", 1i64);
427 tx.root().create_map("c");
428 });
429
430 let keys = doc.root().keys_owned();
431 assert_eq!(keys, vec!["a".to_string(), "b".to_string(), "c".to_string()]);
432 }
433
434 #[test]
435 fn test_map_ref_entries_owned() {
436 let mut doc = Document::new();
437 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
438
439 doc.transact(alice, |tx| {
440 tx.root().set("name", "Alice");
441 tx.root().set("age", 30i64);
442 });
443
444 let entries = doc.root().entries_owned();
445 assert_eq!(entries.len(), 2);
446
447 assert_eq!(entries[0].0, "age");
449 assert_eq!(entries[0].1.as_int(), Some(30));
450 assert_eq!(entries[1].0, "name");
451 assert_eq!(entries[1].1.as_str(), Some("Alice"));
452 }
453}