file_system/fundamentals/identifiers/
inode.rs

1//! Inode identifier type for file system objects.
2//!
3//! This module provides the [`Inode_type`] which represents inode numbers
4//! used to uniquely identify file system objects within a specific file system.
5
6use core::ops::{Add, AddAssign};
7
8/// Type-safe wrapper for inode numbers.
9///
10/// An inode (index node) is a unique identifier for file system objects such as
11/// files, directories, symbolic links, and other entities within a file system.
12/// Each file system object has a unique inode number that persists for the
13/// lifetime of the object.
14///
15/// # Examples
16///
17/// ```rust
18/// use file_system::Inode_type;
19///
20/// // Create an inode number
21/// let inode = Inode_type::new(42);
22/// assert_eq!(inode.As_u64(), 42);
23///
24/// // Inode numbers can be compared
25/// let another_inode = Inode_type::new(43);
26/// assert!(inode < another_inode);
27///
28/// // Arithmetic operations are supported
29/// let incremented = inode + 10;
30/// assert_eq!(incremented.As_u64(), 52);
31/// ```
32///
33/// # Note
34///
35/// Inode 0 is typically reserved in most file systems. The minimum valid
36/// inode number is provided as [`Inode::MINIMUM`].
37#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
38#[repr(transparent)]
39pub struct Inode(u64);
40
41impl Inode {
42    /// The minimum valid inode number.
43    ///
44    /// Most file systems reserve inode 0 for special purposes, so valid
45    /// inode numbers typically start from 1.
46    pub const MINIMUM: Self = Inode(1);
47
48    /// Create a new inode identifier from a u64 value.
49    ///
50    /// # Arguments
51    ///
52    /// * `Item` - The inode number
53    ///
54    /// # Examples
55    ///
56    /// ```rust
57    /// use file_system::Inode_type;
58    ///
59    /// let inode = Inode_type::new(123);
60    /// assert_eq!(inode.As_u64(), 123);
61    /// ```
62    pub const fn new(item: u64) -> Self {
63        Inode(item)
64    }
65
66    /// Get the inode number as a u64.
67    ///
68    /// # Returns
69    ///
70    /// The underlying inode number as a 64-bit unsigned integer.
71    ///
72    /// # Examples
73    ///
74    /// ```rust
75    /// use file_system::Inode_type;
76    ///
77    /// let inode = Inode_type::new(456);
78    /// assert_eq!(inode.As_u64(), 456);
79    /// ```
80    pub const fn as_u64(self) -> u64 {
81        self.0
82    }
83}
84
85impl From<u64> for Inode {
86    fn from(item: u64) -> Self {
87        Inode(item)
88    }
89}
90
91impl From<Inode> for u64 {
92    fn from(item: Inode) -> Self {
93        item.0
94    }
95}
96
97impl Add<u64> for Inode {
98    type Output = Self;
99
100    fn add(self, other: u64) -> Self {
101        Inode(self.0 + other)
102    }
103}
104
105impl AddAssign<u64> for Inode {
106    fn add_assign(&mut self, other: u64) {
107        self.0 += other;
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use alloc::format;
115
116    #[test]
117    fn test_inode_creation() {
118        let inode = Inode::new(42);
119        assert_eq!(inode.as_u64(), 42);
120    }
121
122    #[test]
123    fn test_inode_minimum() {
124        assert_eq!(Inode::MINIMUM.as_u64(), 1);
125    }
126
127    #[test]
128    fn test_inode_const_operations() {
129        // Test that New and As_u64 are const functions
130        const INODE: Inode = Inode::new(123);
131        const VALUE: u64 = INODE.as_u64();
132
133        assert_eq!(VALUE, 123);
134        assert_eq!(INODE.as_u64(), 123);
135    }
136
137    #[test]
138    fn test_inode_conversions() {
139        // From u64
140        let inode_from_u64: Inode = 456u64.into();
141        assert_eq!(inode_from_u64.as_u64(), 456);
142
143        // To u64
144        let as_u64: u64 = inode_from_u64.into();
145        assert_eq!(as_u64, 456);
146    }
147
148    #[test]
149    fn test_inode_comparison() {
150        let small = Inode::new(10);
151        let large = Inode::new(20);
152
153        assert!(small < large);
154        assert!(large > small);
155        assert!(small <= large);
156        assert!(large >= small);
157        assert!(small <= small);
158        assert!(large >= large);
159        assert_eq!(small, small);
160        assert_ne!(small, large);
161    }
162
163    #[test]
164    fn test_inode_ordering() {
165        let mut inodes = [
166            Inode::new(100),
167            Inode::new(50),
168            Inode::new(200),
169            Inode::new(25),
170        ];
171
172        inodes.sort();
173
174        assert_eq!(inodes[0], Inode::new(25));
175        assert_eq!(inodes[1], Inode::new(50));
176        assert_eq!(inodes[2], Inode::new(100));
177        assert_eq!(inodes[3], Inode::new(200));
178    }
179
180    #[test]
181    fn test_inode_addition() {
182        let inode = Inode::new(100);
183        let result = inode + 50;
184        assert_eq!(result.as_u64(), 150);
185    }
186
187    #[test]
188    fn test_inode_add_assign() {
189        let mut inode = Inode::new(100);
190        inode += 25;
191        assert_eq!(inode.as_u64(), 125);
192    }
193
194    #[test]
195    fn test_inode_debug() {
196        let inode = Inode::new(789);
197        let debug_str = format!("{inode:?}");
198        assert!(debug_str.contains("Inode_type"));
199        assert!(debug_str.contains("789"));
200    }
201
202    #[test]
203    fn test_inode_clone_copy() {
204        let original = Inode::new(999);
205        let cloned = original;
206        let copied = original;
207
208        assert_eq!(original, cloned);
209        assert_eq!(original, copied);
210        assert_eq!(cloned, copied);
211
212        // Test that we can still use original after copying
213        assert_eq!(original.as_u64(), 999);
214    }
215
216    #[test]
217    fn test_inode_zero() {
218        let zero = Inode::new(0);
219        assert_eq!(zero.as_u64(), 0);
220        assert!(zero < Inode::MINIMUM);
221    }
222
223    #[test]
224    fn test_inode_max_value() {
225        let max_inode = Inode::new(u64::MAX);
226        assert_eq!(max_inode.as_u64(), u64::MAX);
227    }
228
229    #[test]
230    fn test_inode_arithmetic_edge_cases() {
231        // Test addition near max value
232        let near_max = Inode::new(u64::MAX - 10);
233        let result = near_max + 5;
234        assert_eq!(result.as_u64(), u64::MAX - 5);
235    }
236
237    #[test]
238    fn test_inode_type_safety() {
239        // Verify that Inode_type is a zero-cost abstraction
240        use core::mem::{align_of, size_of};
241
242        assert_eq!(size_of::<Inode>(), size_of::<u64>());
243        assert_eq!(align_of::<Inode>(), align_of::<u64>());
244    }
245
246    #[test]
247    fn test_inode_sequence_operations() {
248        let start = Inode::new(1000);
249        let mut current = start;
250
251        // Test sequential addition
252        for i in 1..=10 {
253            current += 1;
254            assert_eq!(current.as_u64(), 1000 + i);
255        }
256    }
257
258    #[test]
259    fn test_inode_round_trip_conversion() {
260        let original_value = 12345u64;
261        let inode = Inode::new(original_value);
262        let converted: u64 = inode.into();
263        let back_to_inode: Inode = converted.into();
264
265        assert_eq!(original_value, converted);
266        assert_eq!(inode, back_to_inode);
267    }
268
269    #[test]
270    fn test_inode_minimum_comparison() {
271        let minimum = Inode::MINIMUM;
272        let zero = Inode::new(0);
273        let two = Inode::new(2);
274
275        assert!(zero < minimum);
276        assert!(minimum < two);
277        assert_eq!(minimum.as_u64(), 1);
278    }
279
280    #[test]
281    fn test_inode_large_additions() {
282        let inode = Inode::new(1000);
283        let large_add = 1_000_000u64;
284        let result = inode + large_add;
285
286        assert_eq!(result.as_u64(), 1_001_000);
287    }
288
289    #[test]
290    fn test_inode_multiple_operations() {
291        let mut inode = Inode::new(100);
292
293        inode += 10;
294        inode += 20;
295        inode += 30;
296
297        assert_eq!(inode.as_u64(), 160);
298
299        let added = inode + 40;
300        assert_eq!(added.as_u64(), 200);
301        assert_eq!(inode.as_u64(), 160); // Original should be unchanged
302    }
303}