1#![no_std]
12
13use core::fmt;
14
15use oxgraph_csr::{CsrEdgeId, CsrGraph, CsrNodeId, CsrSnapshotError, CsrSnapshotIndex};
16use oxgraph_graph::{ElementPredecessors, OutgoingNeighborsGraph, TopologyCounts};
17use oxgraph_snapshot::Snapshot;
18use oxgraph_topology::TopologyBase;
19
20pub const SNAPSHOT_KIND_PG_INBOUND_OFFSETS_U32: u32 = 0x0201;
22
23pub const SNAPSHOT_KIND_PG_INBOUND_TARGETS_U32: u32 = 0x0202;
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct CscNodeId(pub u32);
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32pub enum CscSnapshotError {
33 Layout(CsrSnapshotError<u32, u32>),
35}
36
37impl fmt::Display for CscSnapshotError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 Self::Layout(error) => write!(f, "inbound layout error: {error}"),
41 }
42 }
43}
44
45impl core::error::Error for CscSnapshotError {}
46
47impl From<CsrSnapshotError<u32, u32>> for CscSnapshotError {
48 fn from(error: CsrSnapshotError<u32, u32>) -> Self {
49 Self::Layout(error)
50 }
51}
52
53pub type CscInnerGraph<'view> = CsrGraph<
59 'view,
60 u32,
61 u32,
62 <u32 as CsrSnapshotIndex>::LittleEndianWord,
63 <u32 as CsrSnapshotIndex>::LittleEndianWord,
64>;
65
66#[derive(Clone, Copy, Debug)]
72pub struct CscSnapshotGraph<'view>(CscInnerGraph<'view>);
73
74impl<'view> CscSnapshotGraph<'view> {
75 pub fn from_snapshot(snapshot: &Snapshot<'view>) -> Result<Self, CscSnapshotError> {
85 Self::from_snapshot_with_kinds(
86 snapshot,
87 SNAPSHOT_KIND_PG_INBOUND_OFFSETS_U32,
88 SNAPSHOT_KIND_PG_INBOUND_TARGETS_U32,
89 )
90 }
91
92 pub fn from_snapshot_with_kinds(
102 snapshot: &Snapshot<'view>,
103 offsets_kind: u32,
104 targets_kind: u32,
105 ) -> Result<Self, CscSnapshotError> {
106 let offsets_section = snapshot
107 .section(offsets_kind)
108 .ok_or(CsrSnapshotError::MissingOffsets)?;
109 let targets_section = snapshot
110 .section(targets_kind)
111 .ok_or(CsrSnapshotError::MissingTargets)?;
112
113 let offsets: &'view [<u32 as CsrSnapshotIndex>::LittleEndianWord] = offsets_section
114 .try_as_slice()
115 .map_err(CsrSnapshotError::OffsetsView)?;
116 let targets: &'view [<u32 as CsrSnapshotIndex>::LittleEndianWord] = targets_section
117 .try_as_slice()
118 .map_err(CsrSnapshotError::TargetsView)?;
119
120 if offsets.is_empty() {
121 return Err(CsrSnapshotError::OffsetsEmpty.into());
122 }
123
124 let node_count_usize = offsets.len() - 1;
125 let node_count =
126 u32::try_from(node_count_usize).map_err(|_| CsrSnapshotError::NodeCountOverflow {
127 offsets_len: offsets.len(),
128 })?;
129
130 let inner = CscInnerGraph::validate(node_count, offsets, targets)
131 .map_err(|error| CscSnapshotError::Layout(CsrSnapshotError::Csr(error)))?;
132 Ok(Self(inner))
133 }
134
135 #[must_use]
137 pub const fn inner(&self) -> &CscInnerGraph<'view> {
138 &self.0
139 }
140
141 #[must_use]
147 pub fn node_count(&self) -> usize {
148 self.0.element_count()
149 }
150
151 #[must_use]
157 pub fn relation_count(&self) -> usize {
158 self.0.relation_count()
159 }
160
161 #[must_use]
167 pub fn predecessors(&self, target: u32) -> impl ExactSizeIterator<Item = u32> + '_ {
168 self.0.outgoing_neighbors(CsrNodeId(target)).map(|id| id.0)
169 }
170
171 pub fn for_each_predecessor(&self, target: u32, mut visit: impl FnMut(u32) -> bool) -> bool {
179 self.0
180 .for_each_out_target(CsrNodeId(target), |id| visit(id.0))
181 }
182}
183
184pub struct CscPredecessors<'view> {
186 inner: <CscInnerGraph<'view> as OutgoingNeighborsGraph>::OutNeighbors<'view>,
188}
189
190impl Iterator for CscPredecessors<'_> {
191 type Item = CscNodeId;
192
193 fn next(&mut self) -> Option<Self::Item> {
194 self.inner.next().map(|id| CscNodeId(id.0))
195 }
196
197 fn size_hint(&self) -> (usize, Option<usize>) {
198 self.inner.size_hint()
199 }
200}
201
202impl ExactSizeIterator for CscPredecessors<'_> {}
203
204impl TopologyBase for CscSnapshotGraph<'_> {
205 type ElementId = CscNodeId;
206 type RelationId = CsrEdgeId<u32>;
207}
208
209impl TopologyCounts for CscSnapshotGraph<'_> {
210 fn element_count(&self) -> usize {
211 self.0.element_count()
212 }
213
214 fn relation_count(&self) -> usize {
215 self.0.relation_count()
216 }
217}
218
219impl ElementPredecessors for CscSnapshotGraph<'_> {
220 type Predecessors<'view>
221 = CscPredecessors<'view>
222 where
223 Self: 'view;
224
225 fn element_predecessors(&self, element: CscNodeId) -> Self::Predecessors<'_> {
226 CscPredecessors {
227 inner: self.0.outgoing_neighbors(CsrNodeId(element.0)),
228 }
229 }
230}
231
232#[cfg(kani)]
233mod proofs;