use super::op_set::{MarkIndexBuilder, ObjInfo, OpSet, ResolvedAction};
use super::types::{Action, ActorCursor, ActorIdx, KeyRef, MarkData, OpType, PropRef, ScalarValue};
use super::{ValueMeta, ValueRef};
use hexane::{ColumnDataIter, DeltaCursor, IntCursor};
use crate::clock::Clock;
use crate::error::AutomergeError;
use crate::exid::ExId;
use crate::types;
use crate::types::{ElemId, ObjId, ObjMeta, ObjType, OpId, SequenceType};
use crate::{hydrate, TextEncoding};
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::Debug;
pub(crate) trait AsBuilder: Debug {
fn as_builder(&self) -> &OpBuilder<'_>;
}
impl AsBuilder for ChangeOp {
fn as_builder(&self) -> &OpBuilder<'static> {
&self.bld
}
}
impl<'a> AsBuilder for OpBuilder<'a> {
fn as_builder(&self) -> &OpBuilder<'a> {
self
}
}
impl<'a> AsBuilder for &OpBuilder<'a> {
fn as_builder(&self) -> &OpBuilder<'a> {
self
}
}
impl AsBuilder for TxOp {
fn as_builder(&self) -> &OpBuilder<'static> {
&self.bld
}
}
impl AsBuilder for &TxOp {
fn as_builder(&self) -> &OpBuilder<'static> {
&self.bld
}
}
#[derive(Debug, Clone)]
pub(crate) struct ChangeOp {
pub(crate) succ: Vec<(OpId, Option<i64>)>,
pub(crate) pos: Option<usize>,
pub(crate) subsort: usize,
pub(crate) conflicted: bool,
pub(crate) bld: OpBuilder<'static>,
}
impl ChangeOp {
pub(crate) fn prop_static(&self) -> Option<PropRef<'static>> {
match &self.bld.key {
KeyRef::Map(s) => Some(PropRef::Map(Cow::Owned(String::from(s.as_ref())))),
_ => None,
}
}
pub(crate) fn prop(&self) -> Option<PropRef<'_>> {
match &self.bld.key {
KeyRef::Map(Cow::Owned(s)) => Some(PropRef::Map(Cow::Borrowed(s))),
KeyRef::Map(Cow::Borrowed(s)) => Some(PropRef::Map(Cow::Borrowed(s))),
_ => None,
}
}
pub(crate) fn mark_data(&self) -> Option<MarkData<'static>> {
let name = self.bld.mark_name.as_ref()?.clone();
let value = self.bld.value.clone();
Some(MarkData { name, value })
}
pub(crate) fn hydrate_value(&self, text_encoding: TextEncoding) -> hydrate::Value {
self.bld.hydrate_value(text_encoding)
}
pub(crate) fn hydrate_value_and_fix_counters(
&self,
text_encoding: TextEncoding,
) -> hydrate::Value {
if self.bld.action == Action::Set {
if let ScalarValue::Counter(c) = &self.bld.value {
let inc: i64 = self.succ.iter().filter_map(|(_, inc)| *inc).sum();
hydrate::Value::Scalar(types::ScalarValue::counter(c + inc))
} else {
hydrate::Value::Scalar(self.bld.value.to_owned())
}
} else {
self.bld.hydrate_value(text_encoding)
}
}
pub(crate) fn width(&self, seq_type: SequenceType, text_encoding: TextEncoding) -> usize {
self.bld.width(seq_type, text_encoding)
}
pub(crate) fn visible(&self) -> bool {
!(self.bld.is_inc() || self.bld.is_delete() || self.has_succ())
}
pub(crate) fn has_succ(&self) -> bool {
self.succ.iter().any(|(_, inc)| inc.is_none())
}
pub(crate) fn insert(&self) -> bool {
self.bld.insert
}
pub(crate) fn is_set_or_make(&self) -> bool {
matches!(
self.bld.action,
Action::Set | Action::MakeMap | Action::MakeList | Action::MakeText | Action::MakeTable
)
}
pub(crate) fn action(&self) -> Action {
self.bld.action
}
pub(crate) fn value(&self) -> &ScalarValue<'static> {
&self.bld.value
}
pub(crate) fn key(&self) -> &KeyRef<'static> {
&self.bld.key
}
pub(crate) fn pred(&self) -> &[OpId] {
&self.bld.pred
}
pub(crate) fn id(&self) -> OpId {
self.bld.id
}
pub(crate) fn elemid_or_key(&self) -> KeyRef<'_> {
if self.bld.insert {
KeyRef::Seq(ElemId(self.bld.id))
} else {
match &self.bld.key {
KeyRef::Map(Cow::Owned(s)) => KeyRef::Map(Cow::Borrowed(s)),
_ => self.bld.key.clone(),
}
}
}
pub(crate) fn get_increment_value(&self) -> Option<i64> {
match (self.bld.action, &self.bld.value) {
(Action::Increment, ScalarValue::Int(i)) => Some(*i),
(Action::Increment, ScalarValue::Uint(i)) => Some(*i as i64),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct TxOp {
pub(crate) obj_type: ObjType,
pub(crate) index: usize,
pub(crate) pos: usize,
pub(crate) noop: bool,
pub(crate) bld: OpBuilder<'static>,
}
#[derive(Debug, Clone)]
pub(crate) struct OpBuilder<'a> {
pub(crate) id: OpId,
pub(crate) obj: ObjId,
pub(crate) action: Action,
pub(crate) key: KeyRef<'a>,
pub(crate) value: ScalarValue<'a>,
pub(crate) insert: bool,
pub(crate) expand: bool,
pub(crate) mark_name: Option<Cow<'a, str>>,
pub(crate) pred: Vec<OpId>,
}
impl OpBuilder<'_> {
pub(crate) fn mark_index(&self) -> Option<MarkIndexBuilder> {
match (self.action, &self.mark_name) {
(Action::Mark, Some(name)) => {
let name = Cow::Owned(name.to_string());
let value = self.value.clone().into_owned();
let data = MarkData { name, value };
Some(MarkIndexBuilder::Start(self.id, data))
}
(Action::Mark, None) => Some(MarkIndexBuilder::End(self.id.prev())),
_ => None,
}
}
pub(crate) fn width(&self, seq_type: SequenceType, text_encoding: TextEncoding) -> usize {
match seq_type {
SequenceType::List => 1,
SequenceType::Text if self.is_mark() => 0,
SequenceType::Text => text_encoding.width(self.as_str()),
}
}
pub(crate) fn is_inc(&self) -> bool {
self.action == Action::Increment
}
pub(crate) fn is_mark(&self) -> bool {
self.action == Action::Mark
}
pub(crate) fn as_str(&self) -> &str {
match (self.action, &self.value) {
(Action::Set, ScalarValue::Str(s)) => s,
(Action::Mark, _) => "",
_ => "\u{fffc}",
}
}
pub(crate) fn is_delete(&self) -> bool {
self.action == Action::Delete
}
pub(crate) fn get_increment_value(&self) -> Option<i64> {
match (self.action, &self.value) {
(Action::Increment, ScalarValue::Int(i)) => Some(*i),
(Action::Increment, ScalarValue::Uint(i)) => Some(*i as i64),
_ => None,
}
}
pub(crate) fn hydrate_value(&self, text_encoding: TextEncoding) -> hydrate::Value {
match self.action {
Action::Set => hydrate::Value::Scalar(self.value.to_owned()),
Action::MakeMap => hydrate::Value::map(),
Action::MakeList => hydrate::Value::list(),
Action::MakeText => hydrate::Value::new(ObjType::Text, text_encoding),
Action::MakeTable => hydrate::Value::new(ObjType::Table, text_encoding),
_ => panic!("cant convert op into a value"),
}
}
}
impl TxOp {
pub(crate) fn id(&self) -> OpId {
self.bld.id
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn list(
id: OpId,
obj: ObjMeta,
pos: usize,
index: usize,
action: ResolvedAction,
elemid: ElemId,
pred: Vec<OpId>,
) -> Self {
let (op_type, noop) = match action {
ResolvedAction::ConflictResolution(action) => (action, true),
ResolvedAction::VisibleUpdate(action) => (action, false),
};
let (action, value, expand, mark_name) = op_type.decompose();
TxOp {
obj_type: obj.typ,
pos,
index,
noop,
bld: OpBuilder {
id,
obj: obj.id,
action,
value,
expand,
mark_name,
key: KeyRef::Seq(elemid),
insert: false,
pred,
},
}
}
pub(crate) fn map(
id: OpId,
obj: ObjMeta,
pos: usize,
action: ResolvedAction,
prop: String,
pred: Vec<OpId>,
) -> Self {
let (action, noop) = match action {
ResolvedAction::ConflictResolution(action) => (action, true),
ResolvedAction::VisibleUpdate(action) => (action, false),
};
let (action, value, expand, mark_name) = action.clone().decompose();
TxOp {
obj_type: obj.typ,
index: 0,
pos,
noop,
bld: OpBuilder {
id,
obj: obj.id,
value,
action,
expand,
mark_name,
key: KeyRef::Map(Cow::Owned(prop)),
insert: false,
pred,
},
}
}
pub(crate) fn insert(
id: OpId,
obj: ObjMeta,
pos: usize,
index: usize,
_action: types::OpType,
elemid: ElemId,
) -> Self {
let (action, value, expand, mark_name) = _action.clone().decompose();
TxOp {
obj_type: obj.typ,
pos,
index,
noop: false,
bld: OpBuilder {
id,
obj: obj.id,
action,
value,
expand,
mark_name,
key: KeyRef::Seq(elemid),
insert: true,
pred: vec![],
},
}
}
pub(crate) fn insert_val(
id: OpId,
obj: ObjMeta,
pos: usize,
value: types::ScalarValue,
elemid: ElemId,
) -> Self {
let _action = types::OpType::Put(value);
let (action, value, expand, mark_name) = _action.clone().decompose();
TxOp {
pos,
index: 0,
obj_type: obj.typ,
noop: false,
bld: OpBuilder {
id,
obj: obj.id,
action,
value,
expand,
mark_name,
key: KeyRef::Seq(elemid),
insert: true,
pred: vec![],
},
}
}
pub(crate) fn insert_obj(
id: OpId,
obj: ObjMeta,
pos: usize,
index: usize,
obj_type: types::ObjType,
elemid: ElemId,
) -> Self {
let _action = types::OpType::Make(obj_type);
let (action, value, expand, mark_name) = _action.clone().decompose();
TxOp {
obj_type: obj.typ,
pos,
index,
noop: false,
bld: OpBuilder {
id,
obj: obj.id,
action,
value,
expand,
mark_name,
key: elemid.into(),
insert: true,
pred: vec![],
},
}
}
pub(crate) fn list_del<I: IntoIterator<Item = OpId>>(
id: OpId,
obj: ObjMeta,
index: usize,
elemid: ElemId,
pred: I,
) -> Self {
let _action = types::OpType::Delete;
let (action, value, expand, mark_name) = _action.clone().decompose();
TxOp {
obj_type: obj.typ,
pos: 0,
index,
noop: false,
bld: OpBuilder {
id,
obj: obj.id,
action,
value,
expand,
mark_name,
key: elemid.into(),
insert: false,
pred: pred.into_iter().collect(),
},
}
}
pub(crate) fn prop(&self) -> PropRef<'_> {
if let KeyRef::Map(s) = &self.bld.key {
PropRef::Map(s.clone())
} else {
PropRef::Seq(self.index)
}
}
pub(crate) fn hydrate_value(&self, text_encoding: TextEncoding) -> hydrate::Value {
self.bld.hydrate_value(text_encoding)
}
pub(crate) fn get_increment_value(&self) -> Option<i64> {
self.bld.get_increment_value()
}
pub(crate) fn is_delete(&self) -> bool {
self.bld.is_delete()
}
pub(crate) fn as_str(&self) -> &str {
self.bld.as_str()
}
pub(crate) fn is_mark(&self) -> bool {
self.bld.is_mark()
}
}
impl OpLike for &TxOp {
type SuccIter<'b>
= std::array::IntoIter<OpId, 0>
where
Self: 'b;
fn mark_index(op: &Self) -> Option<MarkIndexBuilder> {
op.bld.mark_index()
}
fn width(op: &Self, seq_type: SequenceType, text_encoding: TextEncoding) -> u64 {
op.bld.width(seq_type, text_encoding) as u64
}
fn visible(op: &Self) -> bool {
!op.bld.is_inc()
}
fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.bld.action).ok()?;
let parent = self.bld.obj;
Some(ObjInfo { parent, obj_type })
}
fn id_actor(op: &Self) -> ActorIdx {
op.as_builder().id.actoridx()
}
fn id_ctr(op: &Self) -> i64 {
op.as_builder().id.icounter()
}
fn succ_inc(_op: &Self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
let v: Vec<Option<i64>> = vec![];
Box::new(v.into_iter())
}
fn succ(&self) -> Self::SuccIter<'_> {
[].into_iter()
}
fn id(&self) -> OpId {
self.as_builder().id
}
fn obj(&self) -> ObjId {
self.as_builder().obj
}
fn action(o: &Self) -> Action {
o.as_builder().action
}
fn key_str(o: &Self) -> Option<&str> {
match &o.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => Some(s),
KeyRef::Map(Cow::Borrowed(s)) => Some(*s),
_ => None,
}
}
fn key(&self) -> KeyRef<'_> {
match &self.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => KeyRef::Map(Cow::Borrowed(s)),
_ => self.as_builder().key.clone(),
}
}
fn raw_value(&self) -> Option<Cow<'_, [u8]>> {
self.as_builder().value.as_raw()
}
fn meta_value(&self) -> ValueMeta {
ValueMeta::from(&self.as_builder().value)
}
fn insert(o: &Self) -> bool {
o.as_builder().insert
}
fn mark_name(o: &Self) -> Option<Cow<'_, str>> {
o.as_builder().mark_name.as_deref().map(Cow::Borrowed)
}
fn expand(o: &Self) -> bool {
o.as_builder().expand
}
}
impl OpLike for TxOp {
type SuccIter<'b> = std::array::IntoIter<OpId, 0>;
fn mark_index(op: &Self) -> Option<MarkIndexBuilder> {
op.bld.mark_index()
}
fn width(op: &Self, seq_type: SequenceType, text_encoding: TextEncoding) -> u64 {
op.bld.width(seq_type, text_encoding) as u64
}
fn visible(op: &Self) -> bool {
!op.bld.is_inc()
}
fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.bld.action).ok()?;
let parent = self.bld.obj;
Some(ObjInfo { parent, obj_type })
}
fn id_actor(op: &Self) -> ActorIdx {
op.as_builder().id.actoridx()
}
fn id_ctr(op: &Self) -> i64 {
op.as_builder().id.icounter()
}
fn succ_inc(_op: &Self) -> Box<dyn Iterator<Item = Option<i64>>> {
let v: Vec<Option<i64>> = vec![];
Box::new(v.into_iter())
}
fn succ(&self) -> Self::SuccIter<'_> {
[].into_iter()
}
fn id(&self) -> OpId {
self.as_builder().id
}
fn obj(&self) -> ObjId {
self.as_builder().obj
}
fn action(o: &Self) -> Action {
o.as_builder().action
}
fn key_str(o: &Self) -> Option<&str> {
match &o.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => Some(s),
KeyRef::Map(Cow::Borrowed(s)) => Some(*s),
_ => None,
}
}
fn key(&self) -> KeyRef<'_> {
match &self.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => KeyRef::Map(Cow::Borrowed(s)),
_ => self.as_builder().key.clone(),
}
}
fn raw_value(&self) -> Option<Cow<'_, [u8]>> {
self.as_builder().value.as_raw()
}
fn meta_value(&self) -> ValueMeta {
ValueMeta::from(&self.as_builder().value)
}
fn insert(o: &Self) -> bool {
o.as_builder().insert
}
fn mark_name(o: &Self) -> Option<Cow<'_, str>> {
o.as_builder().mark_name.as_deref().map(Cow::Borrowed)
}
fn expand(o: &Self) -> bool {
o.as_builder().expand
}
}
impl OpLike for ChangeOp {
type SuccIter<'b> = Box<dyn ExactSizeIterator<Item = OpId> + 'b>;
fn mark_index(op: &Self) -> Option<MarkIndexBuilder> {
op.bld.mark_index()
}
fn width(op: &Self, seq_type: SequenceType, text_encoding: TextEncoding) -> u64 {
if Self::visible(op) {
op.bld.width(seq_type, text_encoding) as u64
} else {
0
}
}
fn visible(op: &Self) -> bool {
!(op.bld.is_inc() || op.bld.is_delete() || op.succ.iter().any(|(_, inc)| inc.is_none()))
}
fn top(op: &Self) -> bool {
!op.conflicted && Self::visible(op)
}
fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.bld.action).ok()?;
let parent = self.bld.obj;
Some(ObjInfo { parent, obj_type })
}
fn id_actor(op: &Self) -> ActorIdx {
op.as_builder().id.actoridx()
}
fn id_ctr(op: &Self) -> i64 {
op.as_builder().id.icounter()
}
fn succ_inc(op: &Self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
Box::new(op.succ.iter().map(|o| o.1))
}
fn succ(&self) -> Self::SuccIter<'_> {
Box::new(self.succ.iter().map(|o| o.0))
}
fn id(&self) -> OpId {
self.as_builder().id
}
fn obj(&self) -> ObjId {
self.as_builder().obj
}
fn action(o: &Self) -> Action {
o.as_builder().action
}
fn key_str(o: &Self) -> Option<&str> {
match &o.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => Some(s),
KeyRef::Map(Cow::Borrowed(s)) => Some(*s),
_ => None,
}
}
fn key(&self) -> KeyRef<'_> {
match &self.as_builder().key {
KeyRef::Map(Cow::Owned(s)) => KeyRef::Map(Cow::Borrowed(s)),
_ => self.as_builder().key.clone(),
}
}
fn raw_value(&self) -> Option<Cow<'_, [u8]>> {
self.as_builder().value.as_raw()
}
fn meta_value(&self) -> ValueMeta {
ValueMeta::from(&self.as_builder().value)
}
fn insert(o: &Self) -> bool {
o.as_builder().insert
}
fn mark_name(o: &Self) -> Option<Cow<'_, str>> {
o.as_builder().mark_name.as_deref().map(Cow::Borrowed)
}
fn expand(o: &Self) -> bool {
o.as_builder().expand
}
}
impl PartialEq<TxOp> for TxOp {
fn eq(&self, other: &Self) -> bool {
self.bld.id == other.bld.id
}
}
impl Eq for TxOp {}
impl PartialOrd for TxOp {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TxOp {
fn cmp(&self, other: &Self) -> Ordering {
self.bld.id.cmp(&other.bld.id)
}
}
impl<'a> OpLike for Op<'a> {
type SuccIter<'b>
= SuccCursors<'a>
where
Self: 'b;
fn mark_index(op: &Self) -> Option<MarkIndexBuilder> {
op.mark_index()
}
fn width(op: &Self, seq_type: SequenceType, text_encoding: TextEncoding) -> u64 {
op.width(seq_type, text_encoding) as u64
}
fn visible(_op: &Self) -> bool {
true }
fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.action).ok()?;
let parent = self.obj;
Some(ObjInfo { parent, obj_type })
}
fn id_actor(op: &Self) -> ActorIdx {
op.id.actoridx()
}
fn id_ctr(op: &Self) -> i64 {
op.id.icounter()
}
fn id(&self) -> OpId {
self.id
}
fn obj(&self) -> ObjId {
self.obj
}
fn action(o: &Self) -> Action {
o.action
}
fn key_str(o: &Self) -> Option<&str> {
match &o.key {
KeyRef::Map(Cow::Owned(s)) => Some(s),
KeyRef::Map(Cow::Borrowed(s)) => Some(*s),
_ => None,
}
}
fn key(&self) -> KeyRef<'_> {
self.key.clone()
}
fn raw_value(&self) -> Option<Cow<'_, [u8]>> {
self.value.as_raw()
}
fn meta_value(&self) -> ValueMeta {
ValueMeta::from(&self.value)
}
fn succ_inc(op: &Self) -> Box<dyn Iterator<Item = Option<i64>> + '_> {
Box::new(IncCursors(op.succ_cursors.clone()))
}
fn succ(&self) -> Self::SuccIter<'_> {
self.succ()
}
fn insert(o: &Self) -> bool {
o.insert
}
fn expand(o: &Self) -> bool {
o.expand
}
fn mark_name(o: &Self) -> Option<Cow<'_, str>> {
o.mark_name.clone()
}
}
#[derive(Debug, Clone)]
pub(crate) struct Op<'a> {
pub(crate) pos: usize,
pub(crate) conflict: bool,
pub(crate) id: OpId,
pub(crate) action: Action,
pub(crate) obj: ObjId,
pub(crate) key: KeyRef<'a>,
pub(crate) insert: bool,
pub(crate) value: ScalarValue<'a>,
pub(crate) expand: bool,
pub(crate) mark_name: Option<Cow<'a, str>>,
pub(super) succ_cursors: SuccCursors<'a>,
}
#[derive(Clone, Default)]
pub(crate) struct SuccCursors<'a> {
pub(super) len: usize,
pub(super) succ_actor: ColumnDataIter<'a, ActorCursor>,
pub(super) succ_counter: ColumnDataIter<'a, DeltaCursor>,
pub(super) inc_values: ColumnDataIter<'a, IntCursor>,
}
impl<'a> SuccCursors<'a> {
pub(crate) fn pos(&self) -> usize {
self.succ_actor.pos()
}
pub(crate) fn with_inc(self) -> SuccIncCursors<'a> {
SuccIncCursors(self)
}
}
impl std::fmt::Debug for SuccCursors<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SuccCursors")
.field("len", &self.len)
.finish()
}
}
pub(crate) struct SuccIncCursors<'a>(SuccCursors<'a>);
struct IncCursors<'a>(SuccCursors<'a>);
impl Iterator for SuccCursors<'_> {
type Item = OpId;
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
None
} else {
let counter = self.succ_counter.next()??;
let actor = self.succ_actor.next()??;
self.len -= 1;
Some(OpId::new(*counter as u64, u64::from(*actor) as usize))
}
}
}
impl ExactSizeIterator for SuccCursors<'_> {
fn len(&self) -> usize {
self.len
}
}
impl Iterator for SuccIncCursors<'_> {
type Item = (OpId, Option<i64>);
fn next(&mut self) -> Option<Self::Item> {
if self.0.len == 0 {
None
} else {
let counter = self.0.succ_counter.next()??;
let actor = self.0.succ_actor.next()??;
self.0.len -= 1;
let inc = self.0.inc_values.next()?.as_deref().copied();
let id = OpId::new(*counter as u64, u64::from(*actor) as usize);
Some((id, inc))
}
}
}
impl Iterator for IncCursors<'_> {
type Item = Option<i64>;
fn next(&mut self) -> Option<Self::Item> {
if self.0.len == 0 {
None
} else {
self.0.len -= 1;
let inc = self.0.inc_values.next()?.as_deref().copied();
Some(inc)
}
}
}
impl ExactSizeIterator for SuccIncCursors<'_> {
fn len(&self) -> usize {
self.0.len()
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct SuccInsert {
pub(crate) id: OpId,
pub(crate) pos: usize,
pub(crate) inc: Option<i64>,
pub(crate) len: u64,
pub(crate) sub_pos: usize,
}
impl<'a> Op<'a> {
pub(crate) fn mark_index(&self) -> Option<MarkIndexBuilder> {
match (&self.action, &self.mark_name) {
(Action::Mark, Some(name)) => {
let name = Cow::Owned(name.to_string());
let value = self.value.clone().into_owned();
let data = MarkData { name, value };
Some(MarkIndexBuilder::Start(self.id, data))
}
(Action::Mark, None) => Some(MarkIndexBuilder::End(self.id.prev())),
_ => None,
}
}
pub(crate) fn add_succ(&self, id: OpId, mut inc: Option<i64>) -> SuccInsert {
let pos = self.pos;
let mut succ = self.succ_cursors.clone();
if inc.is_some() && !self.is_counter() {
inc = None;
}
let len = succ.len() as u64;
let mut sub_pos = succ.pos();
while let Some(i) = succ.next() {
if i > id {
break;
}
sub_pos = succ.pos();
}
SuccInsert {
id,
pos,
inc,
len,
sub_pos,
}
}
pub(crate) fn fix_counter(&mut self, clock: Option<&Clock>) {
if let ScalarValue::Counter(n) = self.value {
let mut inc = 0;
for (i, val) in self.succ_inc() {
if let Some(v) = val {
if let Some(c) = clock {
if c.covers(&i) {
inc += v;
}
} else {
inc += v;
}
}
}
self.value = ScalarValue::Counter(n + inc);
}
}
pub(crate) fn as_str(&self) -> &str {
if self.action == Action::Mark {
""
} else if let ScalarValue::Str(s) = &self.value {
s.as_ref()
} else {
"\u{fffc}"
}
}
pub(crate) fn width(&self, seq_type: SequenceType, text_encoding: TextEncoding) -> usize {
match seq_type {
SequenceType::List => 1,
SequenceType::Text if self.action == Action::Mark => 0,
SequenceType::Text => text_encoding.width(self.as_str()),
}
}
pub(crate) fn op_type(&self) -> OpType<'a> {
OpType::from_action_and_value(self.action, &self.value, &self.mark_name, self.expand)
}
pub(crate) fn succ(&self) -> SuccCursors<'a> {
self.succ_cursors.clone()
}
pub(crate) fn succ_inc(&self) -> impl ExactSizeIterator<Item = (OpId, Option<i64>)> + 'a {
self.succ_cursors.clone().with_inc()
}
pub(crate) fn exid(&self, op_set: &OpSet) -> ExId {
let id = self.id;
if id == types::ROOT {
ExId::Root
} else {
ExId::Id(
id.counter(),
op_set.get_actor(id.actor()).clone(),
id.actor(),
)
}
}
pub(crate) fn elemid_or_key(&self) -> KeyRef<'a> {
if self.insert {
KeyRef::Seq(ElemId(self.id))
} else {
self.key.clone()
}
}
pub(crate) fn step(&self, stepper: &mut OpStepper<'a>) -> bool {
if self.obj != stepper.obj {
let ok = self.obj > stepper.obj;
stepper.obj = self.obj;
stepper.key = self.elemid_or_key();
stepper.id = self.id;
ok
} else {
let ok = if self.elemid_or_key() == stepper.key {
self.id > stepper.id
} else {
match (&self.key, &stepper.key) {
(KeyRef::Map(s1), KeyRef::Map(s2)) => s1 > s2,
(KeyRef::Seq(e1), KeyRef::Seq(e2)) if self.insert => {
e1 == e2 || ElemId(self.id) < *e2
}
_ => false,
}
};
stepper.key = self.elemid_or_key();
stepper.id = self.id;
ok
}
}
pub(crate) fn cursor(&self) -> Result<ElemId, AutomergeError> {
if self.insert {
Ok(ElemId(self.id))
} else {
match self.key {
KeyRef::Seq(e) => Ok(e),
_ => Err(AutomergeError::InvalidCursorOp),
}
}
}
pub(crate) fn tagged_value(&self, op_set: &'a OpSet) -> (types::Value<'static>, ExId) {
(self.value().into_value(), self.exid(op_set))
}
pub(crate) fn get_increment_value(&self) -> Option<i64> {
match (self.action, &self.value) {
(Action::Increment, ScalarValue::Int(i)) => Some(*i),
(Action::Increment, ScalarValue::Uint(i)) => Some(*i as i64),
_ => None,
}
}
pub(crate) fn value(&self) -> ValueRef<'a> {
match &self.action() {
OpType::Make(obj_type) => ValueRef::Object(*obj_type),
OpType::Put(scalar) => ValueRef::Scalar(scalar.clone()),
OpType::MarkBegin(_, _) => {
ValueRef::Scalar(ScalarValue::Str(Cow::Borrowed("markBegin")))
}
OpType::MarkEnd(_) => ValueRef::Scalar(ScalarValue::Str(Cow::Borrowed("markEnd"))),
_ => panic!("cant convert op into a value - {:?}", self),
}
}
pub(crate) fn hydrate_value(&self, text_encoding: TextEncoding) -> hydrate::Value {
match &self.action() {
OpType::Make(obj_type) => hydrate::Value::new(*obj_type, text_encoding),
OpType::Put(scalar) => hydrate::Value::Scalar(scalar.to_owned()),
OpType::MarkBegin(_, mark) => hydrate::Value::new(&mark.value, text_encoding),
OpType::MarkEnd(_) => hydrate::Value::Scalar("markEnd".into()),
_ => panic!("cant convert op into a value"),
}
}
pub(crate) fn action(&self) -> OpType<'a> {
self.op_type()
}
pub(crate) fn is_inc(&self) -> bool {
self.action == Action::Increment
}
pub(crate) fn is_counter(&self) -> bool {
matches!(&self.value, ScalarValue::Counter(_))
}
pub(crate) fn is_mark(&self) -> bool {
self.action == Action::Mark
}
pub(crate) fn build(self, pred: Vec<OpId>) -> OpBuilder<'a> {
OpBuilder {
id: self.id,
obj: self.obj,
action: self.action,
value: self.value,
key: self.key,
insert: self.insert,
expand: self.expand,
mark_name: self.mark_name,
pred,
}
}
pub(crate) fn visible(&self) -> bool {
if self.is_inc() {
false
} else if self.is_counter() {
!self.succ_inc().any(|(_, inc)| inc.is_none())
} else {
self.succ_cursors.len() == 0
}
}
pub(crate) fn del(id: OpId, obj: ObjId, key: KeyRef<'a>) -> Self {
Op {
pos: 0,
conflict: false,
id,
action: Action::Delete,
obj,
key,
insert: false,
value: ScalarValue::Null,
expand: false,
mark_name: None,
succ_cursors: SuccCursors::default(),
}
}
pub(crate) fn prop(&self) -> Option<PropRef<'a>> {
let key_str = self.key.key_str()?;
Some(PropRef::Map(key_str))
}
}
impl PartialEq<Op<'_>> for Op<'_> {
fn eq(&self, other: &Op<'_>) -> bool {
self.id == other.id
}
}
impl PartialOrd for Op<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Op<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl std::hash::Hash for Op<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state)
}
}
impl Eq for Op<'_> {}
pub(crate) trait AsChangeOp {
fn obj_actor(op: &Self) -> Option<Cow<'_, ActorIdx>>;
fn obj_ctr(op: &Self) -> Option<Cow<'_, u64>>;
fn key_actor(op: &Self) -> Option<Cow<'_, ActorIdx>>;
fn key_ctr(op: &Self) -> Option<Cow<'_, i64>>;
fn key_str(op: &Self) -> Option<Cow<'_, str>>;
fn insert(op: &Self) -> Option<Cow<'_, bool>>;
fn action(op: &Self) -> Option<Cow<'_, Action>>;
fn value(op: &Self) -> Option<Cow<'_, [u8]>>;
fn value_meta(op: &Self) -> Option<Cow<'_, ValueMeta>>;
fn pred_count(op: &Self) -> Option<Cow<'_, u64>>;
fn expand(op: &Self) -> Option<Cow<'_, bool>>;
fn mark_name(op: &Self) -> Option<Cow<'_, str>>;
fn op_id_ctr(op: &Self) -> u64;
fn pred(op: &Self) -> &[OpId];
fn id_actor(id: &OpId) -> Option<Cow<'_, ActorIdx>> {
Some(Cow::Owned(id.actoridx()))
}
fn id_ctr(id: &OpId) -> Option<Cow<'_, i64>> {
Some(Cow::Owned(id.icounter()))
}
}
impl<T: AsChangeOp> AsChangeOp for Option<T> {
fn obj_actor(op: &Self) -> Option<Cow<'_, ActorIdx>> {
T::obj_actor(op.as_ref()?)
}
fn obj_ctr(op: &Self) -> Option<Cow<'_, u64>> {
T::obj_ctr(op.as_ref()?)
}
fn key_actor(op: &Self) -> Option<Cow<'_, ActorIdx>> {
T::key_actor(op.as_ref()?)
}
fn key_ctr(op: &Self) -> Option<Cow<'_, i64>> {
T::key_ctr(op.as_ref()?)
}
fn key_str(op: &Self) -> Option<Cow<'_, str>> {
T::key_str(op.as_ref()?)
}
fn insert(op: &Self) -> Option<Cow<'_, bool>> {
T::insert(op.as_ref()?)
}
fn action(op: &Self) -> Option<Cow<'_, Action>> {
T::action(op.as_ref()?)
}
fn value(op: &Self) -> Option<Cow<'_, [u8]>> {
T::value(op.as_ref()?)
}
fn value_meta(op: &Self) -> Option<Cow<'_, ValueMeta>> {
T::value_meta(op.as_ref()?)
}
fn pred_count(op: &Self) -> Option<Cow<'_, u64>> {
T::pred_count(op.as_ref()?)
}
fn expand(op: &Self) -> Option<Cow<'_, bool>> {
T::expand(op.as_ref()?)
}
fn mark_name(op: &Self) -> Option<Cow<'_, str>> {
T::mark_name(op.as_ref()?)
}
fn op_id_ctr(op: &Self) -> u64 {
op.as_ref().map(|o| T::op_id_ctr(o)).unwrap_or(0)
}
fn pred(op: &Self) -> &[OpId] {
op.as_ref().map(T::pred).unwrap_or(&[])
}
}
impl<B: AsBuilder> AsChangeOp for B {
fn obj_actor(op: &Self) -> Option<Cow<'_, ActorIdx>> {
op.as_builder().obj.actor().map(Cow::Owned)
}
fn obj_ctr(op: &Self) -> Option<Cow<'_, u64>> {
op.as_builder().obj.counter().map(Cow::Owned)
}
fn key_actor(op: &Self) -> Option<Cow<'_, ActorIdx>> {
op.as_builder().key.actor().map(Cow::Owned)
}
fn key_ctr(op: &Self) -> Option<Cow<'_, i64>> {
op.as_builder().key.icounter().map(Cow::Owned)
}
fn key_str(op: &Self) -> Option<Cow<'_, str>> {
op.as_builder().key.key_str()
}
fn insert(op: &Self) -> Option<Cow<'_, bool>> {
Some(Cow::Owned(op.as_builder().insert))
}
fn action(op: &Self) -> Option<Cow<'_, Action>> {
Some(Cow::Owned(op.as_builder().action))
}
fn value(op: &Self) -> Option<Cow<'_, [u8]>> {
op.as_builder().value.as_raw()
}
fn value_meta(op: &Self) -> Option<Cow<'_, ValueMeta>> {
Some(Cow::Owned(ValueMeta::from(&op.as_builder().value)))
}
fn pred_count(op: &Self) -> Option<Cow<'_, u64>> {
Some(Cow::Owned(op.as_builder().pred.len() as u64))
}
fn expand(op: &Self) -> Option<Cow<'_, bool>> {
Some(Cow::Owned(op.as_builder().expand))
}
fn mark_name(op: &Self) -> Option<Cow<'_, str>> {
op.as_builder().mark_name.clone()
}
fn op_id_ctr(op: &Self) -> u64 {
op.as_builder().id.counter()
}
fn pred(op: &Self) -> &[OpId] {
op.as_builder().pred.as_slice()
}
}
pub(crate) trait OpLike: Debug {
type SuccIter<'b>: ExactSizeIterator<Item = OpId> + 'b
where
Self: 'b;
fn id_actor(op: &Self) -> ActorIdx;
fn id_ctr(op: &Self) -> i64;
fn id(&self) -> OpId;
fn obj(&self) -> ObjId;
fn obj_actor(op: &Self) -> Option<ActorIdx> {
op.obj().actor()
}
fn obj_ctr(op: &Self) -> Option<u64> {
op.obj().counter()
}
fn action(o: &Self) -> Action;
fn key_str(o: &Self) -> Option<&str>;
fn key_actor(op: &Self) -> Option<ActorIdx> {
op.key().actor()
}
fn key_ctr(op: &Self) -> Option<i64> {
op.key().icounter()
}
fn key(&self) -> KeyRef<'_>;
fn raw_value(&self) -> Option<Cow<'_, [u8]>>; fn meta_value(&self) -> ValueMeta;
fn insert(op: &Self) -> bool;
fn expand(op: &Self) -> bool;
fn succ(&self) -> Self::SuccIter<'_>;
fn succ_inc(op: &Self) -> Box<dyn Iterator<Item = Option<i64>> + '_>;
fn mark_name(op: &Self) -> Option<Cow<'_, str>>;
fn mark_index(op: &Self) -> Option<MarkIndexBuilder>;
fn width(op: &Self, seq_type: SequenceType, text_encoding: TextEncoding) -> u64;
fn visible(op: &Self) -> bool;
fn top(op: &Self) -> bool {
Self::visible(op)
}
fn obj_info(&self) -> Option<ObjInfo>;
}
#[derive(Clone, Debug)]
pub(crate) struct OpStepper<'a> {
obj: ObjId,
key: KeyRef<'a>,
id: OpId,
}
impl Default for OpStepper<'_> {
fn default() -> Self {
OpStepper {
obj: ObjId::root(),
key: KeyRef::Map(Cow::Borrowed("")),
id: OpId::default(),
}
}
}