use Error;
use dot::{Dot, SiteId, Counter, Summary};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::mem;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Register<T: Clone> {
elements: BTreeMap<SiteId, SiteValue<T>>,
summary: Summary,
site_id: SiteId,
cached_op: Option<Op<T>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RegisterState<'a, T: Clone + 'a> {
elements: Cow<'a, BTreeMap<SiteId, SiteValue<T>>>,
summary: Cow<'a, Summary>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Op<T: Clone> {
site_id: SiteId,
counter: Counter,
value: T,
removed_dots: Vec<Dot>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct SiteValue<T: Clone> {
value: T,
counter: Counter,
}
impl<T: Clone> Register<T> {
pub fn new(value: T) -> Self {
let site_id = 1;
let counter = 1;
let mut elements = BTreeMap::new();
let mut summary = Summary::default();
let _ = elements.insert(site_id, SiteValue{value, counter});
summary.insert_pair(site_id, counter);
Register{elements, summary, site_id, cached_op: None}
}
pub fn get(&self) -> &T {
&self.elements.values().next().as_ref().unwrap().value
}
pub fn update(&mut self, value: T) -> Result<Op<T>, Error> {
let counter = self.summary.increment(self.site_id);
let mut new_elements = BTreeMap::new();
new_elements.insert(self.site_id, SiteValue{value: value.clone(), counter});
let removed_dots = mem::replace(&mut self.elements, new_elements)
.into_iter()
.filter_map(|(site_id, site_value)|
if site_id == self.site_id {
None
} else {
Some(Dot::new(site_id, site_value.counter))
})
.collect();
let op = Op{site_id: self.site_id, value, counter, removed_dots};
if self.site_id == 0 {
self.cached_op = Some(op);
Err(Error::AwaitingSiteId)
} else {
Ok(op)
}
}
pub fn execute_op(&mut self, op: Op<T>) -> &T {
for Dot{site_id, counter} in op.removed_dots {
if let Some(site_value) = self.elements.remove(&site_id) {
if site_value.counter > counter {
self.elements.insert(site_id, site_value);
}
}
}
self.summary.insert_pair(op.site_id, op.counter);
let sv_other = SiteValue{value: op.value, counter: op.counter};
if let Some(sv_self) = self.elements.insert(op.site_id, sv_other) {
if sv_self.counter > op.counter {
self.elements.insert(op.site_id, sv_self);
}
}
self.get()
}
pub fn merge(&mut self, other: RegisterState<T>) {
let mut other_elements = other.elements.into_owned();
let self_elements = mem::replace(&mut self.elements, BTreeMap::new());
for (site_id, sv_self) in self_elements {
if let Some(sv_other) = other_elements.remove(&site_id) {
let sv = if sv_self.counter > sv_other.counter { sv_self } else { sv_other };
self.summary.insert_pair(site_id, sv.counter);
self.elements.insert(site_id, sv);
} else if !other.summary.contains_pair(site_id, sv_self.counter) {
self.summary.insert_pair(site_id, sv_self.counter);
self.elements.insert(site_id, sv_self);
}
}
for (site_id, sv) in other_elements {
if !self.summary.contains_pair(site_id, sv.counter) {
self.summary.insert_pair(site_id, sv.counter);
self.elements.insert(site_id, sv);
}
}
}
pub fn add_site_id(&mut self, site_id: SiteId) -> Result<Option<Op<T>>, Error> {
if self.site_id != 0 {
return Err(Error::AlreadyHasSiteId)
}
self.site_id = site_id;
self.summary.add_site_id(site_id);
if let Some(site_value) = self.elements.remove(&0) {
self.elements.insert(site_id, site_value);
}
if let Some(mut op) = self.cached_op.take() {
op.add_site_id(site_id);
Ok(Some(op))
} else {
Ok(None)
}
}
pub fn site_id(&self) -> SiteId {
self.site_id
}
pub fn summary(&self) -> &Summary {
&self.summary
}
pub fn state(&self) -> RegisterState<T> {
RegisterState{
elements: Cow::Borrowed(&self.elements),
summary: Cow::Borrowed(&self.summary),
}
}
pub fn clone_state(&self) -> RegisterState<'static, T> {
RegisterState {
elements: Cow::Owned(self.elements.clone()),
summary: Cow::Owned(self.summary.clone()),
}
}
pub fn into_state(self) -> RegisterState<'static, T> {
RegisterState {
elements: Cow::Owned(self.elements),
summary: Cow::Owned(self.summary),
}
}
pub fn from_state(state: RegisterState<T>, 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(Register{
elements: state.elements.into_owned(),
summary: state.summary.into_owned(),
site_id,
cached_op: None,
})
}
pub fn validate_and_execute_op(&mut self, op: Op<T>, site_id: SiteId) -> Result<&T, Error> {
op.validate(site_id)?;
Ok(self.execute_op(op))
}
}
impl<T: Clone> Op<T> {
pub fn site_id(&self) -> SiteId { self.site_id }
pub fn counter(&self) -> Counter { self.counter }
pub fn value(&self) -> &T { &self.value }
pub fn removed_dots(&self) -> &[Dot] {
&self.removed_dots
}
pub fn add_site_id(&mut self, site_id: SiteId) {
self.site_id = site_id;
}
pub fn validate(&self, site_id: SiteId) -> Result<(), Error> {
if self.site_id == site_id { Ok(()) } else { Err(Error::InvalidOp) }
}
}