jmbl/
ops.rs

1use crate::{
2    io::SrcID,
3    mem_use::{MemUsage, MemUser},
4};
5use serde::Deserialize;
6use serde_derive::{Deserialize, Serialize};
7use std::hash::Hash;
8use thiserror::Error;
9use ti64::MsSinceEpoch;
10
11#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct OpID(pub SrcID, pub u32);
13
14impl MemUser for OpID {
15    fn mem_use(&self) -> MemUsage {
16        MemUsage::Struct {
17            name: "OpID",
18            fields: vec![
19                ("src", self.0.mem_use()),
20                ("idx", self.1.mem_use()),
21            ],
22        }
23    }
24}
25
26impl std::fmt::Display for OpID {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        write!(f, "{}:{}", self.0, self.1)
29    }
30}
31
32impl std::fmt::Debug for OpID {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        write!(f, "{}:{}", self.0, self.1)
35    }
36}
37
38impl std::str::FromStr for OpID {
39    type Err = OpIDParseError;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        // TODO: we know exactly where the split should be
43        let mut parts = s.split(':');
44        let src_id = parts.next().ok_or(OpIDParseError::MissingLogID)?.parse()?;
45        let sequence_idx = parts
46            .next()
47            .ok_or(OpIDParseError::MissingSequenceIdx)?
48            .parse()?;
49        Ok(OpID(
50            src_id,
51            sequence_idx,
52        ))
53    }
54}
55
56#[derive(Error, Debug)]
57pub enum OpIDParseError {
58    #[error("Missing LogID")]
59    MissingLogID,
60    #[error("Missing sequence index")]
61    MissingSequenceIdx,
62    #[error("Invalid LogID in OpID {0}")]
63    LogIDParseError(#[from] litl::TaggedDataError),
64    #[error("Invalid sequence index in OpID {0}")]
65    SequenceIdxParseError(#[from] std::num::ParseIntError),
66}
67
68#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
69pub struct ObjID {
70    pub init_op: OpID,
71}
72
73impl ObjID {
74    pub fn from_first_op_id(first_op_id: OpID) -> ObjID {
75        ObjID {
76            init_op: first_op_id,
77        }
78    }
79}
80
81impl MemUser for ObjID {
82    fn mem_use(&self) -> MemUsage {
83        self.init_op.mem_use()
84    }
85}
86
87#[allow(clippy::derive_hash_xor_eq)]
88#[derive(Clone, Debug, Hash)]
89pub struct Op {
90    pub id: OpID,
91    pub time: MsSinceEpoch,
92    pub prev: OpID,
93    pub kind: OpKind,
94    pub val: Option<litl::Val>,
95}
96
97impl PartialEq for Op {
98    fn eq(&self, other: &Self) -> bool {
99        self.id == other.id
100    }
101}
102
103impl Eq for Op {}
104
105impl Op {
106    pub fn new(id: OpID, prev: OpID, kind: OpKind, val: Option<litl::Val>) -> Op {
107        Op {
108            id,
109            prev,
110            time: ti64::now(),
111            kind,
112            val,
113        }
114    }
115
116    pub fn new_initial(id: OpID, kind: OpKind, val: Option<litl::Val>) -> Op {
117        Self::new(id, id, kind, val)
118    }
119}
120
121impl MemUser for Op {
122    fn mem_use(&self) -> MemUsage {
123        MemUsage::Struct {
124            name: "Op",
125            fields: vec![
126                ("id", self.id.mem_use()),
127                ("time", self.time.0.mem_use()),
128                ("prev", self.prev.mem_use()),
129                ("kind", self.kind.mem_use()),
130            ],
131        }
132    }
133}
134
135#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
136#[repr(u8)]
137#[serde(rename_all = "camelCase")]
138pub enum OpKind {
139    ListCreate,
140    MapCreate,
141    TextCreate,
142    SetRoot,
143    Undo,
144    Redo,
145    ListInsertAfter,
146    MapSet,
147}
148
149impl MemUser for OpKind {
150    fn mem_use(&self) -> MemUsage {
151        MemUsage::Enum {
152            name: "OpKind",
153            discriminant: std::mem::size_of::<u8>(),
154            min_size: std::mem::size_of::<OpKind>(),
155            variant: Box::new(match self {
156                OpKind::ListCreate => ("ListCreate", MemUsage::Simple(0)),
157                OpKind::MapCreate => ("MapCreate", MemUsage::Simple(0)),
158                OpKind::TextCreate => ("MapCreate", MemUsage::Simple(0)),
159                OpKind::SetRoot => ("MapCreate", MemUsage::Simple(0)),
160                OpKind::Undo => ("Undo", MemUsage::Simple(0)),
161                OpKind::Redo => ("Redo", MemUsage::Simple(0)),
162                OpKind::ListInsertAfter => ("ListInsertAfter", MemUsage::Simple(0)),
163                OpKind::MapSet => ("MapSet", MemUsage::Simple(0)),
164            }),
165        }
166    }
167}
168
169#[derive(Clone, Hash, Debug, PartialEq, Eq)]
170pub struct OpWithTarget {
171    pub target_obj_id: ObjID,
172    pub op: Op,
173}
174
175impl OpWithTarget {
176    pub fn dependencies(&self) -> impl Iterator<Item = OpID> {
177        let depends_on_target = self.target_obj_id.init_op != self.op.id;
178
179        if depends_on_target {
180            Some(self.target_obj_id.init_op)
181        } else {
182            None
183        }
184        .into_iter()
185        .chain(if self.op.prev != self.op.id {
186            Some(self.op.prev)
187        } else {
188            None
189        })
190        .chain(match self.op.kind {
191            OpKind::ListInsertAfter | OpKind::MapSet | OpKind::SetRoot => {
192                match self.op.val.as_ref().map(ObjID::deserialize) {
193                    Some(Ok(ObjID {
194                        init_op: first_op_id,
195                    })) => Some(first_op_id),
196                    Some(Err(_)) | None => None,
197                }
198            }
199            _ => None,
200        })
201    }
202}