use std::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
use data::{Flow, LinkReference, LinksConstants};
use super::{
helpers,
macros::{decorator_struct, forward},
};
use crate::{
data::{ReadHandler, WriteHandler},
Doublets, Error, Fuse, Link, Links,
};
decorator_struct! {
UniquenessValidator
}
impl<T: LinkReference, L: Doublets<T>> Links<T> for UniquenessValidator<T, L> {
forward!(count_links, each_links, create_links, delete_links);
#[inline]
fn update_links(
&mut self,
query: &[T],
change: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let constants = self.links.constants();
let source = helpers::part(change, constants.source_part);
let target = helpers::part(change, constants.target_part);
helpers::ensure_does_not_exist(&self.links, source, target)?;
self.links.update_links(query, change, handler)
}
}
decorator_struct! {
UniquenessResolver
}
impl<T: LinkReference, L: Doublets<T>> UniquenessResolver<T, L> {
#[inline]
fn resolve_address_change_conflict(
&mut self,
old: T,
new: T,
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
resolve_address_change_conflict(self, old, new, handler)
}
}
impl<T: LinkReference, L: Doublets<T>> Links<T> for UniquenessResolver<T, L> {
forward!(count_links, each_links, create_links, delete_links);
#[inline]
fn update_links(
&mut self,
query: &[T],
change: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let constants = self.links.constants();
let source = helpers::part(change, constants.source_part);
let target = helpers::part(change, constants.target_part);
let old = helpers::part(query, constants.index_part);
let Some(new) = self.links.search(source, target) else {
return self.links.update_links(query, change, handler);
};
self.resolve_address_change_conflict(old, new, handler)
}
}
decorator_struct! {
CascadeUniquenessAndUsagesResolver
}
impl<T: LinkReference, L: Doublets<T>> CascadeUniquenessAndUsagesResolver<T, L> {
#[inline]
fn resolve_address_change_conflict(
&mut self,
old: T,
new: T,
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let mut fuse = Fuse::new(&mut *handler);
helpers::merge_usages(self, old, new, |before, after| fuse.call(before, after))?;
resolve_address_change_conflict(self, old, new, &mut |before, after| {
fuse.call(before, after)
})
}
}
impl<T: LinkReference, L: Doublets<T>> Links<T> for CascadeUniquenessAndUsagesResolver<T, L> {
forward!(count_links, each_links, create_links, delete_links);
#[inline]
fn update_links(
&mut self,
query: &[T],
change: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let constants = self.links.constants();
let source = helpers::part(change, constants.source_part);
let target = helpers::part(change, constants.target_part);
let old = helpers::part(query, constants.index_part);
let Some(new) = self.links.search(source, target) else {
return self.links.update_links(query, change, handler);
};
self.resolve_address_change_conflict(old, new, handler)
}
}
#[inline]
fn resolve_address_change_conflict<T, D>(
links: &mut D,
old: T,
new: T,
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>>
where
T: LinkReference,
D: Doublets<T>,
{
let mut fuse = Fuse::new(&mut *handler);
if old != new && links.exist(old) {
links.delete_links(&[old], &mut |before, after| fuse.call(before, after))?;
}
let survivor = links.try_get_link(new)?;
Ok(fuse.call(survivor.clone(), survivor))
}