1use std::collections::BTreeMap;
11use std::fmt;
12
13use ordered_float::NotNan;
14use crate::{CRDTKind, CreateValue, DTValue, LV, Primitive, RegisterValue};
15use smartstring::alias::String as SmartString;
16
17#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
22pub struct CrdtId(pub(crate) LV);
23
24impl CrdtId {
25 #[doc(hidden)]
27 pub fn as_lv(&self) -> LV {
28 self.0
29 }
30}
31
32#[derive(Debug, Clone, Eq, PartialEq)]
41pub enum Value {
42 Nil,
44 Bool(bool),
46 Int(i64),
48 Float(NotNan<f64>),
50 Str(String),
52 Map(CrdtId),
54 Text(CrdtId),
56 Set(CrdtId),
58 Register(CrdtId),
60}
61
62impl Value {
63 pub fn is_nil(&self) -> bool {
65 matches!(self, Value::Nil)
66 }
67
68 pub fn is_primitive(&self) -> bool {
70 matches!(self, Value::Nil | Value::Bool(_) | Value::Int(_) | Value::Float(_) | Value::Str(_))
71 }
72
73 pub fn is_crdt(&self) -> bool {
75 matches!(self, Value::Map(_) | Value::Text(_) | Value::Set(_) | Value::Register(_))
76 }
77
78 pub fn as_bool(&self) -> Option<bool> {
80 match self {
81 Value::Bool(b) => Some(*b),
82 _ => None,
83 }
84 }
85
86 pub fn as_int(&self) -> Option<i64> {
88 match self {
89 Value::Int(n) => Some(*n),
90 _ => None,
91 }
92 }
93
94 pub fn as_f64(&self) -> Option<f64> {
97 match self {
98 Value::Float(n) => Some(n.into_inner()),
99 _ => None,
100 }
101 }
102
103 pub fn as_str(&self) -> Option<&str> {
105 match self {
106 Value::Str(s) => Some(s),
107 _ => None,
108 }
109 }
110
111 pub fn crdt_id(&self) -> Option<CrdtId> {
113 match self {
114 Value::Map(id) | Value::Text(id) | Value::Set(id) | Value::Register(id) => Some(*id),
115 _ => None,
116 }
117 }
118}
119
120impl fmt::Display for Value {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Value::Nil => write!(f, "nil"),
124 Value::Bool(b) => write!(f, "{}", b),
125 Value::Int(n) => write!(f, "{}", n),
126 Value::Float(n) => write!(f, "{}", n),
127 Value::Str(s) => write!(f, "{:?}", s),
128 Value::Map(id) => write!(f, "Map({:?})", id),
129 Value::Text(id) => write!(f, "Text({:?})", id),
130 Value::Set(id) => write!(f, "Set({:?})", id),
131 Value::Register(id) => write!(f, "Register({:?})", id),
132 }
133 }
134}
135
136#[derive(Debug, Clone, Eq, PartialEq)]
148#[derive(serde::Serialize, serde::Deserialize)]
149pub enum PrimitiveValue {
150 Nil,
152 Bool(bool),
154 Int(i64),
156 Float(NotNan<f64>),
158 Str(String),
160}
161
162impl From<bool> for PrimitiveValue {
163 fn from(b: bool) -> Self { PrimitiveValue::Bool(b) }
164}
165
166impl From<i64> for PrimitiveValue {
167 fn from(n: i64) -> Self { PrimitiveValue::Int(n) }
168}
169
170impl From<i32> for PrimitiveValue {
171 fn from(n: i32) -> Self { PrimitiveValue::Int(n as i64) }
172}
173
174impl From<f64> for PrimitiveValue {
176 fn from(n: f64) -> Self { PrimitiveValue::Float(NotNan::new(n).expect("NaN is not a valid CRDT value")) }
177}
178
179impl From<String> for PrimitiveValue {
180 fn from(s: String) -> Self { PrimitiveValue::Str(s) }
181}
182
183impl From<&str> for PrimitiveValue {
184 fn from(s: &str) -> Self { PrimitiveValue::Str(s.to_string()) }
185}
186
187impl From<()> for PrimitiveValue {
188 fn from(_: ()) -> Self { PrimitiveValue::Nil }
189}
190
191impl From<PrimitiveValue> for Primitive {
192 fn from(v: PrimitiveValue) -> Self {
193 match v {
194 PrimitiveValue::Nil => Primitive::Nil,
195 PrimitiveValue::Bool(b) => Primitive::Bool(b),
196 PrimitiveValue::Int(n) => Primitive::I64(n),
197 PrimitiveValue::Float(n) => Primitive::F64(n),
198 PrimitiveValue::Str(s) => Primitive::Str(s.into()),
199 }
200 }
201}
202
203impl From<PrimitiveValue> for CreateValue {
204 fn from(v: PrimitiveValue) -> Self {
205 CreateValue::Primitive(v.into())
206 }
207}
208
209impl From<PrimitiveValue> for Value {
210 fn from(v: PrimitiveValue) -> Self {
211 match v {
212 PrimitiveValue::Nil => Value::Nil,
213 PrimitiveValue::Bool(b) => Value::Bool(b),
214 PrimitiveValue::Int(n) => Value::Int(n),
215 PrimitiveValue::Float(n) => Value::Float(n),
216
217 PrimitiveValue::Str(s) => Value::Str(s),
218 }
219 }
220}
221
222#[derive(Debug, Clone, Eq, PartialEq)]
230#[derive(serde::Serialize, serde::Deserialize)]
231pub enum MaterializedValue {
232 Nil,
234 Bool(bool),
236 Int(i64),
238 Float(NotNan<f64>),
240 Str(String),
242 Text(String),
244 Map(BTreeMap<String, MaterializedValue>),
246 Set(Vec<PrimitiveValue>),
248}
249
250impl From<DTValue> for MaterializedValue {
251 fn from(dt: DTValue) -> Self {
252 match dt {
253 DTValue::Primitive(p) => match p {
254 Primitive::Nil | Primitive::InvalidUninitialized => MaterializedValue::Nil,
255 Primitive::Bool(b) => MaterializedValue::Bool(b),
256 Primitive::I64(n) => MaterializedValue::Int(n),
257 Primitive::F64(n) => MaterializedValue::Float(n),
258 Primitive::Str(s) => MaterializedValue::Str(s.to_string()),
259 },
260 DTValue::Register(inner) => (*inner).into(),
261 DTValue::Text(s) => MaterializedValue::Text(s),
262 DTValue::Map(entries) => MaterializedValue::Map(
263 entries.into_iter()
264 .map(|(k, v)| (k.to_string(), (*v).into()))
265 .collect()
266 ),
267 DTValue::Set(members) => MaterializedValue::Set(
268 members.into_iter()
269 .map(|p| match p {
270 Primitive::Nil | Primitive::InvalidUninitialized => PrimitiveValue::Nil,
271 Primitive::Bool(b) => PrimitiveValue::Bool(b),
272 Primitive::I64(n) => PrimitiveValue::Int(n),
273 Primitive::F64(n) => PrimitiveValue::Float(n),
274 Primitive::Str(s) => PrimitiveValue::Str(s.to_string()),
275 })
276 .collect()
277 ),
278 }
279 }
280}
281
282pub(crate) fn checkout_to_materialized(
283 raw: BTreeMap<SmartString, Box<DTValue>>
284) -> BTreeMap<String, MaterializedValue> {
285 raw.into_iter()
286 .map(|(k, v)| (k.to_string(), (*v).into()))
287 .collect()
288}
289
290impl From<bool> for Value {
293 fn from(b: bool) -> Self { Value::Bool(b) }
294}
295
296impl From<i64> for Value {
297 fn from(n: i64) -> Self { Value::Int(n) }
298}
299
300impl From<i32> for Value {
301 fn from(n: i32) -> Self { Value::Int(n as i64) }
302}
303
304impl From<f64> for Value {
306 fn from(n: f64) -> Self { Value::Float(NotNan::new(n).expect("NaN is not a valid CRDT value")) }
307}
308
309impl From<String> for Value {
310 fn from(s: String) -> Self { Value::Str(s) }
311}
312
313impl From<&str> for Value {
314 fn from(s: &str) -> Self { Value::Str(s.to_string()) }
315}
316
317impl From<()> for Value {
318 fn from(_: ()) -> Self { Value::Nil }
319}
320
321impl From<Primitive> for Value {
324 fn from(p: Primitive) -> Self {
325 match p {
326 Primitive::Nil => Value::Nil,
327 Primitive::Bool(b) => Value::Bool(b),
328 Primitive::I64(n) => Value::Int(n),
329 Primitive::F64(n) => Value::Float(n),
330 Primitive::Str(s) => Value::Str(s.to_string()),
331 Primitive::InvalidUninitialized => Value::Nil,
332 }
333 }
334}
335
336impl From<RegisterValue> for Value {
337 fn from(rv: RegisterValue) -> Self {
338 match rv {
339 RegisterValue::Primitive(p) => p.into(),
340 RegisterValue::OwnedCRDT(kind, lv) => {
341 let id = CrdtId(lv);
342 match kind {
343 CRDTKind::Map => Value::Map(id),
344 CRDTKind::Text => Value::Text(id),
345 CRDTKind::Set => Value::Set(id),
346 CRDTKind::Register => Value::Register(id),
347 CRDTKind::Collection => Value::Map(id),
348 }
349 }
350 }
351 }
352}
353
354impl From<Value> for Primitive {
355 fn from(v: Value) -> Self {
356 match v {
357 Value::Nil => Primitive::Nil,
358 Value::Bool(b) => Primitive::Bool(b),
359 Value::Int(n) => Primitive::I64(n),
360 Value::Float(n) => Primitive::F64(n),
361 Value::Str(s) => Primitive::Str(s.into()),
362 _ => Primitive::Nil,
363 }
364 }
365}
366
367impl From<Value> for CreateValue {
368 fn from(v: Value) -> Self {
369 match v {
370 Value::Nil => CreateValue::Primitive(Primitive::Nil),
371 Value::Bool(b) => CreateValue::Primitive(Primitive::Bool(b)),
372 Value::Int(n) => CreateValue::Primitive(Primitive::I64(n)),
373 Value::Float(n) => CreateValue::Primitive(Primitive::F64(n)),
374 Value::Str(s) => CreateValue::Primitive(Primitive::Str(s.into())),
375 Value::Map(_) => CreateValue::NewCRDT(CRDTKind::Map),
376 Value::Text(_) => CreateValue::NewCRDT(CRDTKind::Text),
377 Value::Set(_) => CreateValue::NewCRDT(CRDTKind::Set),
378 Value::Register(_) => CreateValue::NewCRDT(CRDTKind::Register),
379 }
380 }
381}
382
383#[derive(Debug, Clone, Eq, PartialEq)]
391pub struct Conflicted<T> {
392 pub value: T,
394 pub conflicts: Vec<T>,
396}
397
398impl<T> Conflicted<T> {
399 pub fn new(value: T) -> Self {
401 Self {
402 value,
403 conflicts: Vec::new(),
404 }
405 }
406
407 pub fn with_conflicts(value: T, conflicts: Vec<T>) -> Self {
409 Self { value, conflicts }
410 }
411
412 pub fn has_conflicts(&self) -> bool {
414 !self.conflicts.is_empty()
415 }
416
417 pub fn all_values(&self) -> impl Iterator<Item = &T> {
419 std::iter::once(&self.value).chain(self.conflicts.iter())
420 }
421
422 pub fn map<U, F: Fn(&T) -> U>(&self, f: F) -> Conflicted<U> {
424 Conflicted {
425 value: f(&self.value),
426 conflicts: self.conflicts.iter().map(f).collect(),
427 }
428 }
429
430 pub fn into_value(self) -> T {
432 self.value
433 }
434
435 pub fn into_all_values(self) -> Vec<T> {
437 let mut all = vec![self.value];
438 all.extend(self.conflicts);
439 all
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446
447 #[test]
448 fn test_value_primitives() {
449 assert!(Value::Nil.is_nil());
450 assert!(Value::Nil.is_primitive());
451 assert!(!Value::Nil.is_crdt());
452
453 assert_eq!(Value::Bool(true).as_bool(), Some(true));
454 assert_eq!(Value::Int(42).as_int(), Some(42));
455 assert_eq!(Value::Str("hello".into()).as_str(), Some("hello"));
456 }
457
458 #[test]
459 fn test_value_conversions() {
460 let v: Value = true.into();
461 assert_eq!(v, Value::Bool(true));
462
463 let v: Value = 42i64.into();
464 assert_eq!(v, Value::Int(42));
465
466 let v: Value = "hello".into();
467 assert_eq!(v, Value::Str("hello".into()));
468 }
469
470 #[test]
471 fn test_primitive_value_conversions() {
472 let v: PrimitiveValue = true.into();
473 assert_eq!(v, PrimitiveValue::Bool(true));
474
475 let v: PrimitiveValue = 42i64.into();
476 assert_eq!(v, PrimitiveValue::Int(42));
477
478 let v: PrimitiveValue = "hello".into();
479 assert_eq!(v, PrimitiveValue::Str("hello".into()));
480
481 let v: PrimitiveValue = ().into();
482 assert_eq!(v, PrimitiveValue::Nil);
483 }
484
485 #[test]
486 fn test_conflicted() {
487 let c = Conflicted::new(42);
488 assert!(!c.has_conflicts());
489 assert_eq!(c.all_values().count(), 1);
490
491 let c = Conflicted::with_conflicts(42, vec![43, 44]);
492 assert!(c.has_conflicts());
493 assert_eq!(c.all_values().collect::<Vec<_>>(), vec![&42, &43, &44]);
494 }
495
496 #[test]
497 fn test_conflicted_into_value_no_clone() {
498 let c = Conflicted::new(String::from("hello"));
500 let val = c.into_value();
501 assert_eq!(val, "hello");
502 }
503}