use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::sync::{Arc, Mutex, RwLock};
use automerge::{ChangeHash, ObjId, Prop, ReadDoc, transaction::Transactable};
use crate::{Automorph, ChangeReport, Error, PrimitiveChanged, Result, ScalarCursor};
impl<T: Automorph> Automorph for Box<T> {
type Changes = T::Changes;
type Cursor = T::Cursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
(**self).save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(Box::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(Box::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
(**self).diff(doc, obj, prop)
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
(**self).diff_at(doc, obj, prop, heads)
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
(**self).update(doc, obj, prop)
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
(**self).update_at(doc, obj, prop, heads)
}
}
impl<T: Automorph + PartialEq> Automorph for Rc<T> {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
(**self).save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(Rc::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(Rc::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let inner_changes = (**self).diff(doc, obj, prop)?;
Ok(PrimitiveChanged::new(inner_changes.any()))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let inner_changes = (**self).diff_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(inner_changes.any()))
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let new_value = Self::load(doc, obj, prop)?;
let changed = **self != *new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let new_value = Self::load_at(doc, obj, prop, heads)?;
let changed = **self != *new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
}
impl<T: Automorph + PartialEq> Automorph for Arc<T> {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
(**self).save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(Arc::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(Arc::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let inner_changes = (**self).diff(doc, obj, prop)?;
Ok(PrimitiveChanged::new(inner_changes.any()))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let inner_changes = (**self).diff_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(inner_changes.any()))
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let new_value = Self::load(doc, obj, prop)?;
let changed = **self != *new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let new_value = Self::load_at(doc, obj, prop, heads)?;
let changed = **self != *new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
}
impl<T: Automorph + Copy> Automorph for Cell<T> {
type Changes = T::Changes;
type Cursor = T::Cursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
self.get().save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(Cell::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(Cell::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.get().diff(doc, obj, prop)
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.get().diff_at(doc, obj, prop, heads)
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let mut inner = self.get();
let changes = inner.update(doc, obj, prop)?;
if changes.any() {
self.set(inner);
}
Ok(changes)
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let mut inner = self.get();
let changes = inner.update_at(doc, obj, prop, heads)?;
if changes.any() {
self.set(inner);
}
Ok(changes)
}
}
impl<T: Automorph> Automorph for RefCell<T> {
type Changes = T::Changes;
type Cursor = T::Cursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
self.borrow().save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(RefCell::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(RefCell::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.borrow().diff(doc, obj, prop)
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.borrow().diff_at(doc, obj, prop, heads)
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.borrow_mut().update(doc, obj, prop)
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.borrow_mut().update_at(doc, obj, prop, heads)
}
}
impl<T: Automorph> Automorph for Mutex<T> {
type Changes = T::Changes;
type Cursor = T::Cursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
self.lock()
.map_err(|_| Error::invalid_value("mutex poisoned"))?
.save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(Mutex::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(Mutex::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.lock()
.map_err(|_| Error::invalid_value("mutex poisoned"))?
.diff(doc, obj, prop)
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.lock()
.map_err(|_| Error::invalid_value("mutex poisoned"))?
.diff_at(doc, obj, prop, heads)
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.get_mut()
.map_err(|_| Error::invalid_value("mutex poisoned"))?
.update(doc, obj, prop)
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.get_mut()
.map_err(|_| Error::invalid_value("mutex poisoned"))?
.update_at(doc, obj, prop, heads)
}
}
impl<T: Automorph> Automorph for RwLock<T> {
type Changes = T::Changes;
type Cursor = T::Cursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
self.read()
.map_err(|_| Error::invalid_value("rwlock poisoned"))?
.save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
Ok(RwLock::new(T::load(doc, obj, prop)?))
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
Ok(RwLock::new(T::load_at(doc, obj, prop, heads)?))
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.read()
.map_err(|_| Error::invalid_value("rwlock poisoned"))?
.diff(doc, obj, prop)
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.read()
.map_err(|_| Error::invalid_value("rwlock poisoned"))?
.diff_at(doc, obj, prop, heads)
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
self.write()
.map_err(|_| Error::invalid_value("rwlock poisoned"))?
.update(doc, obj, prop)
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
self.write()
.map_err(|_| Error::invalid_value("rwlock poisoned"))?
.update_at(doc, obj, prop, heads)
}
}