use super::{IdOrdItem, IdOrdMap};
use crate::support::daft_utils::IdLeaf;
use core::fmt;
use daft::Diffable;
use equivalent::Comparable;
impl<T: IdOrdItem> Diffable for IdOrdMap<T> {
type Diff<'a>
= Diff<'a, T>
where
T: 'a;
fn diff<'daft>(&'daft self, other: &'daft Self) -> Self::Diff<'daft> {
let mut diff = Diff::new();
for item in self {
if let Some(other_item) = other.get(&item.key()) {
diff.common.insert_overwrite(IdLeaf::new(item, other_item));
} else {
diff.removed.insert_overwrite(item);
}
}
for item in other {
if !self.contains_key(&item.key()) {
diff.added.insert_overwrite(item);
}
}
diff
}
}
pub struct Diff<'daft, T: ?Sized + IdOrdItem> {
pub common: IdOrdMap<IdLeaf<&'daft T>>,
pub added: IdOrdMap<&'daft T>,
pub removed: IdOrdMap<&'daft T>,
}
impl<'a, 'daft, T> fmt::Debug for Diff<'daft, T>
where
T: ?Sized + IdOrdItem + fmt::Debug,
T::Key<'a>: fmt::Debug,
T: 'a,
'daft: 'a,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Diff")
.field("common", &self.common)
.field("added", &self.added)
.field("removed", &self.removed)
.finish()
}
}
impl<'daft, T: ?Sized + IdOrdItem> Diff<'daft, T> {
pub fn new() -> Self {
Self {
common: IdOrdMap::new(),
added: IdOrdMap::new(),
removed: IdOrdMap::new(),
}
}
}
impl<'daft, T: ?Sized + IdOrdItem + Eq> Diff<'daft, T> {
pub fn unchanged(&self) -> impl Iterator<Item = &'daft T> + '_ {
self.common
.iter()
.filter_map(|leaf| leaf.is_unchanged().then_some(*leaf.before()))
}
pub fn is_unchanged<'a, Q>(&'a self, key: &Q) -> bool
where
Q: ?Sized + Comparable<T::Key<'a>>,
{
self.common.get(key).is_some_and(|leaf| leaf.is_unchanged())
}
pub fn get_unchanged<'a, Q>(&'a self, key: &Q) -> Option<&'daft T>
where
Q: ?Sized + Comparable<T::Key<'a>>,
{
self.common
.get(key)
.and_then(|leaf| leaf.is_unchanged().then_some(*leaf.before()))
}
pub fn modified(&self) -> impl Iterator<Item = IdLeaf<&'daft T>> + '_ {
self.common
.iter()
.filter_map(|leaf| leaf.is_modified().then_some(*leaf))
}
pub fn is_modified<'a, Q>(&'a self, key: &Q) -> bool
where
Q: ?Sized + Comparable<T::Key<'a>>,
{
self.common.get(key).is_some_and(|leaf| leaf.is_modified())
}
pub fn get_modified<'a, Q>(&'a self, key: &Q) -> Option<IdLeaf<&'daft T>>
where
Q: ?Sized + Comparable<T::Key<'a>>,
{
self.common
.get(key)
.and_then(|leaf| leaf.is_modified().then_some(*leaf))
}
pub fn modified_diff(&self) -> impl Iterator<Item = T::Diff<'daft>> + '_
where
T: Diffable,
{
self.modified().map(|leaf| leaf.diff_pair())
}
}
impl<'daft, T: IdOrdItem> Default for Diff<'daft, T> {
fn default() -> Self {
Self::new()
}
}
impl<T: IdOrdItem> IdOrdItem for IdLeaf<T> {
type Key<'a>
= T::Key<'a>
where
T: 'a;
fn key(&self) -> Self::Key<'_> {
let before_key = self.before().key();
if before_key != self.after().key() {
panic!("key is different between before and after");
}
before_key
}
#[inline]
fn upcast_key<'short, 'long: 'short>(
long: Self::Key<'long>,
) -> Self::Key<'short> {
T::upcast_key(long)
}
}