use alloc::vec::Vec;
use core::fmt::Debug;
use crate::{
builders::{ChangesetFormat, PatchsetFormat, format::Format},
encoding::{MaybeValue, Value},
};
#[derive(Debug, Clone)]
pub(crate) enum Operation<F: Format<S, B>, S, B> {
Insert {
values: Vec<Value<S, B>>,
indirect: bool,
},
Delete {
data: F::DeleteData,
indirect: bool,
},
Update {
values: Vec<(F::Old, MaybeValue<S, B>)>,
indirect: bool,
},
}
impl<F: Format<S, B>, S, B> Operation<F, S, B> {
#[inline]
pub(crate) fn indirect(&self) -> bool {
match self {
Self::Insert { indirect, .. }
| Self::Delete { indirect, .. }
| Self::Update { indirect, .. } => *indirect,
}
}
}
impl<F: Format<S, B>, S: PartialEq + AsRef<str>, B: PartialEq + AsRef<[u8]>> PartialEq
for Operation<F, S, B>
where
F::DeleteData: PartialEq,
F::Old: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.indirect() != other.indirect() {
return false;
}
match (self, other) {
(Self::Insert { values: a, .. }, Self::Insert { values: b, .. }) => a == b,
(Self::Delete { data: a, .. }, Self::Delete { data: b, .. }) => a == b,
(Self::Update { values: a, .. }, Self::Update { values: b, .. }) => a == b,
_ => false,
}
}
}
impl<F: Format<S, B>, S: Eq + AsRef<str>, B: Eq + AsRef<[u8]>> Eq for Operation<F, S, B>
where
F::DeleteData: Eq,
F::Old: Eq,
{
}
pub trait Indirect: Sized {
#[must_use]
fn indirect(self, indirect: bool) -> Self;
}
pub trait Reverse {
type Output;
fn reverse(self) -> Self::Output;
}
impl<S: Clone + Debug + AsRef<str>, B: Clone + Debug + AsRef<[u8]>> Reverse
for Operation<ChangesetFormat, S, B>
{
type Output = Self;
fn reverse(self) -> Self::Output {
match self {
Self::Insert { values, indirect } => Self::Delete {
data: values,
indirect,
},
Self::Delete { data, indirect } => Self::Insert {
values: data,
indirect,
},
Self::Update { values, indirect } => Self::Update {
values: values.into_iter().map(|(old, new)| (new, old)).collect(),
indirect,
},
}
}
}
impl<S: Clone + Debug + PartialEq + AsRef<str>, B: Clone + Debug + PartialEq + AsRef<[u8]>>
core::ops::Add for Operation<ChangesetFormat, S, B>
{
type Output = Option<Self>;
fn add(self, rhs: Self) -> Self::Output {
let indirect = rhs.indirect();
match (self, rhs) {
(Self::Insert { values: lhs, .. }, Self::Insert { .. }) => Some(Self::Insert {
values: lhs,
indirect,
}),
(
Self::Insert { mut values, .. },
Self::Update {
values: updates, ..
},
) => {
for (idx, (_old, new)) in updates.into_iter().enumerate() {
if let Some(new_val) = new {
values[idx] = new_val;
}
}
Some(Self::Insert { values, indirect })
}
(Self::Insert { .. }, Self::Delete { .. }) => None,
(Self::Update { values: lhs, .. }, Self::Insert { .. }) => Some(Self::Update {
values: lhs,
indirect,
}),
(Self::Update { values: lhs, .. }, Self::Update { values: rhs, .. }) => {
let merged = lhs
.into_iter()
.zip(rhs)
.map(|((old, _mid), (_mid2, new))| (old, new))
.collect();
Some(Self::Update {
values: merged,
indirect,
})
}
(Self::Update { values: upd, .. }, Self::Delete { .. }) => {
let old_values = upd
.into_iter()
.map(|(old, _new)| old.unwrap_or(Value::Null))
.collect();
Some(Self::Delete {
data: old_values,
indirect,
})
}
(Self::Delete { data: del, .. }, Self::Insert { values: ins, .. }) => {
if del == ins {
None } else {
let update_values = del
.into_iter()
.zip(ins)
.map(|(old, new)| (Some(old), Some(new)))
.collect();
Some(Self::Update {
values: update_values,
indirect,
})
}
}
(Self::Delete { data: lhs, .. }, Self::Update { .. } | Self::Delete { .. }) => {
Some(Self::Delete {
data: lhs,
indirect,
})
}
}
}
}
impl<S: Clone + PartialEq + AsRef<str>, B: Clone + PartialEq + AsRef<[u8]>> core::ops::Add
for Operation<PatchsetFormat, S, B>
{
type Output = Option<Self>;
fn add(self, rhs: Self) -> Self::Output {
let indirect = rhs.indirect();
match (self, rhs) {
(Self::Insert { values: lhs, .. }, Self::Insert { .. }) => Some(Self::Insert {
values: lhs,
indirect,
}),
(
Self::Insert { mut values, .. },
Self::Update {
values: updates, ..
},
) => {
for (idx, ((), new)) in updates.into_iter().enumerate() {
if let Some(new_val) = new {
values[idx] = new_val;
}
}
Some(Self::Insert { values, indirect })
}
(Self::Insert { .. }, Self::Delete { data: (), .. }) => None,
(Self::Update { values: lhs, .. }, Self::Insert { .. }) => Some(Self::Update {
values: lhs,
indirect,
}),
(Self::Update { values: lhs, .. }, Self::Update { values: rhs, .. }) => {
let merged = lhs
.into_iter()
.zip(rhs)
.map(|((old, _mid), (_mid2, new))| (old, new))
.collect();
Some(Self::Update {
values: merged,
indirect,
})
}
(Self::Update { .. }, Self::Delete { data, .. }) => {
Some(Self::Delete { data, indirect })
}
(Self::Delete { data: (), .. }, Self::Insert { values: ins, .. }) => {
let update_values = ins.into_iter().map(|new| ((), Some(new))).collect();
Some(Self::Update {
values: update_values,
indirect,
})
}
(Self::Delete { data: lhs, .. }, Self::Update { .. } | Self::Delete { .. }) => {
Some(Self::Delete {
data: lhs,
indirect,
})
}
}
}
}