#![no_std]
use core::fmt;
use oxgraph_csr::{CsrEdgeId, CsrGraph, CsrNodeId, CsrSnapshotError, CsrSnapshotIndex};
use oxgraph_graph::{ElementPredecessors, OutgoingNeighborsGraph, TopologyCounts};
use oxgraph_layout_util::{NodeAxis, SnapshotWidth};
use oxgraph_snapshot::Snapshot;
use oxgraph_topology::TopologyBase;
pub type CscNodeId<N = u32> = oxgraph_layout_util::LocalId<NodeAxis, N>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CscSnapshotError<N = u32, E = u32> {
Layout(CsrSnapshotError<N, E>),
}
impl<N: fmt::Display, E: fmt::Display> fmt::Display for CscSnapshotError<N, E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Layout(error) => write!(f, "inbound layout error: {error}"),
}
}
}
impl<N, E> core::error::Error for CscSnapshotError<N, E>
where
N: fmt::Debug + fmt::Display,
E: fmt::Debug + fmt::Display,
{
}
impl<N, E> From<CsrSnapshotError<N, E>> for CscSnapshotError<N, E> {
fn from(error: CsrSnapshotError<N, E>) -> Self {
Self::Layout(error)
}
}
pub type CscInnerGraph<'view, N = u32, E = u32> = CsrGraph<
'view,
N,
E,
<E as SnapshotWidth>::LittleEndianWord,
<N as SnapshotWidth>::LittleEndianWord,
>;
#[derive(Clone, Copy)]
pub struct CscSnapshotGraph<'view, N = u32, E = u32>(CscInnerGraph<'view, N, E>)
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex;
impl<N, E> fmt::Debug for CscSnapshotGraph<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("CscSnapshotGraph")
.field("node_count", &self.node_count())
.field("relation_count", &self.relation_count())
.finish()
}
}
impl<'view, N, E> CscSnapshotGraph<'view, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
pub fn from_snapshot_with_kinds(
snapshot: &Snapshot<'view>,
offsets_kind: u32,
targets_kind: u32,
version: u32,
) -> Result<Self, CscSnapshotError<N, E>> {
let inner = CscInnerGraph::<'view, N, E>::from_snapshot_with_kinds(
snapshot,
offsets_kind,
targets_kind,
version,
)?;
Ok(Self(inner))
}
#[must_use]
pub const fn inner(&self) -> &CscInnerGraph<'view, N, E> {
&self.0
}
#[must_use]
pub fn node_count(&self) -> usize {
self.0.element_count()
}
#[must_use]
pub fn relation_count(&self) -> usize {
self.0.relation_count()
}
pub fn predecessors(
&self,
target: CscNodeId<N>,
) -> impl ExactSizeIterator<Item = CscNodeId<N>> + '_ {
self.0
.outgoing_neighbors(CsrNodeId::new(target.get()))
.map(|id| CscNodeId::new(id.get()))
}
pub fn for_each_predecessor(
&self,
target: CscNodeId<N>,
mut visit: impl FnMut(CscNodeId<N>) -> bool,
) -> bool {
self.0
.for_each_out_target(CsrNodeId::new(target.get()), |id| {
visit(CscNodeId::new(id.get()))
})
}
}
pub struct CscPredecessors<'view, N = u32, E = u32>
where
N: CsrSnapshotIndex + 'view,
E: CsrSnapshotIndex + 'view,
{
inner: <CscInnerGraph<'view, N, E> as OutgoingNeighborsGraph>::OutNeighbors<'view>,
}
impl<N, E> Iterator for CscPredecessors<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
type Item = CscNodeId<N>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|id| CscNodeId::new(id.get()))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<N, E> ExactSizeIterator for CscPredecessors<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
}
impl<N, E> TopologyBase for CscSnapshotGraph<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
type ElementId = CscNodeId<N>;
type RelationId = CsrEdgeId<E>;
}
impl<N, E> TopologyCounts for CscSnapshotGraph<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
fn element_count(&self) -> usize {
self.0.element_count()
}
fn relation_count(&self) -> usize {
self.0.relation_count()
}
}
impl<N, E> ElementPredecessors for CscSnapshotGraph<'_, N, E>
where
N: CsrSnapshotIndex,
E: CsrSnapshotIndex,
{
type Predecessors<'view>
= CscPredecessors<'view, N, E>
where
Self: 'view;
fn element_predecessors(&self, element: CscNodeId<N>) -> Self::Predecessors<'_> {
CscPredecessors {
inner: self.0.outgoing_neighbors(CsrNodeId::new(element.get())),
}
}
}
#[cfg(kani)]
mod proofs;