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! {
UsagesValidator
}
impl<T: LinkReference, L: Doublets<T>> Links<T> for UsagesValidator<T, L> {
forward!(count_links, each_links, create_links);
#[inline]
fn update_links(
&mut self,
query: &[T],
change: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let index = helpers::part(query, self.links.constants().index_part);
helpers::ensure_no_usages(&self.links, index)?;
self.links.update_links(query, change, handler)
}
#[inline]
fn delete_links(
&mut self,
query: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let index = helpers::part(query, self.links.constants().index_part);
helpers::ensure_no_usages(&self.links, index)?;
self.links.delete_links(query, handler)
}
}
decorator_struct! {
CascadeUsagesResolver
}
impl<T: LinkReference, L: Doublets<T>> CascadeUsagesResolver<T, L> {
fn cascade(
&mut self,
index: T,
visited: &mut Vec<T>,
handler: &mut dyn FnMut(Link<T>, Link<T>) -> Flow,
) -> Result<Flow, Error<T>> {
if visited.contains(&index) {
return Ok(Flow::Continue);
}
visited.push(index);
for usage in helpers::usages_of(self, index) {
if usage.index == index || !self.links.exist(usage.index) {
continue;
}
self.cascade(usage.index, visited, handler)?;
}
self.links.delete_links(&[index], handler)
}
}
impl<T: LinkReference, L: Doublets<T>> Links<T> for CascadeUsagesResolver<T, L> {
forward!(count_links, each_links, create_links, update_links);
#[inline]
fn delete_links(
&mut self,
query: &[T],
handler: WriteHandler<'_, T>,
) -> Result<Flow, Error<T>> {
let index = helpers::part(query, self.links.constants().index_part);
let mut fuse = Fuse::new(&mut *handler);
let mut visited = Vec::new();
self.cascade(index, &mut visited, &mut |before, after| {
fuse.call(before, after)
})
}
}