use std::sync::OnceLock;
use doublets::data::{Flow, LinksConstants, ReadHandler, WriteHandler};
use doublets::{Doublets, Error, Link as DoubletsLink, Links};
use crate::link::Link;
use crate::link_storage::LinkStorage;
pub fn link_storage_constants() -> &'static LinksConstants<u32> {
static CONSTANTS: OnceLock<LinksConstants<u32>> = OnceLock::new();
CONSTANTS.get_or_init(LinksConstants::external)
}
fn as_doublets_link(link: &Link) -> DoubletsLink<u32> {
DoubletsLink::new(link.index, link.source, link.target)
}
fn part(query: &[u32], index: usize) -> u32 {
query.get(index).copied().unwrap_or(0)
}
fn all(storage: &LinkStorage) -> Vec<Link> {
let mut matched: Vec<Link> = storage.all().into_iter().copied().collect();
matched.sort_by_key(|link| link.index);
matched
}
fn by_pattern(storage: &LinkStorage, source: u32, target: u32) -> Vec<Link> {
let constants = link_storage_constants();
let (any, null) = (constants.any, constants.null);
match (source == any, target == any) {
(true, true) => all(storage),
(true, false) if target == null => Vec::new(),
(true, false) => {
let mut matched: Vec<Link> = storage
.all()
.into_iter()
.filter(|link| link.target == target)
.copied()
.collect();
matched.sort_by_key(|link| link.index);
matched
}
(false, true) if source == null => Vec::new(),
(false, true) => {
let mut matched: Vec<Link> = storage
.all()
.into_iter()
.filter(|link| link.source == source)
.copied()
.collect();
matched.sort_by_key(|link| link.index);
matched
}
(false, false) if source == null || target == null => Vec::new(),
(false, false) => storage
.all()
.into_iter()
.filter(|link| link.source == source && link.target == target)
.min_by_key(|link| link.index)
.copied()
.into_iter()
.collect(),
}
}
fn matching(storage: &LinkStorage, query: &[u32]) -> Vec<Link> {
let any = link_storage_constants().any;
match *query {
[] => all(storage),
[index] if index == any => all(storage),
[index] => storage.get(index).copied().into_iter().collect(),
[index, value] if index == any && value == any => all(storage),
[index, value] if index == any => {
let mut matched = by_pattern(storage, value, any);
matched.extend(by_pattern(storage, any, value));
matched
}
[index, value] => storage
.get(index)
.filter(|link| value == any || link.source == value || link.target == value)
.copied()
.into_iter()
.collect(),
[index, source, target] if index == any => by_pattern(storage, source, target),
[index, source, target] => storage
.get(index)
.filter(|link| {
(source == any || link.source == source) && (target == any || link.target == target)
})
.copied()
.into_iter()
.collect(),
_ => Vec::new(),
}
}
impl Links<u32> for LinkStorage {
fn constants(&self) -> &LinksConstants<u32> {
link_storage_constants()
}
fn count_links(&self, query: &[u32]) -> u32 {
matching(self, query).len() as u32
}
fn create_links(
&mut self,
_query: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
let index = self.create(0, 0);
let created = Link::new(index, 0, 0);
Ok(handler(DoubletsLink::nothing(), as_doublets_link(&created)))
}
fn each_links(&self, query: &[u32], handler: ReadHandler<'_, u32>) -> Flow {
for link in matching(self, query) {
if handler(as_doublets_link(&link)) == Flow::Break {
return Flow::Break;
}
}
Flow::Continue
}
fn update_links(
&mut self,
query: &[u32],
change: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
let index = part(query, 0);
let source = part(change, 1);
let target = part(change, 2);
let before = self
.update_raw(index, source, target)
.map_err(|_| Error::NotExists(index))?;
let after = Link::new(index, source, target);
Ok(handler(as_doublets_link(&before), as_doublets_link(&after)))
}
fn delete_links(
&mut self,
query: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
let index = part(query, 0);
let before = self
.delete_raw(index)
.map_err(|_| Error::NotExists(index))?;
Ok(handler(as_doublets_link(&before), DoubletsLink::nothing()))
}
}
impl Doublets<u32> for LinkStorage {
fn get_link(&self, index: u32) -> Option<DoubletsLink<u32>> {
self.get(index).map(as_doublets_link)
}
}
impl Links<u32> for &mut LinkStorage {
fn constants(&self) -> &LinksConstants<u32> {
(**self).constants()
}
fn count_links(&self, query: &[u32]) -> u32 {
(**self).count_links(query)
}
fn create_links(
&mut self,
query: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
(**self).create_links(query, handler)
}
fn each_links(&self, query: &[u32], handler: ReadHandler<'_, u32>) -> Flow {
(**self).each_links(query, handler)
}
fn update_links(
&mut self,
query: &[u32],
change: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
(**self).update_links(query, change, handler)
}
fn delete_links(
&mut self,
query: &[u32],
handler: WriteHandler<'_, u32>,
) -> Result<Flow, Error<u32>> {
(**self).delete_links(query, handler)
}
}
impl Doublets<u32> for &mut LinkStorage {
fn get_link(&self, index: u32) -> Option<DoubletsLink<u32>> {
(**self).get_link(index)
}
}