1use std::ops::Range;
6
7
8use crate::value::{CrdtId, PrimitiveValue};
9use crate::list::operation::TextOperation;
10use crate::{AgentId, CRDTKind, CreateValue, OpLog, Primitive, ROOT_CRDT_ID, LV};
11
12pub struct MapMut<'a> {
16 oplog: &'a mut OpLog,
17 agent: AgentId,
18 crdt_id: LV,
19}
20
21impl<'a> MapMut<'a> {
22 pub(crate) fn new(oplog: &'a mut OpLog, agent: AgentId, crdt_id: LV) -> Self {
23 Self { oplog, agent, 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 set(&mut self, key: &str, value: impl Into<PrimitiveValue>) {
46 let create_value: CreateValue = value.into().into();
47 self.oplog.local_map_set(self.agent, self.crdt_id, key, create_value);
48 }
49
50 pub fn set_nil(&mut self, key: &str) {
58 self.oplog.local_map_set(
59 self.agent,
60 self.crdt_id,
61 key,
62 CreateValue::Primitive(Primitive::Nil),
63 );
64 }
65
66 pub fn create_map(&mut self, key: &str) -> CrdtId {
71 let lv = self.oplog.local_map_set(
72 self.agent,
73 self.crdt_id,
74 key,
75 CreateValue::NewCRDT(CRDTKind::Map),
76 );
77 CrdtId(lv)
78 }
79
80 pub fn create_text(&mut self, key: &str) -> CrdtId {
84 let lv = self.oplog.local_map_set(
85 self.agent,
86 self.crdt_id,
87 key,
88 CreateValue::NewCRDT(CRDTKind::Text),
89 );
90 CrdtId(lv)
91 }
92
93 pub fn create_set(&mut self, key: &str) -> CrdtId {
97 let lv = self.oplog.local_map_set(
98 self.agent,
99 self.crdt_id,
100 key,
101 CreateValue::NewCRDT(CRDTKind::Set),
102 );
103 CrdtId(lv)
104 }
105
106 pub fn create_register(&mut self, key: &str) -> CrdtId {
110 let lv = self.oplog.local_map_set(
111 self.agent,
112 self.crdt_id,
113 key,
114 CreateValue::NewCRDT(CRDTKind::Register),
115 );
116 CrdtId(lv)
117 }
118}
119
120pub struct TextMut<'a> {
124 oplog: &'a mut OpLog,
125 agent: AgentId,
126 crdt_id: LV,
127}
128
129impl<'a> TextMut<'a> {
130 pub(crate) fn new(oplog: &'a mut OpLog, agent: AgentId, crdt_id: LV) -> Self {
131 Self { oplog, agent, crdt_id }
132 }
133
134 pub fn id(&self) -> CrdtId {
136 CrdtId(self.crdt_id)
137 }
138
139 pub fn insert(&mut self, pos: usize, content: &str) {
143 let op = TextOperation::new_insert(pos, content);
144 self.oplog.local_text_op(self.agent, self.crdt_id, op);
145 }
146
147 pub fn delete(&mut self, range: Range<usize>) {
151 if !range.is_empty() {
152 let op = TextOperation::new_delete(range);
153 self.oplog.local_text_op(self.agent, self.crdt_id, op);
154 }
155 }
156
157 pub fn replace(&mut self, range: Range<usize>, content: &str) {
161 if !range.is_empty() {
162 let del_op = TextOperation::new_delete(range.clone());
163 self.oplog.local_text_op(self.agent, self.crdt_id, del_op);
164 }
165 if !content.is_empty() {
166 let ins_op = TextOperation::new_insert(range.start, content);
167 self.oplog.local_text_op(self.agent, self.crdt_id, ins_op);
168 }
169 }
170
171 pub fn push(&mut self, content: &str) {
173 let len = self.oplog.checkout_text(self.crdt_id).len_chars();
174 let op = TextOperation::new_insert(len, content);
175 self.oplog.local_text_op(self.agent, self.crdt_id, op);
176 }
177
178 pub fn clear(&mut self) {
180 let len = self.oplog.checkout_text(self.crdt_id).len_chars();
181 if len > 0 {
182 let op = TextOperation::new_delete(0..len);
183 self.oplog.local_text_op(self.agent, self.crdt_id, op);
184 }
185 }
186}
187
188pub struct SetMut<'a> {
192 oplog: &'a mut OpLog,
193 agent: AgentId,
194 crdt_id: LV,
195}
196
197impl<'a> SetMut<'a> {
198 pub(crate) fn new(oplog: &'a mut OpLog, agent: AgentId, crdt_id: LV) -> Self {
199 Self { oplog, agent, crdt_id }
200 }
201
202 pub fn id(&self) -> CrdtId {
204 CrdtId(self.crdt_id)
205 }
206
207 pub fn add(&mut self, value: impl Into<PrimitiveValue>) {
212 let primitive: Primitive = value.into().into();
213 self.oplog.local_set_add(self.agent, self.crdt_id, primitive);
214 }
215
216 pub fn add_str(&mut self, s: &str) {
218 self.oplog.local_set_add(self.agent, self.crdt_id, Primitive::Str(s.into()));
219 }
220
221 pub fn add_int(&mut self, n: i64) {
223 self.oplog.local_set_add(self.agent, self.crdt_id, Primitive::I64(n));
224 }
225
226 pub fn add_bool(&mut self, b: bool) {
228 self.oplog.local_set_add(self.agent, self.crdt_id, Primitive::Bool(b));
229 }
230
231 pub fn remove(&mut self, value: impl Into<PrimitiveValue>) {
237 let primitive: Primitive = value.into().into();
238 self.oplog.local_set_remove(self.agent, self.crdt_id, primitive);
239 }
240
241 pub fn remove_str(&mut self, s: &str) {
243 self.oplog.local_set_remove(self.agent, self.crdt_id, Primitive::Str(s.into()));
244 }
245
246 pub fn remove_int(&mut self, n: i64) {
248 self.oplog.local_set_remove(self.agent, self.crdt_id, Primitive::I64(n));
249 }
250}
251
252#[allow(dead_code)]
259pub(crate) struct RegisterMut<'a> {
260 oplog: &'a mut OpLog,
261 agent: AgentId,
262 crdt_id: LV,
263}
264
265#[allow(dead_code)]
266impl<'a> RegisterMut<'a> {
267 pub(crate) fn new(oplog: &'a mut OpLog, agent: AgentId, crdt_id: LV) -> Self {
268 Self { oplog, agent, crdt_id }
269 }
270
271 pub fn id(&self) -> CrdtId {
273 CrdtId(self.crdt_id)
274 }
275
276 }
279
280#[cfg(test)]
281mod tests {
282 use uuid::Uuid;
283 use crate::Document;
284
285 #[test]
286 fn test_map_mut_set() {
287 let mut doc = Document::new();
288 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
289
290 doc.transact(alice, |tx| {
291 tx.root().set("string", "hello");
292 tx.root().set("int", 42);
293 tx.root().set("bool", true);
294 tx.root().set("nil", ());
295 });
296
297 assert_eq!(doc.root().get("string").unwrap().as_str(), Some("hello"));
298 assert_eq!(doc.root().get("int").unwrap().as_int(), Some(42));
299 assert_eq!(doc.root().get("bool").unwrap().as_bool(), Some(true));
300 assert!(doc.root().get("nil").unwrap().is_nil());
301 }
302
303 #[test]
304 fn test_map_mut_create_nested() {
305 let mut doc = Document::new();
306 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
307
308 let text_id = doc.transact(alice, |tx| {
309 tx.root().create_text("content")
310 });
311
312 doc.transact(alice, |tx| {
313 if let Some(mut text) = tx.text_by_id(text_id) {
314 text.insert(0, "Hello, world!");
315 }
316 });
317
318 let text = doc.root().get_text("content").unwrap();
319 assert_eq!(text.content(), "Hello, world!");
320 }
321
322 #[test]
323 fn test_text_mut() {
324 let mut doc = Document::new();
325 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
326
327 let text_id = doc.transact(alice, |tx| {
328 tx.root().create_text("doc")
329 });
330
331 doc.transact(alice, |tx| {
332 let mut text = tx.text_by_id(text_id).unwrap();
333 text.insert(0, "Hello");
334 text.insert(5, ", world!");
335 });
336
337 assert_eq!(doc.root().get_text("doc").unwrap().content(), "Hello, world!");
338
339 doc.transact(alice, |tx| {
340 let mut text = tx.text_by_id(text_id).unwrap();
341 text.delete(5..13); });
343
344 assert_eq!(doc.root().get_text("doc").unwrap().content(), "Hello");
345 }
346
347 #[test]
348 fn test_set_mut() {
349 let mut doc = Document::new();
350 let alice = doc.create_agent(Uuid::from_u128(0xA11CE));
351
352 let set_id = doc.transact(alice, |tx| {
353 tx.root().create_set("tags")
354 });
355
356 doc.transact(alice, |tx| {
357 let mut set = tx.set_by_id(set_id).unwrap();
358 set.add_str("rust");
359 set.add_str("crdt");
360 set.add_int(42);
361 });
362
363 let set = doc.root().get_set("tags").unwrap();
364 assert!(set.contains_str("rust"));
365 assert!(set.contains_str("crdt"));
366 assert!(set.contains_int(42));
367 assert!(!set.contains_str("missing"));
368
369 doc.transact(alice, |tx| {
370 let mut set = tx.set_by_id(set_id).unwrap();
371 set.remove_str("crdt");
372 });
373
374 let set = doc.root().get_set("tags").unwrap();
375 assert!(set.contains_str("rust"));
376 assert!(!set.contains_str("crdt"));
377 }
378}