use std::{fmt::Debug, hash::Hash, marker::PhantomData};
use crate::core::{
GraphBase, GraphWeak, Neighbors,
base::NeighborRef,
borrow::OwnableRef,
id::IdType,
marker::{Directed, Direction, EdgeType, Undirected},
};
pub struct Implicit<V, E, N, F, Ty: EdgeType> {
neighbors: F,
#[allow(clippy::type_complexity)]
ty: PhantomData<fn() -> (V, E, N, Ty)>,
}
impl<V, E, N, F> Implicit<V, E, N, F, Directed>
where
N: IntoIterator<Item = (V, E)>,
F: Fn(&V) -> N,
{
pub fn new(neighbors: F) -> Self {
Self {
neighbors,
ty: PhantomData,
}
}
pub fn undirected(self) -> Implicit<V, E, N, F, Undirected> {
Implicit {
neighbors: self.neighbors,
ty: PhantomData,
}
}
}
impl<V, E, N, F, Ty: EdgeType> GraphBase for Implicit<V, E, N, F, Ty>
where
N: IntoIterator<Item = (V, E)>,
F: Fn(&V) -> N,
ImplicitId<V>: IdType,
ImplicitId<E>: IdType,
{
type VertexId = ImplicitId<V>;
type EdgeId = ImplicitId<E>;
type EdgeType = Ty;
}
impl<V, E, N, F, Ty: EdgeType> Neighbors for Implicit<V, E, N, F, Ty>
where
N: IntoIterator<Item = (V, E)>,
F: Fn(&V) -> N,
ImplicitId<V>: IdType,
ImplicitId<E>: IdType,
{
type NeighborRef<'a>
= NeighborRef<ImplicitId<V>, ImplicitId<E>>
where
Self: 'a;
type NeighborsIter<'a>
= NeighborsIter<V, E, N::IntoIter>
where
Self: 'a;
fn neighbors_undirected(&self, from: &Self::VertexId) -> Self::NeighborsIter<'_> {
let from = from.0.as_ref().expect("non-sentinel id");
let neighbors = (self.neighbors)(from).into_iter();
NeighborsIter {
neighbors,
ty: PhantomData,
}
}
fn neighbors_directed(&self, from: &Self::VertexId, dir: Direction) -> Self::NeighborsIter<'_> {
assert_eq!(
dir,
Direction::Outgoing,
"incoming direction is not supported in implicit graph"
);
self.neighbors_undirected(from)
}
}
impl<V, E, N, F, Ty: EdgeType> GraphWeak<V, E> for Implicit<V, E, N, F, Ty>
where
N: IntoIterator<Item = (V, E)>,
F: Fn(&V) -> N,
ImplicitId<V>: IdType,
ImplicitId<E>: IdType,
{
fn vertex_weak<'a>(&'a self, id: &'a Self::VertexId) -> Option<OwnableRef<'a, V>> {
id.0.as_ref().map(OwnableRef::Borrowed)
}
fn edge_weak<'a>(&'a self, id: &'a Self::EdgeId) -> Option<OwnableRef<'a, E>> {
id.0.as_ref().map(OwnableRef::Borrowed)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ImplicitId<T>(Option<T>);
impl<T> From<T> for ImplicitId<T> {
fn from(value: T) -> Self {
Self(Some(value))
}
}
impl<T> AsRef<T> for ImplicitId<T> {
fn as_ref(&self) -> &T {
self.0.as_ref().expect("non-sentinel id")
}
}
impl<T> ImplicitId<T> {
pub fn into_inner(self) -> T {
self.0.expect("non-sentinel id")
}
}
impl<T> IdType for ImplicitId<T>
where
T: Debug + Clone + PartialEq + Eq + PartialOrd + Ord + Hash,
{
fn sentinel() -> Self {
Self(None)
}
fn is_integer() -> bool {
false
}
fn as_bits(&self) -> u64 {
panic!("unsupported");
}
fn from_bits(_: u64) -> Self {
panic!("unsupported");
}
}
pub struct NeighborsIter<V, E, N> {
neighbors: N,
ty: PhantomData<(V, E, N)>,
}
impl<V, E, N> Iterator for NeighborsIter<V, E, N>
where
N: Iterator<Item = (V, E)>,
ImplicitId<V>: IdType,
ImplicitId<E>: IdType,
{
type Item = NeighborRef<ImplicitId<V>, ImplicitId<E>>;
fn next(&mut self) -> Option<Self::Item> {
let (vertex, edge) = self.neighbors.next()?;
Some(NeighborRef {
id: ImplicitId(Some(vertex)),
edge: ImplicitId(Some(edge)),
pred: ImplicitId::sentinel(),
dir: Direction::Outgoing,
})
}
}