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 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}