Skip to main content

noxu_tree/
node.rs

1//! Base node types and identifiers for the B-tree.
2//!
3//!
4//! Node is an abstract base class. In Rust, we use an enum for the
5//! closed set of node types, plus utilities for node ID generation.
6
7/// Sentinel value representing a null/uninitialized node ID.
8pub const NULL_NODE_ID: i64 = -1;
9
10/// Identifies the kind of a tree node.
11///
12/// This enum represents the closed set of node types in the B-tree.
13/// Each type has specific semantics and behavior.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum NodeType {
16    /// Upper Internal Node - non-leaf node in the B-tree.
17    IN,
18
19    /// Bottom Internal Node - leaf-level node containing references to LNs.
20    BIN,
21
22    /// BIN Delta - a partial BIN containing only changed slots.
23    BINDelta,
24
25    /// Leaf Node - contains actual data records.
26    LN,
27
28    /// MapLN - special LN that references a database metadata tree.
29    MapLN,
30
31    /// NameLN - special LN that maps database names to database IDs.
32    NameLN,
33
34    /// FileSummaryLN - special LN that tracks log file utilization.
35    FileSummaryLN,
36}
37
38impl NodeType {
39    /// Returns true if this is any type of LN (leaf node).
40    #[inline]
41    pub fn is_ln(self) -> bool {
42        matches!(
43            self,
44            NodeType::LN
45                | NodeType::MapLN
46                | NodeType::NameLN
47                | NodeType::FileSummaryLN
48        )
49    }
50
51    /// Returns true if this is any type of IN (internal node).
52    ///
53    /// This includes IN, BIN, and BINDelta.
54    #[inline]
55    pub fn is_in(self) -> bool {
56        matches!(self, NodeType::IN | NodeType::BIN | NodeType::BINDelta)
57    }
58
59    /// Returns true if this is a BIN or BINDelta.
60    #[inline]
61    pub fn is_bin(self) -> bool {
62        matches!(self, NodeType::BIN | NodeType::BINDelta)
63    }
64
65    /// Returns true if this is an upper IN (non-leaf internal node).
66    #[inline]
67    pub fn is_upper_in(self) -> bool {
68        matches!(self, NodeType::IN)
69    }
70
71    /// Returns true if this is a BIN delta.
72    #[inline]
73    pub fn is_bin_delta(self) -> bool {
74        matches!(self, NodeType::BINDelta)
75    }
76
77    /// Returns the tree level for this node type.
78    ///
79    /// LNs are level 0. For internal nodes, the level is determined at runtime
80    /// and stored in the IN structure, so this returns -1 as a sentinel.
81    #[inline]
82    pub fn level(self) -> i32 {
83        if self.is_ln() {
84            0
85        } else {
86            -1 // Level is stored in the IN/BIN itself
87        }
88    }
89
90    /// Returns a string name for this node type.
91    pub fn name(self) -> &'static str {
92        match self {
93            NodeType::IN => "IN",
94            NodeType::BIN => "BIN",
95            NodeType::BINDelta => "BINDelta",
96            NodeType::LN => "LN",
97            NodeType::MapLN => "MapLN",
98            NodeType::NameLN => "NameLN",
99            NodeType::FileSummaryLN => "FileSummaryLN",
100        }
101    }
102}
103
104impl std::fmt::Display for NodeType {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(f, "{}", self.name())
107    }
108}
109
110// L-30: the former private i64 node-id generator (`NEXT_NODE_ID` /
111// `generate_node_id` / `reset_node_id_counter` / `peek_next_node_id`) lived
112// here but was dead production code (never exported from `lib.rs`, used only
113// by this module's own tests).  It was a SECOND independent node-id source
114// that reset to 1 on every restart.  Node-ids now come from the single
115// tree-wide counter `crate::tree::generate_node_id`, which the env seeds
116// post-recovery (`NodeSequence.getNextLocalNodeId`).
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_node_type_is_ln() {
123        assert!(NodeType::LN.is_ln());
124        assert!(NodeType::MapLN.is_ln());
125        assert!(NodeType::NameLN.is_ln());
126        assert!(NodeType::FileSummaryLN.is_ln());
127
128        assert!(!NodeType::IN.is_ln());
129        assert!(!NodeType::BIN.is_ln());
130        assert!(!NodeType::BINDelta.is_ln());
131    }
132
133    #[test]
134    fn test_node_type_is_in() {
135        assert!(NodeType::IN.is_in());
136        assert!(NodeType::BIN.is_in());
137        assert!(NodeType::BINDelta.is_in());
138
139        assert!(!NodeType::LN.is_in());
140        assert!(!NodeType::MapLN.is_in());
141    }
142
143    #[test]
144    fn test_node_type_is_bin() {
145        assert!(NodeType::BIN.is_bin());
146        assert!(NodeType::BINDelta.is_bin());
147
148        assert!(!NodeType::IN.is_bin());
149        assert!(!NodeType::LN.is_bin());
150    }
151
152    #[test]
153    fn test_node_type_is_upper_in() {
154        assert!(NodeType::IN.is_upper_in());
155
156        assert!(!NodeType::BIN.is_upper_in());
157        assert!(!NodeType::BINDelta.is_upper_in());
158        assert!(!NodeType::LN.is_upper_in());
159    }
160
161    #[test]
162    fn test_node_type_is_bin_delta() {
163        assert!(NodeType::BINDelta.is_bin_delta());
164
165        assert!(!NodeType::BIN.is_bin_delta());
166        assert!(!NodeType::IN.is_bin_delta());
167        assert!(!NodeType::LN.is_bin_delta());
168    }
169
170    #[test]
171    fn test_node_type_level() {
172        // All LN types are level 0
173        assert_eq!(NodeType::LN.level(), 0);
174        assert_eq!(NodeType::MapLN.level(), 0);
175        assert_eq!(NodeType::NameLN.level(), 0);
176        assert_eq!(NodeType::FileSummaryLN.level(), 0);
177
178        // Internal nodes return -1 (level stored elsewhere)
179        assert_eq!(NodeType::IN.level(), -1);
180        assert_eq!(NodeType::BIN.level(), -1);
181        assert_eq!(NodeType::BINDelta.level(), -1);
182    }
183
184    #[test]
185    fn test_node_type_name() {
186        assert_eq!(NodeType::IN.name(), "IN");
187        assert_eq!(NodeType::BIN.name(), "BIN");
188        assert_eq!(NodeType::BINDelta.name(), "BINDelta");
189        assert_eq!(NodeType::LN.name(), "LN");
190        assert_eq!(NodeType::MapLN.name(), "MapLN");
191        assert_eq!(NodeType::NameLN.name(), "NameLN");
192        assert_eq!(NodeType::FileSummaryLN.name(), "FileSummaryLN");
193    }
194
195    #[test]
196    fn test_node_type_display() {
197        assert_eq!(format!("{}", NodeType::BIN), "BIN");
198        assert_eq!(format!("{}", NodeType::LN), "LN");
199    }
200
201    #[test]
202    fn test_null_node_id_constant() {
203        assert_eq!(NULL_NODE_ID, -1);
204    }
205}