use super::{TriHashItem, TriHashMap};
use crate::{
DefaultHashBuilder, IdHashItem, id_hash_map,
support::{
alloc::{Allocator, Global},
daft_utils::IdLeaf,
},
};
use core::{
fmt,
hash::{BuildHasher, Hash},
};
use daft::Diffable;
use equivalent::Equivalent;
use ref_cast::RefCast;
impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> Diffable
for TriHashMap<T, S, A>
{
type Diff<'a>
= MapLeaf<'a, T, S, A>
where
T: 'a,
S: 'a,
A: 'a;
fn diff<'daft>(&'daft self, other: &'daft Self) -> Self::Diff<'daft> {
MapLeaf { before: self, after: other }
}
}
pub struct MapLeaf<
'daft,
T: TriHashItem,
S = DefaultHashBuilder,
A: Allocator = Global,
> {
pub before: &'daft TriHashMap<T, S, A>,
pub after: &'daft TriHashMap<T, S, A>,
}
impl<'a, 'daft, T: TriHashItem + fmt::Debug, S, A: Allocator> fmt::Debug
for MapLeaf<'daft, T, S, A>
where
T::K1<'a>: fmt::Debug,
T::K2<'a>: fmt::Debug,
T::K3<'a>: fmt::Debug,
T: 'a,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapLeaf")
.field("before", &self.before)
.field("after", &self.after)
.finish()
}
}
impl<'daft, T: TriHashItem, S, A: Allocator> Clone for MapLeaf<'daft, T, S, A> {
fn clone(&self) -> Self {
*self
}
}
impl<'daft, T: TriHashItem, S, A: Allocator> Copy for MapLeaf<'daft, T, S, A> {}
impl<'daft, T: TriHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator>
PartialEq for MapLeaf<'daft, T, S, A>
{
fn eq(&self, other: &Self) -> bool {
self.before == other.before && self.after == other.after
}
}
impl<'daft, T: TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
for MapLeaf<'daft, T, S, A>
{
}
impl<'daft, T: TriHashItem, S: Clone + BuildHasher, A: Clone + Allocator>
MapLeaf<'daft, T, S, A>
{
pub fn by_key1(self) -> id_hash_map::Diff<'daft, ByK1<T>, S, A> {
impl_diff_ref_cast!(
self,
id_hash_map::Diff::<'daft, ByK1<T>, S, A>,
key1,
get1,
contains_key1,
ByK1<T>
)
}
pub fn by_key2(self) -> id_hash_map::Diff<'daft, ByK2<T>, S, A> {
impl_diff_ref_cast!(
self,
id_hash_map::Diff::<'daft, ByK2<T>, S, A>,
key2,
get2,
contains_key2,
ByK2<T>
)
}
pub fn by_key3(self) -> id_hash_map::Diff<'daft, ByK3<T>, S, A> {
impl_diff_ref_cast!(
self,
id_hash_map::Diff::<'daft, ByK3<T>, S, A>,
key3,
get3,
contains_key3,
ByK3<T>
)
}
pub fn by_unique(self) -> Diff<'daft, T, S, A> {
let mut diff = Diff::with_hasher_in(
self.before.hasher().clone(),
self.before.allocator().clone(),
);
for item in self.before {
if let Some(after_item) =
self.after.get_unique(&item.key1(), &item.key2(), &item.key3())
{
diff.common.insert_overwrite(IdLeaf::new(item, after_item));
} else {
diff.removed.insert_overwrite(item);
}
}
for item in self.after {
if !self.before.contains_key_unique(
&item.key1(),
&item.key2(),
&item.key3(),
) {
diff.added.insert_overwrite(item);
}
}
diff
}
}
pub struct Diff<
'daft,
T: ?Sized + TriHashItem,
S = DefaultHashBuilder,
A: Allocator = Global,
> {
pub common: TriHashMap<IdLeaf<&'daft T>, S, A>,
pub added: TriHashMap<&'daft T, S, A>,
pub removed: TriHashMap<&'daft T, S, A>,
}
impl<'daft, T: ?Sized + TriHashItem, S: Default, A: Allocator + Default> Default
for Diff<'daft, T, S, A>
{
fn default() -> Self {
Self {
common: TriHashMap::default(),
added: TriHashMap::default(),
removed: TriHashMap::default(),
}
}
}
impl<'a, 'daft, T, S, A: Allocator> fmt::Debug for Diff<'daft, T, S, A>
where
T: ?Sized + TriHashItem + fmt::Debug,
T::K1<'a>: fmt::Debug,
T::K2<'a>: fmt::Debug,
T::K3<'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()
}
}
#[cfg(all(feature = "default-hasher", feature = "allocator-api2"))]
impl<'daft, T: ?Sized + TriHashItem> Diff<'daft, T> {
pub fn new() -> Self {
Self {
common: TriHashMap::new(),
added: TriHashMap::new(),
removed: TriHashMap::new(),
}
}
}
#[cfg(feature = "allocator-api2")]
impl<'daft, T: ?Sized + TriHashItem, S: Clone + BuildHasher> Diff<'daft, T, S> {
pub fn with_hasher(hasher: S) -> Self {
Self {
common: TriHashMap::with_hasher(hasher.clone()),
added: TriHashMap::with_hasher(hasher.clone()),
removed: TriHashMap::with_hasher(hasher),
}
}
}
impl<
'daft,
T: ?Sized + TriHashItem,
S: Clone + BuildHasher,
A: Clone + Allocator,
> Diff<'daft, T, S, A>
{
pub fn with_hasher_in(hasher: S, alloc: A) -> Self {
Self {
common: TriHashMap::with_hasher_in(hasher.clone(), alloc.clone()),
added: TriHashMap::with_hasher_in(hasher.clone(), alloc.clone()),
removed: TriHashMap::with_hasher_in(hasher, alloc),
}
}
}
impl<'daft, T: ?Sized + TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator>
Diff<'daft, T, S, A>
{
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_unchanged1<'a, Q>(&'a self, key1: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K1<'a>>,
{
self.common.get1(key1).is_some_and(|leaf| leaf.is_unchanged())
}
pub fn is_unchanged2<'a, Q>(&'a self, key2: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K2<'a>>,
{
self.common.get2(key2).is_some_and(|leaf| leaf.is_unchanged())
}
pub fn is_unchanged3<'a, Q>(&'a self, key3: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K3<'a>>,
{
self.common.get3(key3).is_some_and(|leaf| leaf.is_unchanged())
}
pub fn get_unchanged1<'a, Q>(&'a self, key: &Q) -> Option<&'daft T>
where
Q: ?Sized + Hash + Equivalent<T::K1<'a>>,
{
self.common
.get1(key)
.and_then(|leaf| leaf.is_unchanged().then_some(*leaf.before()))
}
pub fn get_unchanged2<'a, Q>(&'a self, key: &Q) -> Option<&'daft T>
where
Q: ?Sized + Hash + Equivalent<T::K2<'a>>,
{
self.common
.get2(key)
.and_then(|leaf| leaf.is_unchanged().then_some(*leaf.before()))
}
pub fn get_unchanged3<'a, Q>(&'a self, key: &Q) -> Option<&'daft T>
where
Q: ?Sized + Hash + Equivalent<T::K3<'a>>,
{
self.common
.get3(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_modified1<'a, Q>(&'a self, key1: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K1<'a>>,
{
self.common.get1(key1).is_some_and(|leaf| leaf.is_modified())
}
pub fn is_modified2<'a, Q>(&'a self, key2: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K2<'a>>,
{
self.common.get2(key2).is_some_and(|leaf| leaf.is_modified())
}
pub fn is_modified3<'a, Q>(&'a self, key3: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<T::K3<'a>>,
{
self.common.get3(key3).is_some_and(|leaf| leaf.is_modified())
}
pub fn get_modified1<'a, Q>(&'a self, key: &Q) -> Option<IdLeaf<&'daft T>>
where
Q: ?Sized + Hash + Equivalent<T::K1<'a>>,
{
self.common
.get1(key)
.and_then(|leaf| leaf.is_modified().then_some(*leaf))
}
pub fn get_modified2<'a, Q>(&'a self, key: &Q) -> Option<IdLeaf<&'daft T>>
where
Q: ?Sized + Hash + Equivalent<T::K2<'a>>,
{
self.common
.get2(key)
.and_then(|leaf| leaf.is_modified().then_some(*leaf))
}
pub fn get_modified3<'a, Q>(&'a self, key: &Q) -> Option<IdLeaf<&'daft T>>
where
Q: ?Sized + Hash + Equivalent<T::K3<'a>>,
{
self.common
.get3(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<T: TriHashItem> TriHashItem for IdLeaf<T> {
type K1<'a>
= T::K1<'a>
where
T: 'a;
type K2<'a>
= T::K2<'a>
where
T: 'a;
type K3<'a>
= T::K3<'a>
where
T: 'a;
fn key1(&self) -> Self::K1<'_> {
let before_key = self.before().key1();
if before_key != self.after().key1() {
panic!("key1 is different between before and after");
}
before_key
}
fn key2(&self) -> Self::K2<'_> {
let before_key = self.before().key2();
if before_key != self.after().key2() {
panic!("key2 is different between before and after");
}
before_key
}
fn key3(&self) -> Self::K3<'_> {
let before_key = self.before().key3();
if before_key != self.after().key3() {
panic!("key3 is different between before and after");
}
before_key
}
#[inline]
fn upcast_key1<'short, 'long: 'short>(
long: Self::K1<'long>,
) -> Self::K1<'short> {
T::upcast_key1(long)
}
#[inline]
fn upcast_key2<'short, 'long: 'short>(
long: Self::K2<'long>,
) -> Self::K2<'short> {
T::upcast_key2(long)
}
#[inline]
fn upcast_key3<'short, 'long: 'short>(
long: Self::K3<'long>,
) -> Self::K3<'short> {
T::upcast_key3(long)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RefCast)]
#[repr(transparent)]
pub struct ByK1<T>(pub T);
impl<T> ByK1<T> {
#[inline]
pub fn ref_cast(item: &T) -> &Self {
RefCast::ref_cast(item)
}
#[inline]
pub fn ref_cast_mut(item: &mut T) -> &mut Self {
RefCast::ref_cast_mut(item)
}
}
impl<T: TriHashItem> IdHashItem for ByK1<T> {
type Key<'a>
= T::K1<'a>
where
T: 'a;
#[inline]
fn key(&self) -> Self::Key<'_> {
self.0.key1()
}
#[inline]
fn upcast_key<'short, 'long: 'short>(
long: Self::Key<'long>,
) -> Self::Key<'short> {
T::upcast_key1(long)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RefCast)]
#[repr(transparent)]
pub struct ByK2<T>(pub T);
impl<T> ByK2<T> {
#[inline]
pub fn ref_cast(item: &T) -> &Self {
RefCast::ref_cast(item)
}
#[inline]
pub fn ref_cast_mut(item: &mut T) -> &mut Self {
RefCast::ref_cast_mut(item)
}
}
impl<T: TriHashItem> IdHashItem for ByK2<T> {
type Key<'a>
= T::K2<'a>
where
T: 'a;
#[inline]
fn key(&self) -> Self::Key<'_> {
self.0.key2()
}
#[inline]
fn upcast_key<'short, 'long: 'short>(
long: Self::Key<'long>,
) -> Self::Key<'short> {
T::upcast_key2(long)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RefCast)]
#[repr(transparent)]
pub struct ByK3<T>(pub T);
impl<T> ByK3<T> {
#[inline]
pub fn ref_cast(item: &T) -> &Self {
RefCast::ref_cast(item)
}
#[inline]
pub fn ref_cast_mut(item: &mut T) -> &mut Self {
RefCast::ref_cast_mut(item)
}
}
impl<T: TriHashItem> IdHashItem for ByK3<T> {
type Key<'a>
= T::K3<'a>
where
T: 'a;
#[inline]
fn key(&self) -> Self::Key<'_> {
self.0.key3()
}
#[inline]
fn upcast_key<'short, 'long: 'short>(
long: Self::Key<'long>,
) -> Self::Key<'short> {
T::upcast_key3(long)
}
}