use crate::{
CausalContext, CausalDotStore, ExtensionType, Identifier, MvReg, OrArray, OrMap,
crdts::{
TypeVariantValue, Value,
orarray::{Position, Uid},
snapshot::{self, ToValue},
},
};
use std::{convert::Infallible, fmt};
pub fn values<C>(m: &OrArray<C>) -> snapshot::OrArray<snapshot::AllValues<'_, C::ValueRef<'_>>>
where
C: ExtensionType,
{
m.values()
}
#[allow(clippy::type_complexity)]
pub fn value<C>(
m: &OrArray<C>,
) -> Result<
snapshot::OrArray<snapshot::CollapsedValue<'_, C::ValueRef<'_>>>,
Box<snapshot::SingleValueError<<&OrArray<C> as ToValue>::LeafValue>>,
>
where
C: ExtensionType,
{
m.value()
}
pub fn create<C>() -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| m.create(cc, id)
}
pub fn insert<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<Value<C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| {
let uid = cc.next_dot_for(id).into();
let p = create_position_for_index(m, idx);
m.insert(uid, o, p, cc, id)
}
}
pub fn insert_map<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<OrMap<String, C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
insert(move |cc, id| (o)(cc, id).map_store(Value::Map), idx)
}
pub fn insert_array<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<OrArray<C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
insert(move |cc, id| (o)(cc, id).map_store(Value::Array), idx)
}
pub fn insert_register<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&CausalContext, Identifier) -> CausalDotStore<MvReg>,
C: ExtensionType + fmt::Debug + PartialEq,
{
insert(move |cc, id| (o)(cc, id).map_store(Value::Register), idx)
}
pub fn apply<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&TypeVariantValue<C>, &CausalContext, Identifier) -> CausalDotStore<Value<C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| {
let uid = uid_from_index(m, idx);
assert_ne!(idx, m.len(), "index out of bounds");
let p = create_position_for_index(m, idx);
m.apply(uid, o, p, cc, id)
}
}
pub fn apply_to_map<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&OrMap<String, C>, &CausalContext, Identifier) -> CausalDotStore<OrMap<String, C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
apply(
move |m, cc, id| (o)(&m.map, cc, id).map_store(Value::Map),
idx,
)
}
pub fn apply_to_array<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>,
C: ExtensionType + fmt::Debug + PartialEq,
{
apply(
move |m, cc, id| (o)(&m.array, cc, id).map_store(Value::Array),
idx,
)
}
pub fn apply_to_register<O, C>(
o: O,
idx: usize,
) -> impl FnOnce(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
O: FnOnce(&MvReg, &CausalContext, Identifier) -> CausalDotStore<MvReg>,
C: ExtensionType + fmt::Debug + PartialEq,
{
apply(
move |m, cc, id| (o)(&m.reg, cc, id).map_store(Value::Register),
idx,
)
}
pub fn mv<C>(
from: usize,
to: usize,
) -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| {
let uid = uid_from_index(m, from);
let p = create_position_for_index(m, to);
m.mv(uid, p, cc, id)
}
}
pub fn delete<'s, C>(
idx: usize,
) -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>> + 's
where
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| {
let uid = uid_from_index(m, idx);
m.delete(uid, cc, id)
}
}
pub fn clear<C>() -> impl Fn(&OrArray<C>, &CausalContext, Identifier) -> CausalDotStore<OrArray<C>>
where
C: ExtensionType + fmt::Debug + PartialEq,
{
move |m, cc, id| m.clear(cc, id)
}
fn ids<C>(m: &OrArray<C>) -> Vec<((), Uid, Position)> {
m.with_list(|_, _, _| Ok::<_, Infallible>(Some(())))
.unwrap()
}
fn create_position_for_index<C>(m: &OrArray<C>, idx: usize) -> Position {
if idx == 0 {
let min_p = m.iter_as_is().map(|(_, _, p)| p).min();
return Position::between(None, min_p);
}
if idx == m.len() {
let max_p = m.iter_as_is().map(|(_, _, p)| p).max();
return Position::between(max_p, None);
}
assert!(
idx < m.len(),
"index out of bounds ({idx} when length is {})",
m.len()
);
let ids = ids(m);
let pos_at_index = ids.get(idx).map(|(_, _, p)| *p);
let pos_at_previous_index = if idx == 0 {
None
} else {
Some(
ids.get(idx - 1)
.expect("we check for out-of-bounds above")
.2,
)
};
Position::between(pos_at_previous_index, pos_at_index)
}
fn uid_from_index<C>(m: &OrArray<C>, idx: usize) -> Uid {
ids(m)[idx].1
}