use Error;
use dot::{Summary, SiteId};
macro_rules! crdt_impl2 {
($self_ident:ident,
$state:ty,
$state_static:ty,
$state_ident:ident,
$inner:ty,
$op:ty,
$local_op:ty,
$local_value:ty,
) => {
pub fn site_id(&self) -> SiteId {
self.site_id
}
#[doc(hidden)]
pub fn summary(&self) -> &Summary {
&self.summary
}
#[doc(hidden)]
pub fn cached_ops(&self) -> &[$op] {
&self.cached_ops
}
pub fn state(&self) -> $state {
$state_ident {
inner: Cow::Borrowed(&self.inner),
summary: Cow::Borrowed(&self.summary),
}
}
pub fn clone_state(&self) -> $state_static {
$state_ident {
inner: Cow::Owned(self.inner.clone()),
summary: Cow::Owned(self.summary.clone()),
}
}
pub fn into_state(self) -> $state_static {
$state_ident {
inner: Cow::Owned(self.inner),
summary: Cow::Owned(self.summary),
}
}
pub fn from_state(state: $state, site_id: Option<SiteId>) -> Result<Self, Error> {
let site_id = match site_id {
None => 0,
Some(0) => return Err(Error::InvalidSiteId),
Some(s) => s,
};
Ok($self_ident{
site_id,
inner: state.inner.into_owned(),
summary: state.summary.into_owned(),
cached_ops: vec![],
})
}
pub fn local_value(&self) -> $local_value {
self.inner.local_value()
}
pub fn execute_op(&mut self, op: $op) -> $local_op {
for dot in op.inserted_dots() {
self.summary.insert(dot);
}
self.inner.execute_op(op)
}
pub fn validate_and_execute_op(&mut self, op: $op, site_id: SiteId) -> Result<$local_op, Error> {
op.validate(site_id)?;
Ok(self.execute_op(op))
}
pub fn merge(&mut self, other: $state) -> Result<(), Error> {
other.inner.validate_no_unassigned_sites()?;
other.summary.validate_no_unassigned_sites()?;
self.inner.merge(other.inner.into_owned(), &self.summary, &other.summary);
self.summary.merge(&other.summary);
Ok(())
}
pub fn add_site_id(&mut self, site_id: SiteId) -> Result<Vec<$op>, Error> {
if self.site_id != 0 {
return Err(Error::AlreadyHasSiteId);
}
self.site_id = site_id;
self.inner.add_site_id(site_id);
self.summary.add_site_id(site_id);
Ok(::std::mem::replace(&mut self.cached_ops, vec![])
.into_iter()
.map(|mut op| { op.add_site_id(site_id); op})
.collect())
}
fn after_op(&mut self, op: $op) -> Result<$op, Error> {
if self.site_id == 0 {
self.cached_ops.push(op);
Err(Error::AwaitingSiteId)
} else {
Ok(op)
}
}
}
}
pub(crate) trait NestedInner: Sized {
fn nested_add_site_id(&mut self, site_id: SiteId);
fn nested_validate_all(&self, site_id: SiteId) -> Result<(), Error>;
fn nested_validate_no_unassigned_sites(&self) -> Result<(), Error>;
fn nested_can_merge(&self, other: &Self) -> bool;
fn nested_merge(&mut self, other: Self, summary: &Summary, other_summary: &Summary) -> Result<(), Error> {
if self.nested_can_merge(&other) {
self.nested_force_merge(other, summary, other_summary);
Ok(())
} else {
Err(Error::CannotMerge)
}
}
fn nested_force_merge(&mut self, other: Self, summary: &Summary, other_summary: &Summary);
}
pub(crate) trait NestedOp {
fn nested_add_site_id(&mut self, site_id: SiteId);
fn nested_validate(&self, site_id: SiteId) -> Result<(), Error>;
}