Skip to main content

oxgraph_hyper_bcsr/
word.rs

1//! Borrowed-section word abstraction for bipartite-CSR payloads.
2
3use core::marker::PhantomData;
4
5use oxgraph_layout_util::SnapshotWidth;
6pub use oxgraph_layout_util::{LayoutIndex, LayoutSnapshotWord, LayoutWord};
7
8use crate::snapshot::{
9    SNAPSHOT_KIND_BCSR_HEAD_OFFSETS_BASE, SNAPSHOT_KIND_BCSR_HEAD_PARTICIPANTS_BASE,
10    SNAPSHOT_KIND_BCSR_TAIL_OFFSETS_BASE, SNAPSHOT_KIND_BCSR_TAIL_PARTICIPANTS_BASE,
11    SNAPSHOT_KIND_BCSR_VERTEX_INCOMING_HYPEREDGES_BASE,
12    SNAPSHOT_KIND_BCSR_VERTEX_INCOMING_OFFSETS_BASE,
13    SNAPSHOT_KIND_BCSR_VERTEX_OUTGOING_HYPEREDGES_BASE,
14    SNAPSHOT_KIND_BCSR_VERTEX_OUTGOING_OFFSETS_BASE,
15};
16
17/// Section version written and expected for all BCSR layout payloads.
18pub const SNAPSHOT_BCSR_SECTION_VERSION: u32 = 1;
19
20/// Bundles the three index widths and three storage words of one BCSR view.
21///
22/// [`BcsrHypergraph`](crate::BcsrHypergraph) is generic over exactly one
23/// `BcsrWords` family instead of six coupled type parameters. The three
24/// `*Index` types are the logical dense widths; the three `*Word` types are
25/// the in-memory representations stored in the borrowed sections, each
26/// constrained to decode to its matching index. Two families exist:
27/// [`NativeWords`] for host-order build-path views (including `usize`) and
28/// [`LeWords`] for little-endian snapshot-backed views.
29///
30/// # Performance
31///
32/// `perf: unspecified`; this is a type-level trait with no methods.
33pub trait BcsrWords {
34    /// Logical vertex index width.
35    type VertexIndex: LayoutIndex;
36    /// Logical hyperedge (relation) index width.
37    type RelationIndex: LayoutIndex;
38    /// Logical incidence index width.
39    type IncidenceIndex: LayoutIndex;
40    /// Storage word of the four offset sections; decodes to
41    /// [`Self::IncidenceIndex`].
42    type OffsetWord: LayoutWord<Index = Self::IncidenceIndex>;
43    /// Storage word of the hyperedge-major participant sections; decodes to
44    /// [`Self::VertexIndex`].
45    type VertexWord: LayoutWord<Index = Self::VertexIndex>;
46    /// Storage word of the vertex-major hyperedge sections; decodes to
47    /// [`Self::RelationIndex`].
48    type RelationWord: LayoutWord<Index = Self::RelationIndex>;
49}
50
51/// Type-level brand carried by the word-family markers; the `fn() -> …`
52/// wrapper keeps auto traits and variance independent of the index widths.
53type WordFamilyBrand<VertexIndex, RelationIndex, IncidenceIndex> =
54    PhantomData<fn() -> (VertexIndex, RelationIndex, IncidenceIndex)>;
55
56/// Native host word family: sections store each index type directly.
57///
58/// Selects identity storage words (`OffsetWord = IncidenceIndex`, and so on),
59/// which is the build-path representation. `usize` is permitted because
60/// nothing is persisted. This is a type-level carrier — it is never
61/// constructed.
62///
63/// # Performance
64///
65/// `perf: unspecified`; this is a type-level marker.
66pub struct NativeWords<VertexIndex, RelationIndex, IncidenceIndex> {
67    /// Type-level brand selecting the three index widths.
68    _family: WordFamilyBrand<VertexIndex, RelationIndex, IncidenceIndex>,
69}
70
71impl<VertexIndex, RelationIndex, IncidenceIndex> BcsrWords
72    for NativeWords<VertexIndex, RelationIndex, IncidenceIndex>
73where
74    VertexIndex: LayoutIndex + LayoutWord<Index = VertexIndex>,
75    RelationIndex: LayoutIndex + LayoutWord<Index = RelationIndex>,
76    IncidenceIndex: LayoutIndex + LayoutWord<Index = IncidenceIndex>,
77{
78    type IncidenceIndex = IncidenceIndex;
79    type OffsetWord = IncidenceIndex;
80    type RelationIndex = RelationIndex;
81    type RelationWord = RelationIndex;
82    type VertexIndex = VertexIndex;
83    type VertexWord = VertexIndex;
84}
85
86/// Little-endian snapshot word family: sections store fixed-width
87/// little-endian words.
88///
89/// Selects each width's [`SnapshotWidth::LittleEndianWord`] as the storage
90/// word, which is the view-path representation over persisted snapshot bytes.
91/// `usize` is excluded because snapshot bytes are fixed-width. This is a
92/// type-level carrier — it is never constructed.
93///
94/// # Performance
95///
96/// `perf: unspecified`; this is a type-level marker.
97pub struct LeWords<VertexIndex, RelationIndex, IncidenceIndex> {
98    /// Type-level brand selecting the three index widths.
99    _family: WordFamilyBrand<VertexIndex, RelationIndex, IncidenceIndex>,
100}
101
102impl<VertexIndex, RelationIndex, IncidenceIndex> BcsrWords
103    for LeWords<VertexIndex, RelationIndex, IncidenceIndex>
104where
105    VertexIndex: SnapshotWidth,
106    RelationIndex: SnapshotWidth,
107    IncidenceIndex: SnapshotWidth,
108{
109    type IncidenceIndex = IncidenceIndex;
110    type OffsetWord = IncidenceIndex::LittleEndianWord;
111    type RelationIndex = RelationIndex;
112    type RelationWord = RelationIndex::LittleEndianWord;
113    type VertexIndex = VertexIndex;
114    type VertexWord = VertexIndex::LittleEndianWord;
115}
116
117/// Width-specific section-kind tags for persisted BCSR layout payloads.
118///
119/// This is the thin BCSR-specific layer over the shared
120/// [`SnapshotWidth`](oxgraph_layout_util::SnapshotWidth) contract: it derives
121/// the eight per-width section kinds from the crate's 4-aligned base constants
122/// and [`SnapshotWidth::WIDTH_CODE`], and adds the section version. The
123/// little-endian storage word and the native/LE conversions come from
124/// `SnapshotWidth`, so `Index::LittleEndianWord` and `Index::to_le_word` keep
125/// resolving through that trait.
126///
127/// `usize` deliberately does not implement this trait: snapshot bytes are
128/// fixed-width.
129///
130/// # Performance
131///
132/// Reading the kind/version constants is `O(1)`.
133pub trait BcsrSnapshotIndex: SnapshotWidth {
134    /// Head offsets section kind for this width.
135    const HEAD_OFFSETS_KIND: u32 = SNAPSHOT_KIND_BCSR_HEAD_OFFSETS_BASE | Self::WIDTH_CODE;
136    /// Head participants section kind for this width.
137    const HEAD_PARTICIPANTS_KIND: u32 =
138        SNAPSHOT_KIND_BCSR_HEAD_PARTICIPANTS_BASE | Self::WIDTH_CODE;
139    /// Tail offsets section kind for this width.
140    const TAIL_OFFSETS_KIND: u32 = SNAPSHOT_KIND_BCSR_TAIL_OFFSETS_BASE | Self::WIDTH_CODE;
141    /// Tail participants section kind for this width.
142    const TAIL_PARTICIPANTS_KIND: u32 =
143        SNAPSHOT_KIND_BCSR_TAIL_PARTICIPANTS_BASE | Self::WIDTH_CODE;
144    /// Vertex outgoing offsets section kind for this width.
145    const VERTEX_OUTGOING_OFFSETS_KIND: u32 =
146        SNAPSHOT_KIND_BCSR_VERTEX_OUTGOING_OFFSETS_BASE | Self::WIDTH_CODE;
147    /// Vertex outgoing hyperedges section kind for this width.
148    const VERTEX_OUTGOING_HYPEREDGES_KIND: u32 =
149        SNAPSHOT_KIND_BCSR_VERTEX_OUTGOING_HYPEREDGES_BASE | Self::WIDTH_CODE;
150    /// Vertex incoming offsets section kind for this width.
151    const VERTEX_INCOMING_OFFSETS_KIND: u32 =
152        SNAPSHOT_KIND_BCSR_VERTEX_INCOMING_OFFSETS_BASE | Self::WIDTH_CODE;
153    /// Vertex incoming hyperedges section kind for this width.
154    const VERTEX_INCOMING_HYPEREDGES_KIND: u32 =
155        SNAPSHOT_KIND_BCSR_VERTEX_INCOMING_HYPEREDGES_BASE | Self::WIDTH_CODE;
156    /// Section version written for this width's BCSR payloads.
157    const SECTION_VERSION: u32 = SNAPSHOT_BCSR_SECTION_VERSION;
158}
159
160impl BcsrSnapshotIndex for u16 {}
161impl BcsrSnapshotIndex for u32 {}
162impl BcsrSnapshotIndex for u64 {}