use crate::{
io::SrcID,
mem_use::{MemUsage, MemUser},
};
use serde::Deserialize;
use serde_derive::{Deserialize, Serialize};
use std::hash::Hash;
use thiserror::Error;
use ti64::MsSinceEpoch;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OpID {
pub src_id: SrcID,
pub sequence_idx: u32,
}
impl MemUser for OpID {
fn mem_use(&self) -> MemUsage {
MemUsage::Struct {
name: "OpID",
fields: vec![
("src_id", self.src_id.mem_use()),
("sequence_idx", self.sequence_idx.mem_use()),
],
}
}
}
impl std::fmt::Display for OpID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.src_id, self.sequence_idx)
}
}
impl std::fmt::Debug for OpID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.src_id, self.sequence_idx)
}
}
impl std::str::FromStr for OpID {
type Err = OpIDParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split(':');
let src_id = parts.next().ok_or(OpIDParseError::MissingLogID)?.parse()?;
let sequence_idx = parts
.next()
.ok_or(OpIDParseError::MissingSequenceIdx)?
.parse()?;
Ok(OpID {
src_id: src_id,
sequence_idx,
})
}
}
#[derive(Error, Debug)]
pub enum OpIDParseError {
#[error("Missing LogID")]
MissingLogID,
#[error("Missing sequence index")]
MissingSequenceIdx,
#[error("Invalid LogID in OpID {0}")]
LogIDParseError(#[from] litl::TaggedDataError),
#[error("Invalid sequence index in OpID {0}")]
SequenceIdxParseError(#[from] std::num::ParseIntError),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct ObjID {
pub init_op: OpID,
}
impl ObjID {
pub fn from_first_op_id(first_op_id: OpID) -> ObjID {
ObjID {
init_op: first_op_id,
}
}
}
impl MemUser for ObjID {
fn mem_use(&self) -> MemUsage {
self.init_op.mem_use()
}
}
#[allow(clippy::derive_hash_xor_eq)]
#[derive(Clone, Debug, Hash)]
pub struct Op {
pub id: OpID,
pub time: MsSinceEpoch,
pub prev: OpID,
pub kind: OpKind,
pub val: Option<litl::Val>,
}
impl PartialEq for Op {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Op {}
impl Op {
pub fn new(id: OpID, prev: OpID, kind: OpKind, val: Option<litl::Val>) -> Op {
Op {
id,
prev,
time: ti64::now(),
kind,
val,
}
}
pub fn new_initial(id: OpID, kind: OpKind, val: Option<litl::Val>) -> Op {
Self::new(id, id, kind, val)
}
}
impl MemUser for Op {
fn mem_use(&self) -> MemUsage {
MemUsage::Struct {
name: "Op",
fields: vec![
("id", self.id.mem_use()),
("time", self.time.0.mem_use()),
("prev", self.prev.mem_use()),
("kind", self.kind.mem_use()),
],
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
#[repr(u8)]
#[serde(rename_all = "camelCase")]
pub enum OpKind {
ListCreate,
MapCreate,
TextCreate,
SetRoot,
Undo,
Redo,
ListInsertAfter,
MapSet,
}
impl MemUser for OpKind {
fn mem_use(&self) -> MemUsage {
MemUsage::Enum {
name: "OpKind",
discriminant: std::mem::size_of::<u8>(),
min_size: std::mem::size_of::<OpKind>(),
variant: Box::new(match self {
OpKind::ListCreate => ("ListCreate", MemUsage::Simple(0)),
OpKind::MapCreate => ("MapCreate", MemUsage::Simple(0)),
OpKind::TextCreate => ("MapCreate", MemUsage::Simple(0)),
OpKind::SetRoot => ("MapCreate", MemUsage::Simple(0)),
OpKind::Undo => ("Undo", MemUsage::Simple(0)),
OpKind::Redo => ("Redo", MemUsage::Simple(0)),
OpKind::ListInsertAfter => ("ListInsertAfter", MemUsage::Simple(0)),
OpKind::MapSet => ("MapSet", MemUsage::Simple(0)),
}),
}
}
}
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub struct OpWithTarget {
pub target_obj_id: ObjID,
pub op: Op,
}
impl OpWithTarget {
pub fn dependencies(&self) -> impl Iterator<Item = OpID> {
let depends_on_target = self.target_obj_id.init_op != self.op.id;
if depends_on_target {
Some(self.target_obj_id.init_op)
} else {
None
}
.into_iter()
.chain(if self.op.prev != self.op.id {
Some(self.op.prev)
} else {
None
})
.chain(match self.op.kind {
OpKind::ListInsertAfter | OpKind::MapSet | OpKind::SetRoot => {
match self.op.val.as_ref().map(ObjID::deserialize) {
Some(Ok(ObjID {
init_op: first_op_id,
})) => Some(first_op_id),
Some(Err(_)) | None => None,
}
}
_ => None,
})
}
}