use automerge::{ChangeHash, ObjId, Prop, ReadDoc, ScalarValue, Value, transaction::Transactable};
use crate::{Automorph, Error, PrimitiveChanged, Result, ScalarCursor};
impl Automorph for bool {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.to_bool() == Some(*self) => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, *self)?;
}
_ => {
doc.put(obj, prop, *self)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let new_value = x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let new_value = x
.to_bool()
.ok_or_else(|| Error::type_mismatch("bool", Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch("bool", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
}
impl Automorph for char {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let s = self.to_string();
s.save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(c),
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(c),
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(PrimitiveChanged::new(*self != c)),
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(PrimitiveChanged::new(*self != c)),
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => {
let changed = *self != c;
if changed {
*self = c;
}
Ok(PrimitiveChanged::new(changed))
}
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
if let Some(s) = x.to_str() {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => {
let changed = *self != c;
if changed {
*self = c;
}
Ok(PrimitiveChanged::new(changed))
}
_ => Err(Error::invalid_value("expected single character")),
}
} else {
Err(Error::type_mismatch("char", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("char", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
}
impl Automorph for () {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.is_null() => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, ScalarValue::Null)?;
}
_ => {
doc.put(obj, prop, ScalarValue::Null)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(()),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(()),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(PrimitiveChanged::new(false)),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(PrimitiveChanged::new(false)),
}
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(PrimitiveChanged::new(false)),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(PrimitiveChanged::new(false)),
}
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(PrimitiveChanged::new(false)),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(PrimitiveChanged::new(false)),
}
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) if x.is_null() => Ok(PrimitiveChanged::new(false)),
Some((v, _)) => Err(Error::type_mismatch("null", Some(format!("{:?}", v)))),
None => Ok(PrimitiveChanged::new(false)),
}
}
}
macro_rules! impl_signed_int {
($($t:ty),*) => {
$(
impl Automorph for $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<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let value = *self as i64;
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.to_i64() == Some(value) => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, value)?;
}
_ => {
doc.put(obj, prop, value)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let new_value = x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let new_value = x.to_i64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
}
)*
};
}
macro_rules! impl_unsigned_int {
($($t:ty),*) => {
$(
impl Automorph for $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<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let value = *self as u64;
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.to_u64() == Some(value) => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, value)?;
}
_ => {
doc.put(obj, prop, value)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let doc_value = x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let new_value = x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn update_at<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let new_value = x.to_u64()
.map(|v| v as $t)
.ok_or_else(|| Error::type_mismatch(stringify!($t), Some(format!("{:?}", x))))?;
let changed = *self != new_value;
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
Some((v, _)) => Err(Error::type_mismatch(stringify!($t), Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
}
)*
};
}
impl_signed_int!(i8, i16, i32, i64);
impl_unsigned_int!(u8, u16, u32, u64);
impl Automorph for isize {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let value = *self as i64;
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.to_i64() == Some(value) => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, value)?;
}
_ => {
doc.put(obj, prop, value)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let v = x
.to_i64()
.ok_or_else(|| Error::type_mismatch("isize", Some(format!("{:?}", x))))?;
isize::try_from(v).map_err(|_| {
Error::invalid_value(format!(
"value {} out of range for isize (valid range: {} to {})",
v,
isize::MIN,
isize::MAX
))
})
}
Some((v, _)) => Err(Error::type_mismatch("isize", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let v = x
.to_i64()
.ok_or_else(|| Error::type_mismatch("isize", Some(format!("{:?}", x))))?;
isize::try_from(v).map_err(|_| {
Error::invalid_value(format!(
"value {} out of range for isize (valid range: {} to {})",
v,
isize::MIN,
isize::MAX
))
})
}
Some((v, _)) => Err(Error::type_mismatch("isize", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
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 Automorph for usize {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let value = *self as u64;
let cur = doc.get(obj, prop.clone())?;
match cur {
Some((Value::Scalar(x), _)) if x.to_u64() == Some(value) => {}
_ => match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, value)?;
}
_ => {
doc.put(obj, prop, value)?;
}
},
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
let v = x
.to_u64()
.ok_or_else(|| Error::type_mismatch("usize", Some(format!("{:?}", x))))?;
usize::try_from(v).map_err(|_| {
Error::invalid_value(format!(
"value {} out of range for usize (valid range: 0 to {})",
v,
usize::MAX
))
})
}
Some((v, _)) => Err(Error::type_mismatch("usize", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
let v = x
.to_u64()
.ok_or_else(|| Error::type_mismatch("usize", Some(format!("{:?}", x))))?;
usize::try_from(v).map_err(|_| {
Error::invalid_value(format!(
"value {} out of range for usize (valid range: 0 to {})",
v,
usize::MAX
))
})
}
Some((v, _)) => Err(Error::type_mismatch("usize", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
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 Automorph for i128 {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let bytes = self.to_be_bytes().to_vec();
bytes.save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
if let Some(bytes) = x.to_bytes() {
if bytes.len() == 16 {
let arr: [u8; 16] = bytes
.try_into()
.map_err(|_| Error::invalid_value("byte slice conversion failed"))?;
Ok(i128::from_be_bytes(arr))
} else {
Err(Error::invalid_value("expected 16 bytes for i128"))
}
} else {
Err(Error::type_mismatch("i128", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("i128", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
if let Some(bytes) = x.to_bytes() {
if bytes.len() == 16 {
let arr: [u8; 16] = bytes
.try_into()
.map_err(|_| Error::invalid_value("byte slice conversion failed"))?;
Ok(i128::from_be_bytes(arr))
} else {
Err(Error::invalid_value("expected 16 bytes for i128"))
}
} else {
Err(Error::type_mismatch("i128", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("i128", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
let changed = *self != doc_value;
if changed {
*self = doc_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 doc_value = Self::load_at(doc, obj, prop, heads)?;
let changed = *self != doc_value;
if changed {
*self = doc_value;
}
Ok(PrimitiveChanged::new(changed))
}
}
impl Automorph for u128 {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let bytes = self.to_be_bytes().to_vec();
bytes.save(doc, obj, prop)
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => {
if let Some(bytes) = x.to_bytes() {
if bytes.len() == 16 {
let arr: [u8; 16] = bytes
.try_into()
.map_err(|_| Error::invalid_value("byte slice conversion failed"))?;
Ok(u128::from_be_bytes(arr))
} else {
Err(Error::invalid_value("expected 16 bytes for u128"))
}
} else {
Err(Error::type_mismatch("u128", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("u128", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => {
if let Some(bytes) = x.to_bytes() {
if bytes.len() == 16 {
let arr: [u8; 16] = bytes
.try_into()
.map_err(|_| Error::invalid_value("byte slice conversion failed"))?;
Ok(u128::from_be_bytes(arr))
} else {
Err(Error::invalid_value("expected 16 bytes for u128"))
}
} else {
Err(Error::type_mismatch("u128", Some(format!("{:?}", x))))
}
}
Some((v, _)) => Err(Error::type_mismatch("u128", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
Ok(PrimitiveChanged::new(*self != doc_value))
}
fn update<D: ReadDoc>(
&mut self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
let changed = *self != doc_value;
if changed {
*self = doc_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 doc_value = Self::load_at(doc, obj, prop, heads)?;
let changed = *self != doc_value;
if changed {
*self = doc_value;
}
Ok(PrimitiveChanged::new(changed))
}
}
impl Automorph for f32 {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let value = *self as f64;
let prop: Prop = prop.into();
let obj = obj.as_ref();
let cur = doc.get(obj, prop.clone())?;
let should_update = match &cur {
Some((Value::Scalar(x), _)) => {
if let Some(existing) = x.to_f64() {
(existing as f32).to_bits() != self.to_bits()
} else {
true
}
}
_ => true,
};
if should_update {
match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, value)?;
}
_ => {
doc.put(obj, prop, value)?;
}
}
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => x
.to_f64()
.map(|v| v as f32)
.ok_or_else(|| Error::type_mismatch("f32", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("f32", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => x
.to_f64()
.map(|v| v as f32)
.ok_or_else(|| Error::type_mismatch("f32", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("f32", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
let changed = self.to_bits() != doc_value.to_bits();
Ok(PrimitiveChanged::new(changed))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
let changed = self.to_bits() != doc_value.to_bits();
Ok(PrimitiveChanged::new(changed))
}
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.to_bits() != new_value.to_bits();
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.to_bits() != new_value.to_bits();
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
}
impl Automorph for f64 {
type Changes = PrimitiveChanged;
type Cursor = ScalarCursor;
fn save<D: Transactable + ReadDoc>(
&self,
doc: &mut D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<()> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
let cur = doc.get(obj, prop.clone())?;
let should_update = match &cur {
Some((Value::Scalar(x), _)) => {
if let Some(existing) = x.to_f64() {
existing.to_bits() != self.to_bits()
} else {
true
}
}
_ => true,
};
if should_update {
match (&cur, &prop) {
(None, Prop::Seq(s)) => {
doc.insert(obj, *s, *self)?;
}
_ => {
doc.put(obj, prop, *self)?;
}
}
}
Ok(())
}
fn load<D: ReadDoc>(doc: &D, obj: impl AsRef<ObjId>, prop: impl Into<Prop>) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get(obj, prop)? {
Some((Value::Scalar(x), _)) => x
.to_f64()
.ok_or_else(|| Error::type_mismatch("f64", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("f64", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn load_at<D: ReadDoc>(
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self> {
let prop: Prop = prop.into();
let obj = obj.as_ref();
match doc.get_at(obj, prop, heads)? {
Some((Value::Scalar(x), _)) => x
.to_f64()
.ok_or_else(|| Error::type_mismatch("f64", Some(format!("{:?}", x)))),
Some((v, _)) => Err(Error::type_mismatch("f64", Some(format!("{:?}", v)))),
None => Err(Error::missing_value()),
}
}
fn diff<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
) -> Result<Self::Changes> {
let doc_value = Self::load(doc, obj, prop)?;
let changed = self.to_bits() != doc_value.to_bits();
Ok(PrimitiveChanged::new(changed))
}
fn diff_at<D: ReadDoc>(
&self,
doc: &D,
obj: impl AsRef<ObjId>,
prop: impl Into<Prop>,
heads: &[ChangeHash],
) -> Result<Self::Changes> {
let doc_value = Self::load_at(doc, obj, prop, heads)?;
let changed = self.to_bits() != doc_value.to_bits();
Ok(PrimitiveChanged::new(changed))
}
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.to_bits() != new_value.to_bits();
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.to_bits() != new_value.to_bits();
if changed {
*self = new_value;
}
Ok(PrimitiveChanged::new(changed))
}
}