Skip to main content

quiver_core/
ids.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2//! Strongly-typed identifiers used throughout the storage engine.
3//!
4//! Wrapping the raw integers in newtypes keeps an LSN from being mistaken for a
5//! collection id (or a row, or a segment) at a call site — a cheap, compile-time
6//! guard for a component where mixing them up corrupts data.
7
8use serde::{Deserialize, Serialize};
9
10/// A log sequence number: a monotonically increasing id assigned to every WAL
11/// record. LSNs totally order all mutations and anchor checkpointing and
12/// recovery.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
14pub struct Lsn(pub u64);
15
16impl Lsn {
17    /// The zero LSN — precedes every real record and is the initial checkpoint
18    /// floor of a fresh store.
19    pub const ZERO: Lsn = Lsn(0);
20
21    /// The next LSN in sequence.
22    #[must_use]
23    pub const fn next(self) -> Lsn {
24        Lsn(self.0 + 1)
25    }
26
27    /// The underlying integer value.
28    #[must_use]
29    pub const fn value(self) -> u64 {
30        self.0
31    }
32}
33
34impl std::fmt::Display for Lsn {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        write!(f, "{}", self.0)
37    }
38}
39
40/// A collection identifier, assigned monotonically by the catalog and stable for
41/// the life of the collection.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
43pub struct CollectionId(pub u64);
44
45impl CollectionId {
46    /// The underlying integer value.
47    #[must_use]
48    pub const fn value(self) -> u64 {
49        self.0
50    }
51}
52
53impl std::fmt::Display for CollectionId {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(f, "{}", self.0)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn lsn_orders_and_increments() {
65        assert_eq!(Lsn::ZERO.value(), 0);
66        assert_eq!(Lsn::ZERO.next(), Lsn(1));
67        assert!(Lsn(1) < Lsn(2));
68        assert_eq!(Lsn(41).next().value(), 42);
69    }
70
71    #[test]
72    fn ids_display() {
73        assert_eq!(Lsn(7).to_string(), "7");
74        assert_eq!(CollectionId(3).to_string(), "3");
75        assert_eq!(CollectionId(3).value(), 3);
76    }
77}