Skip to main content

kernel/
rxarray.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Rust XArray implementation.
4//!
5//! This module implements an extensible array (aka XArray) via the [`XArray`] type. See [`XArray4`]
6//! and [`XArray6`] for common configurations.
7//!
8//! The array can hold two types of entries at the same time where each index independently stores
9//! either an owned pointer (`T: ForeignOwnable`) or a bounded integer up to `usize::MAX >> 1`
10//! backed by [`Bounded`]. Users insert entries via the [`Entry`] type. References to entries in
11//! the tree are handled by the [`BorrowedEntry`] and [`BorrowedEntryMut`] types.
12//!
13//! # Differences from C XArray
14//!
15//! The C XArray uses RCU for lock-free reads and an internal spinlock for writes. This
16//! implementation does not provide internal locking. A mutable reference is required for writes, a
17//! shared reference for reads. Locking can be applied externally. RCU support is planned.
18//!
19//! This implementation allocates during store. `xa_reserve()` and `xas_nomem()` are not yet
20//! supported.
21//!
22//! C `xa_destroy()` frees only internal nodes; callers must free their own stored values. Dropping
23//! [`XArray`] also frees all stored entries.
24//!
25//! C `xa_mk_value()` issues `WARN_ON` if the value exceeds `LONG_MAX`; the left shift overflows,
26//! producing a wrong entry.
27//! Rust [`Entry::int()`] rejects out-of-range values at compile time via `Bounded`, and
28//! [`Entry::try_int()`] returns [`None`] at runtime.
29//!
30//! The C XArray grows in depth on demand to be efficient for small indices, creating a short tree
31//! whenever possible and adding levels as larger indices appear. This implementation always walks
32//! the full levels, whatever the largest stored index is. Variable height is planned.
33//!
34//! C XArray features like search marks, multi-index entries, advanced API, etc. are not yet
35//! implemented.
36//!
37//! This implementation aims for full feature parity with the C XArray; any gap not covered above is
38//! a defect in this list.
39//!
40//! # Data structure
41//!
42//! The XArray is a radix tree that maps `usize` indices to [`Entry`] values. Each node holds an
43//! array of `SIZE` slots (where `SIZE = 1 << SHIFT`), and the tree depth is
44//! `ceil(usize::BITS / SHIFT)`. Indices are decomposed so that each chunk indexes a slot in a
45//! node at the corresponding level.
46//!
47//! ```text
48//!                                 XArray
49//!                                    │
50//!                                    ▼
51//!                           ┌────────────────┐
52//!                           │   Root Node    │  Level = levels-1
53//!                           │ slots[0..SIZE] │
54//!                           └────────────────┘
55//!                            /       |       \
56//!               ┌───────────┘        │        └───────────┐
57//!               ▼                    ▼                    ▼
58//!      ┌────────────────┐       ┌────────┐       ┌────────────────┐
59//!      │      Node      │       │ Empty  │       │      Node      │
60//!      │ slots[0..SIZE] │       └────────┘       │ slots[0..SIZE] │
61//!      └────────────────┘                        └────────────────┘
62//!        /           \                                   |
63//!       ▼             ▼                                  ▼
64//!    ...            ...                          ┌────────────────┐
65//!                                                │   Leaf Node    │  Level = 0
66//!                                                │ slots[0..SIZE] │
67//!                                                └────────────────┘
68//!                                                 /       |       \
69//!                                                ▼        ▼        ▼
70//!                                             Entry    Empty    Entry
71//!                                             (Int)             (Ptr)
72//! ```
73//!
74//! Index decomposition for [`XArray6`] (SHIFT=6, 64 slots per node, 11 levels on 64-bit):
75//!
76//! ```text
77//!   ┌─────────────────────────────────────────────────────────────────┐
78//!   │ index                                                           │
79//!   ├─────────┬─────────┬───────────────┬─────────┬─────────┬─────────┤
80//!   │ level10 │ level 9 │      ...      │ level 2 │ level 1 │ level 0 │
81//!   │ [63:60] │ [59:54] │               │ [17:12] │ [11:6]  │  [5:0]  │
82//!   └─────────┴─────────┴───────────────┴─────────┴─────────┴─────────┘
83//! ```
84//!
85//! At each level, the slot offset is: `(index >> (level * SHIFT)) & (SIZE - 1)`.
86//!
87//! # C API
88//!
89//! This implementation does not have a C API yet. When one is added, its FFI layer must validate
90//! at runtime what the Rust API enforces at compile or construction time:
91//!
92//! - **Int values**: use [`Entry::try_int()`]; reject [`None`] as `-EINVAL`. C has no [`Bounded`],
93//!   so the FFI wrapper is the enforcement point.
94//! - **Pointers**: validate 4-byte alignment and non-null at runtime.
95//!   `const_assert!(T::FOREIGN_ALIGN >= 4)` only covers Rust callers.
96//! - **NULL pointers**: dispatch as erase (`xa_store(NULL) == xa_erase`) or reserve
97//!   (`XA_FLAGS_ALLOC`) before reaching [`XArray::store()`].
98//! - **Error entries**: reject `xa_is_err()` values; Rust would misclassify them as node pointers
99//!   (see `Slot` invariants).
100
101use crate::{
102    alloc::Flags,
103    fmt,
104    num::Bounded,
105    prelude::*,
106    types::ForeignOwnable, //
107};
108use core::{
109    marker::PhantomData,
110    mem, //
111};
112
113/// Type alias for [`XArray`] with a shift of 4 and 16 slots per node.
114pub type XArray4<T> = XArray<T, 4, 16>;
115
116/// Type alias for [`XArray`] with a shift of 6 and 64 slots per node.
117pub type XArray6<T> = XArray<T, 6, 64>;
118
119/// Type alias for [`Entry::Int`] values. Integers that fit in `usize::BITS - 1` bits
120/// (`0..=usize::MAX >> 1`).
121pub type Value = Bounded<usize, { usize::BITS - 1 }>;
122
123/// An entry is either an [`Entry::Int`] integer (`0..=usize::MAX >> 1`) or an owned
124/// [`Entry::Pointer`].
125///
126/// Empty slots are represented by [`None`], not a separate variant.
127///
128/// Integer values are validated by [`Value`]. Pointer alignment (`T::FOREIGN_ALIGN >= 4`) is a
129/// requirement of the slot encoding, enforced at compile time when an [`XArray`] over `T` is
130/// constructed (see the [`XArray`] invariants); [`Entry`] itself carries no invariants.
131pub enum Entry<T: ForeignOwnable> {
132    /// Integer value (`0..=usize::MAX >> 1`).
133    Int(Value),
134    /// Pointer payload. Owned (`T`).
135    Pointer(T),
136}
137
138impl<T: ForeignOwnable> Entry<T> {
139    /// Creates an [`Entry::Int`] validated at compile time.
140    ///
141    /// Fails to compile if `V > usize::MAX >> 1`.
142    pub const fn int<const V: usize>() -> Self {
143        Entry::Int(Value::new::<V>())
144    }
145
146    /// Creates an [`Entry::Int`] validated at runtime.
147    ///
148    /// Returns [`None`] if `v > usize::MAX >> 1`.
149    pub fn try_int(v: usize) -> Option<Self> {
150        Value::try_new(v).map(Entry::Int)
151    }
152}
153
154/// A borrowed entry returned by [`XArray::load()`], containing either an integer or a borrowed
155/// pointer.
156pub enum BorrowedEntry<'a, T: ForeignOwnable + 'a> {
157    /// Integer value (`0..=usize::MAX >> 1`).
158    Int(Value),
159    /// Pointer payload `T::Borrowed<'_>`.
160    Pointer(T::Borrowed<'a>),
161}
162
163/// A mutably borrowed entry returned by [`XArray::load_mut()`], containing either an integer or a
164/// borrowed pointer.
165pub enum BorrowedEntryMut<'a, T: ForeignOwnable + 'a> {
166    /// Integer value (`0..=usize::MAX >> 1`).
167    Int(Value),
168    /// Pointer payload `T::BorrowedMut<'_>`.
169    Pointer(T::BorrowedMut<'a>),
170}
171
172/// The error returned by [`XArray::store()`].
173///
174/// Contains the underlying error and the entry that was not stored.
175pub struct StoreError<T: ForeignOwnable> {
176    /// The error that occurred.
177    pub error: Error,
178    /// The entry that was not stored.
179    pub entry: Entry<T>,
180}
181
182impl<T: ForeignOwnable> fmt::Debug for StoreError<T> {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        f.debug_struct("StoreError")
185            .field("error", &self.error)
186            .finish()
187    }
188}
189
190impl<T: ForeignOwnable> From<StoreError<T>> for Error {
191    #[inline]
192    fn from(value: StoreError<T>) -> Self {
193        value.error
194    }
195}
196
197/// An extensible array backed by a radix tree, mapping `usize` indices to [`Entry`] values.
198///
199/// `T` must be a [`ForeignOwnable`] whose `FOREIGN_ALIGN` is at least 4. The type can be named with
200/// any other `T`, but constructing a value of it fails to compile.
201///
202/// # Ownership
203///
204/// When an [`XArray`] is dropped, all stored [`Entry::Pointer`] entries are freed via
205/// [`ForeignOwnable::from_foreign()`]. This differs from the C `xa_destroy()`, which only frees
206/// internal nodes and requires callers to free stored pointers themselves. [`Entry::Int`] entries
207/// are encoded integers with no backing allocation and need no cleanup.
208///
209/// # Examples
210///
211/// ```
212/// use kernel::alloc::{flags, KBox};
213/// use kernel::rxarray::{BorrowedEntry, Entry, XArray6};
214///
215/// let mut xa = XArray6::<KBox<u64>>::new();
216/// assert!(xa.is_empty());
217///
218/// // Store a pointer entry at index 1.
219/// let boxed = KBox::new(0xbeef_u64, flags::GFP_KERNEL)?;
220/// xa.store(1, Entry::Pointer(boxed), flags::GFP_KERNEL)?;
221/// match xa.load(1) {
222///     Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 0xbeef_u64),
223///     _ => panic!("expected Pointer"),
224/// }
225///
226/// // Store a value entry at index 0.
227/// let old = xa.store(0, Entry::int::<0xdead>(), flags::GFP_KERNEL)?;
228/// assert!(old.is_none());
229/// assert!(!xa.is_empty());
230///
231/// match xa.load(0) {
232///     Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xdead),
233///     _ => panic!("expected Int"),
234/// }
235///
236/// let old = xa.store(0, Entry::int::<0xcafe>(), flags::GFP_KERNEL)?;
237/// match old {
238///     Some(Entry::Int(v)) => assert_eq!(v, 0xdead),
239///     _ => panic!("expected old Int"),
240/// }
241///
242/// match xa.erase(0) {
243///     Some(Entry::Int(v)) => assert_eq!(v, 0xcafe),
244///     _ => panic!("expected erased Int"),
245/// }
246/// assert!(xa.erase(1).is_some());
247/// assert!(xa.is_empty());
248///
249/// # Ok::<(), Error>(())
250/// ```
251///
252/// # Invariants
253///
254/// - `T::FOREIGN_ALIGN >= 4`, ensuring pointer entries do not collide with the integer or internal
255///   entry encoding.
256/// - `SHIFT > 0` and `SIZE == 1 << SHIFT`.
257/// - Every slot in every node satisfies the `Slot` invariants.
258/// - Interior levels (level > 0) contain only empty or node slots. Leaf level (level 0) contains
259///   only empty, `Int`, or `Pointer` slots.
260/// - The subtree below every node slot contains at least one of the `Entry` types (`Int` or
261///   `Pointer`).
262pub struct XArray<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> {
263    root: Node<T, SHIFT, SIZE>,
264}
265
266impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Default for XArray<T, SHIFT, SIZE> {
267    fn default() -> Self {
268        Self::new()
269    }
270}
271
272impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> XArray<T, SHIFT, SIZE> {
273    const fn validate() {
274        const_assert!(SHIFT > 0, "SHIFT must be > 0");
275        const_assert!(SIZE == (1 << SHIFT), "SIZE != 1 << SHIFT");
276        const_assert!(
277            T::FOREIGN_ALIGN >= 4,
278            "ForeignOwnable pointers must be 4-byte aligned"
279        );
280    }
281
282    /// Creates a new empty [`XArray`].
283    pub const fn new() -> Self {
284        Self::validate();
285        // INVARIANT:
286        // - `Self::validate` checks `T::FOREIGN_ALIGN >= 4`, `SHIFT > 0` and `SIZE == 1 << SHIFT`
287        //   at compile time.
288        // - `Node::new` fills every slot with `Slot::EMPTY`, which satisfies the empty-slot case
289        //   of the `Slot` invariants.
290        // - Every slot is empty, and an empty slot is valid at any level.
291        XArray { root: Node::new() }
292    }
293
294    /// Returns the number of levels in the tree.
295    const fn levels() -> usize {
296        (usize::BITS as usize).div_ceil(SHIFT)
297    }
298
299    /// Returns `true` if the tree contains no entries.
300    ///
301    /// Scanning the root node suffices: by the type invariants, every node slot in it leads to at
302    /// least one entry.
303    pub fn is_empty(&self) -> bool {
304        self.root.is_empty()
305    }
306
307    /// Erases the entry at `index`.
308    ///
309    /// Returns the previous entry, or [`None`] if the slot was empty. Empty intermediate nodes are
310    /// freed during traversal.
311    pub fn erase(&mut self, index: usize) -> Option<Entry<T>> {
312        self.root.erase(index, Self::levels() - 1)
313    }
314
315    /// Stores an entry at `index`.
316    ///
317    /// Returns the previous entry, or [`None`] if the slot was empty.
318    ///
319    /// # Errors
320    ///
321    /// Returns a [`StoreError`] carrying the entry back to the caller, with error [`ENOMEM`] if
322    /// a new intermediate node cannot be allocated. A failed stored leaves the tree unchanged. For
323    /// C callers, [`EINVAL`] in case of tree corruption detection.
324    pub fn store(
325        &mut self,
326        index: usize,
327        entry: Entry<T>,
328        flags: Flags,
329    ) -> Result<Option<Entry<T>>, StoreError<T>> {
330        self.root.store(index, entry, Self::levels() - 1, flags)
331    }
332
333    /// Loads the entry at `index`.
334    ///
335    /// Returns [`None`] if the slot is empty. The returned [`BorrowedEntry`] is a value that
336    /// borrows from the array where pointer entries carry `T::Borrowed<'_>` (e.g., `&T` for
337    /// `KBox<T>`), and integer entries carry a copy of the [`Value`].
338    pub fn load(&self, index: usize) -> Option<BorrowedEntry<'_, T>> {
339        self.root.load(index, Self::levels() - 1)
340    }
341
342    /// Loads the entry at `index` for mutation.
343    ///
344    /// Returns [`None`] if the slot is empty. The returned [`BorrowedEntryMut`] is a value that
345    /// borrows from the array where pointer entries carry `T::BorrowedMut<'_>` (e.g., `&mut T` for
346    /// `KBox<T>`), and integer entries carry a copy of the [`Value`].
347    pub fn load_mut(&mut self, index: usize) -> Option<BorrowedEntryMut<'_, T>> {
348        self.root.load_mut(index, Self::levels() - 1)
349    }
350}
351
352/// The internal storage unit: a single `usize` encoding an [`Entry`] or an internal node pointer.
353///
354/// # Invariants
355///
356/// The encoded value `self.0` is one of:
357/// - `0`: the slot is empty.
358/// - An odd value `(v << 1) | 1`: an integer value `v` where `v <= usize::MAX >> 1`.
359/// - An even, non-zero value with bits `1:0 == 0b00`: a valid, non-null pointer previously returned
360///   by [`ForeignOwnable::into_foreign()`].
361/// - An even, non-zero value with bits `1:0 == 0b10` and value > `NODE_THRESHOLD`: a valid pointer
362///   to a live `Node<T, SHIFT, SIZE>` allocation, created by [`Slot::mk_node()`] from
363///   [`KBox::into_raw()`] tagged with `| 2`. The slot owns the [`KBox<Node>`] allocation.
364//
365// All entries with bits `1:0 == 0b10` are internal to the XArray implementation. The encoded value
366// distinguishes sub-types:
367//
368// - Offset 0..=62, encoded 2..=250: sibling entries.
369//   The encoded value contains the offset of the canonical slot within the same node (multi-index
370//   entries, CONFIG_XARRAY_MULTI).
371//
372// - Logical 256, encoded 1026: retry (XA_RETRY_ENTRY).
373//   Tombstone signaling concurrent tree modification; RCU lock-free readers must restart.
374//
375// - Logical 257, encoded 1030: zero (XA_ZERO_ENTRY).
376//   Placeholder marking a slot as occupied but logically empty (xa_reserve, XA_FLAGS_TRACK_FREE).
377//
378// - Encoded value > `NODE_THRESHOLD` (4096): node pointers (heap addresses tagged with | 2). Always
379//   above this threshold.
380//
381// Note: C error entries (xa_is_err()) also encode as internal entries with values far above this
382// threshold. They are never stored in tree slots, only returned by the XArray state machine API. C
383// callers bypass this assumption; the FFI layer must reject error entries before they reach Rust,
384// where kind() would misclassify them as Node, causing as_node() to dereference an invalid
385// pointer.
386//
387// This implementation only creates node pointers via `mk_node()`. The other sub-types are reserved
388// for future RCU and multi-index support. See include/linux/xarray.h.
389#[repr(transparent)]
390struct Slot<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>(usize, PhantomData<T>);
391
392impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Default for Slot<T, SHIFT, SIZE> {
393    fn default() -> Self {
394        Self::EMPTY
395    }
396}
397
398#[derive(Copy, Clone)]
399enum SlotType {
400    Empty,
401    Pointer,
402    Internal,
403    Node, // Internal with value > NODE_THRESHOLD.
404    Int,
405}
406
407impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Slot<T, SHIFT, SIZE> {
408    // INVARIANT: `0` is the encoding for an empty slot.
409    const EMPTY: Self = Slot(0, PhantomData);
410
411    /// Encodes an [`Entry<T>`] into a [`Slot`] for tree storage.
412    fn encode(entry: Entry<T>) -> Self {
413        const_assert!(
414            T::FOREIGN_ALIGN >= 4,
415            "ForeignOwnable pointers must be 4-byte aligned"
416        );
417
418        match entry {
419            Entry::Int(v) => {
420                // INVARIANT: `*v <= usize::MAX >> 1` is guaranteed by `Value` (`Bounded`), so the
421                // shift cannot overflow and the encoded value is odd.
422                Slot((*v << 1) | 1, PhantomData)
423            }
424            Entry::Pointer(p) => {
425                let bits = p.into_foreign() as usize;
426                debug_assert!(bits != 0, "ForeignOwnable returned null");
427                debug_assert!(bits & 3 == 0, "ForeignOwnable pointer not 4-byte aligned");
428                // INVARIANT: `into_foreign()` guarantees a non-null pointer aligned to
429                // `T::FOREIGN_ALIGN`, and `const_assert!(T::FOREIGN_ALIGN >= 4)` above ensures
430                // bits `1:0 == 0b00`.
431                Slot(bits, PhantomData)
432            }
433        }
434    }
435
436    /// Decodes a [`Slot`] into an owned [`Entry<T>`], consuming the slot.
437    ///
438    /// Returns [`None`] for empty slots.
439    fn decode(self) -> Option<Entry<T>> {
440        let slot_type = self.kind();
441        let bits = mem::ManuallyDrop::new(self).0;
442
443        match slot_type {
444            SlotType::Empty => None,
445            // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
446            SlotType::Int => Some(Entry::Int(Value::from_expr(bits >> 1))),
447            SlotType::Node | SlotType::Internal => {
448                debug_assert!(false, "attempt to decode internal/node entry");
449                None
450            }
451            SlotType::Pointer => {
452                // SAFETY:
453                // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
454                //   a previous call to `T::into_foreign()`.
455                // - `decode` takes the slot by value, so the caller has already removed it from
456                //   the tree, and `ManuallyDrop` suppresses `Slot::drop`. This is therefore the
457                //   only `from_foreign` call for this pointer.
458                Some(Entry::Pointer(unsafe {
459                    T::from_foreign(bits as *mut c_void)
460                }))
461            }
462        }
463    }
464
465    /// Borrows the entry in this slot without consuming it.
466    ///
467    /// Returns [`None`] for empty slots. Pointer entries are borrowed via
468    /// [`ForeignOwnable::borrow()`].
469    fn borrow(&self) -> Option<BorrowedEntry<'_, T>> {
470        let slot_type = self.kind();
471        let bits = self.0;
472
473        match slot_type {
474            SlotType::Empty => None,
475            // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
476            SlotType::Int => Some(BorrowedEntry::Int(Value::from_expr(bits >> 1))),
477            SlotType::Node | SlotType::Internal => {
478                debug_assert!(false, "attempt to borrow internal/node entry");
479                None
480            }
481            SlotType::Pointer => {
482                // SAFETY:
483                // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
484                //   a previous call to `T::into_foreign()`.
485                // - Every path that reaches `from_foreign` for this slot needs ownership of it
486                //   (`decode`) or a unique borrow (`Slot::drop`), and reaching either from the
487                //   array requires `&mut self` on the `XArray`. Neither can coexist with this
488                //   shared borrow, so any `from_foreign` on this pointer happens after the borrow
489                //   ends.
490                Some(BorrowedEntry::Pointer(unsafe {
491                    T::borrow(bits as *mut c_void)
492                }))
493            }
494        }
495    }
496
497    /// Mutably borrows the entry in this slot without consuming it.
498    ///
499    /// Returns [`None`] for empty slots. Pointer entries are borrowed via
500    /// [`ForeignOwnable::borrow_mut()`]; integer entries are returned by value.
501    fn borrow_mut(&mut self) -> Option<BorrowedEntryMut<'_, T>> {
502        let slot_type = self.kind();
503        let bits = self.0;
504
505        match slot_type {
506            SlotType::Empty => None,
507            // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
508            SlotType::Int => Some(BorrowedEntryMut::Int(Value::from_expr(bits >> 1))),
509            SlotType::Node | SlotType::Internal => {
510                debug_assert!(false, "attempt to borrow internal/node entry");
511                None
512            }
513            SlotType::Pointer => {
514                // SAFETY:
515                // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
516                //   a previous call to `T::into_foreign()`.
517                // - The returned value borrows `self` mutably, so no other `borrow()` or
518                //   `borrow_mut()` on this slot can overlap it, and every path that reaches
519                //   `from_foreign` for this slot (`decode`, `Slot::drop`) needs the slot by value
520                //   or by unique borrow, so any `from_foreign` on this pointer happens after the
521                //   borrow ends.
522                Some(BorrowedEntryMut::Pointer(unsafe {
523                    T::borrow_mut(bits as *mut c_void)
524                }))
525            }
526        }
527    }
528
529    // The boundary between internal entries and node pointers.
530    const NODE_THRESHOLD: usize = 4096;
531
532    #[inline]
533    fn kind(&self) -> SlotType {
534        let slot = self.0;
535        if slot == 0 {
536            return SlotType::Empty;
537        }
538        match slot & 3 {
539            2 if slot > Self::NODE_THRESHOLD => SlotType::Node,
540            2 => SlotType::Internal,
541            1 | 3 => SlotType::Int,
542            _ => SlotType::Pointer,
543        }
544    }
545
546    #[inline]
547    fn is_empty(&self) -> bool {
548        matches!(self.kind(), SlotType::Empty)
549    }
550
551    #[inline]
552    fn is_node(&self) -> bool {
553        matches!(self.kind(), SlotType::Node)
554    }
555
556    /// Returns a shared reference to the child node pointed to by this entry, or [`None`] if this
557    /// is not a node slot.
558    fn as_node(&self) -> Option<&Node<T, SHIFT, SIZE>> {
559        if !self.is_node() {
560            return None;
561        }
562        let ptr = (self.0 & !3) as *const Node<T, SHIFT, SIZE>;
563        // SAFETY:
564        // - By the type invariant, a slot classified `Node` holds `KBox::into_raw()` of a valid,
565        //   live `KBox<Node<T, SHIFT, SIZE>>` allocation owned by this slot. `& !3` reverses the
566        //   `| 2` tag.
567        // - The returned reference borrows `self`, so the slot cannot be modified and the
568        //   allocation cannot be freed while it is live.
569        Some(unsafe { &*ptr })
570    }
571
572    /// Returns a mutable reference to the child node pointed to by this entry, or [`None`] if this
573    /// is not a node slot.
574    fn as_node_mut(&mut self) -> Option<&mut Node<T, SHIFT, SIZE>> {
575        if !self.is_node() {
576            return None;
577        }
578        let ptr = (self.0 & !3) as *mut Node<T, SHIFT, SIZE>;
579        // SAFETY:
580        // - By the type invariant, a slot classified `Node` holds `KBox::into_raw()` of a valid,
581        //   live `KBox<Node<T, SHIFT, SIZE>>` allocation owned by this slot. `& !3` reverses the
582        //   `| 2` tag.
583        // - The returned reference borrows `self` mutably, so no other reference to the allocation
584        //   can exist and the slot cannot be modified while it is live.
585        Some(unsafe { &mut *ptr })
586    }
587
588    /// Creates a node slot from a heap-allocated [`Node`].
589    fn mk_node(node: KBox<Node<T, SHIFT, SIZE>>) -> Self {
590        let ptr = KBox::into_raw(node) as usize;
591        debug_assert!(ptr & 3 == 0, "Node pointer not aligned");
592        // INVARIANT: `ptr` owns a live `KBox<Node>` allocation from `into_raw()`, so it is at least
593        // 4-byte aligned (checked above) and `| 2` gives bits `1:0 == 0b10`. Kernel heap addresses
594        // are far above `NODE_THRESHOLD`, so the result classifies as node.
595        Slot(ptr | 2, PhantomData)
596    }
597}
598
599impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Drop for Slot<T, SHIFT, SIZE> {
600    fn drop(&mut self) {
601        match self.kind() {
602            SlotType::Pointer => {
603                // SAFETY:
604                // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
605                //   a previous call to `T::into_foreign()`.
606                // - Every other `from_foreign` path (`decode`) consumes the slot through
607                //   `ManuallyDrop`, which suppresses this destructor, so this is the only
608                //   `from_foreign` call for this pointer.
609                drop(unsafe { T::from_foreign(self.0 as *mut c_void) });
610            }
611            SlotType::Node => {
612                let ptr = (self.0 & !3) as *mut Node<T, SHIFT, SIZE>;
613                // SAFETY:
614                // - By the type invariant, a slot classified `Node` holds a pointer produced by
615                //   `KBox::into_raw()` in `Slot::mk_node()`, tagged with `| 2`; `& !3` above
616                //   reverses the tag.
617                // - The slot is being dropped and passes that ownership to the reconstructed box.
618                //   `decode()`, the only other consumer of a slot by value, never accepts node
619                //   slots, so this is the only `KBox::from_raw()` for this pointer.
620                //
621                // Dropping the box drops the child's slots in turn, freeing the subtree. The
622                // recursion is bounded by the tree depth.
623                drop(unsafe { KBox::from_raw(ptr) });
624            }
625            SlotType::Internal => {
626                debug_assert!(false, "internal entry must not reach Slot::drop");
627            }
628            _ => {}
629        }
630    }
631}
632
633/// A single node in the radix tree. Each node contains `SIZE` slots, where each slot may be empty,
634/// contain a user entry (integer or pointer), or point to a child node at the next tree level.
635///
636/// # Invariants
637///
638/// - Interior nodes (level > 0): each slot is either `Empty` or a `Node` pointer created by
639///   [`Slot::mk_node()`] from a valid [`KBox<Node<T, SHIFT, SIZE>>`] allocation.
640/// - Leaf nodes (level == 0): each slot is either `Empty`, `Int`, or `Pointer`. No `Node` or
641///   `Internal` slots may appear at level 0.
642struct Node<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> {
643    slots: [Slot<T, SHIFT, SIZE>; SIZE],
644}
645
646impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Node<T, SHIFT, SIZE> {
647    // Bitmask for extracting the slot offset. Equivalent to XA_CHUNK_MASK.
648    const MASK: usize = SIZE - 1;
649
650    const fn new() -> Self {
651        // INVARIANT: every slot is `Slot::EMPTY`, so the node satisfies the type invariants at any
652        // level.
653        Self {
654            slots: [const { Slot::EMPTY }; SIZE],
655        }
656    }
657
658    /// Extracts the slot index for `index` at the given tree `level`.
659    ///
660    /// Equivalent to `get_offset()` (see `lib/xarray.c`).
661    #[inline]
662    fn slot_index(index: usize, level: usize) -> usize {
663        (index >> (level * SHIFT)) & Self::MASK
664    }
665
666    /// Returns `true` if every slot in this node is empty.
667    fn is_empty(&self) -> bool {
668        self.slots.iter().all(|slot| slot.is_empty())
669    }
670
671    /// Erases the entry at `index`.
672    ///
673    /// Returns the previous entry, or [`None`] if the slot was empty. Frees empty intermediate
674    /// nodes on the way back up.
675    fn erase(&mut self, index: usize, level: usize) -> Option<Entry<T>> {
676        let slot_index = Self::slot_index(index, level);
677        let slot = &mut self.slots[slot_index];
678        if level == 0 {
679            debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
680            // INVARIANT: `mem::take` leaves `Slot::EMPTY` behind, which is permitted at leaf level.
681            let old = mem::take(slot);
682            return old.decode();
683        }
684
685        if let Some(child) = slot.as_node_mut() {
686            let old_value = child.erase(index, level - 1);
687            if child.is_empty() {
688                // INVARIANT: `mem::take` leaves `Slot::EMPTY` behind, which is permitted at
689                // interior level. Dropping the taken slot frees the child node.
690                drop(mem::take(slot));
691            }
692            old_value
693        } else {
694            // Values at intermediate levels indicate tree corruption.
695            debug_assert!(slot.is_empty(), "Non-null non-node entry");
696            None
697        }
698    }
699
700    /// Builds an unlinked subtree that holds `entry` at `index`, from `level` down to leaf.
701    ///
702    /// A failed node allocation at any level returns the [`StoreError`] carrying `entry`, and the
703    /// nodes built so far are dropped automatically on the way out. The caller links the subtree
704    /// into the main tree only after the whole build has succeeded.
705    fn mk_subtree(
706        index: usize,
707        entry: Entry<T>,
708        level: usize,
709        flags: Flags,
710    ) -> Result<KBox<Self>, StoreError<T>> {
711        let mut node = match KBox::new(Self::new(), flags) {
712            Ok(node) => node,
713            Err(error) => {
714                return Err(StoreError {
715                    error: error.into(),
716                    entry,
717                })
718            }
719        };
720        let slot_index = Self::slot_index(index, level);
721        if level == 0 {
722            // INVARIANT: `Slot::encode` returns an `Int` or `Pointer` slot, both of which are
723            // permitted at leaf level.
724            node.slots[slot_index] = Slot::encode(entry);
725        } else {
726            let child_node = Self::mk_subtree(index, entry, level - 1, flags)?;
727            // INVARIANT: `Slot::mk_node` returns a node slot holding a valid `KBox<Node>`, which
728            // is permitted at interior level. The child subtree holds `entry` at its leaf level.
729            node.slots[slot_index] = Slot::mk_node(child_node);
730        }
731        Ok(node)
732    }
733
734    /// Stores `entry` at `index`, allocating intermediate nodes as needed.
735    ///
736    /// Returns the previous entry, or [`None`] if the slot was empty.
737    fn store(
738        &mut self,
739        index: usize,
740        entry: Entry<T>,
741        level: usize,
742        flags: Flags,
743    ) -> Result<Option<Entry<T>>, StoreError<T>> {
744        let slot_index = Self::slot_index(index, level);
745        let slot = &mut self.slots[slot_index];
746        if level == 0 {
747            debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
748            // INVARIANT: `Slot::encode` returns an `Int` or `Pointer` slot, both of which are
749            // permitted at leaf level.
750            let old = mem::replace(slot, Slot::encode(entry));
751            return Ok(old.decode());
752        }
753
754        if slot.is_empty() {
755            // Link the subtree only after every allocation has succeeded. A failed allocation drops
756            // the partial subtree and leaves the main tree untouched.
757            let child_node = Self::mk_subtree(index, entry, level - 1, flags)?;
758            // INVARIANT: `Slot::mk_node` returns a node slot holding a valid `KBox<Node>`, which
759            // is permitted at interior level. The subtree holds `entry` at its leaf level.
760            *slot = Slot::mk_node(child_node);
761            return Ok(None);
762        }
763
764        let Some(child_node) = slot.as_node_mut() else {
765            // Unreachable unless the tree is corrupt. Rust type safety prevents this; C callers
766            // bypass that guarantee, so the FFI layer must ensure tree integrity before reaching
767            // this path.
768            debug_assert!(false, "Non-null non-node entry");
769            return Err(StoreError {
770                error: EINVAL,
771                entry,
772            });
773        };
774        // Any code after this call would block tail-call elimination.
775        child_node.store(index, entry, level - 1, flags)
776    }
777
778    /// Loads the entry at `index`.
779    ///
780    /// Returns a borrowed view of the entry, or [`None`] if the slot is empty.
781    fn load(&self, index: usize, level: usize) -> Option<BorrowedEntry<'_, T>> {
782        let slot_index = Self::slot_index(index, level);
783        let slot = &self.slots[slot_index];
784        if level == 0 {
785            debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
786            return slot.borrow();
787        }
788
789        // Values at intermediate levels indicate tree corruption: trap when debug assertions are
790        // enabled, load as absent otherwise. Same shape as `load_mut()`, where the borrow checker
791        // constraints it.
792        debug_assert!(slot.is_node() || slot.is_empty(), "Non-null non-node entry");
793        slot.as_node()?.load(index, level - 1)
794    }
795
796    /// Loads the entry at `index` for mutation.
797    ///
798    /// Returns [`None`] if the slot is empty.
799    fn load_mut(&mut self, index: usize, level: usize) -> Option<BorrowedEntryMut<'_, T>> {
800        let slot_index = Self::slot_index(index, level);
801        let slot = &mut self.slots[slot_index];
802        if level == 0 {
803            debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
804            return slot.borrow_mut();
805        }
806
807        // Values at intermediate levels indicate tree corruption: trap when debug assertions are
808        // enabled, load as absent otherwise.
809        debug_assert!(slot.is_node() || slot.is_empty(), "Non-null non-node entry");
810        slot.as_node_mut()?.load_mut(index, level - 1)
811    }
812}
813
814#[macros::kunit_tests(rust_rxarray)]
815mod tests {
816    use super::*;
817    use kernel::alloc::flags;
818
819    // Dispatches a test across all SHIFT/SIZE configurations. Default arm passes <T, SHIFT, SIZE>
820    // with T = KBox<u64>; `ptr` arm passes <SHIFT, SIZE> only for pointer tests that must construct
821    // KBox<u64> values because ForeignOwnable has no constructor, so T must be concrete.
822    macro_rules! for_each_xarray {
823        ($fn:ident) => {
824            $fn::<KBox<u64>, 4, 16>();
825            $fn::<KBox<u64>, 6, 64>();
826        };
827        (ptr, $fn:ident) => {
828            $fn::<4, 16>();
829            $fn::<6, 64>();
830        };
831    }
832
833    // `XArray` carries no explicit `Send`/`Sync` impl: the `PhantomData<T>` in `Slot` makes the
834    // auto-derived bounds follow `T`. These assertions fail to compile if that ever stops holding.
835    const fn assert_send<T: Send>() {}
836    const fn assert_sync<T: Sync>() {}
837
838    fn assert_auto_traits_impl<
839        T: ForeignOwnable + Send + Sync,
840        const SHIFT: usize,
841        const SIZE: usize,
842    >() {
843        assert_send::<XArray<T, SHIFT, SIZE>>();
844        assert_sync::<XArray<T, SHIFT, SIZE>>();
845    }
846
847    #[test]
848    fn assert_auto_traits() {
849        for_each_xarray!(assert_auto_traits_impl);
850    }
851
852    fn new_is_empty_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
853        let xa = XArray::<T, SHIFT, SIZE>::new();
854        assert!(xa.is_empty());
855        assert!(xa.load(0).is_none());
856        assert!(xa.load(usize::MAX).is_none());
857    }
858
859    #[test]
860    fn new_is_empty() {
861        for_each_xarray!(new_is_empty_impl);
862    }
863
864    fn store_load_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
865        let mut xa = XArray::<T, SHIFT, SIZE>::new();
866        let old = xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
867        assert!(old.is_none());
868        assert!(!xa.is_empty());
869
870        match xa.load(0) {
871            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 137),
872            _ => panic!("expected Int"),
873        };
874    }
875
876    #[test]
877    fn store_load_value() {
878        for_each_xarray!(store_load_value_impl);
879    }
880
881    fn overwrite_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
882        let mut xa = XArray::<T, SHIFT, SIZE>::new();
883        xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
884            .unwrap();
885        let old = xa
886            .store(137, Entry::int::<2002>(), flags::GFP_KERNEL)
887            .unwrap();
888
889        match old {
890            Some(Entry::Int(v)) => assert_eq!(v, 1001),
891            _ => panic!("expected old Int"),
892        }
893        match xa.load(137) {
894            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 2002),
895            _ => panic!("expected Int"),
896        };
897    }
898
899    #[test]
900    fn overwrite_value() {
901        for_each_xarray!(overwrite_value_impl);
902    }
903
904    fn erase_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
905        let mut xa = XArray::<T, SHIFT, SIZE>::new();
906        xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
907            .unwrap();
908        xa.store(138, Entry::int::<1002>(), flags::GFP_KERNEL)
909            .unwrap();
910        xa.store(139, Entry::int::<1003>(), flags::GFP_KERNEL)
911            .unwrap();
912
913        let old = xa.erase(138);
914        match old {
915            Some(Entry::Int(v)) => assert_eq!(v, 1002),
916            _ => panic!("expected erased Int"),
917        }
918        assert!(xa.load(138).is_none());
919
920        match xa.load(137) {
921            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1001),
922            _ => panic!("expected Int at neighbor"),
923        }
924        match xa.load(139) {
925            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1003),
926            _ => panic!("expected Int at neighbor"),
927        };
928    }
929
930    #[test]
931    fn erase_value() {
932        for_each_xarray!(erase_value_impl);
933    }
934
935    // Two paths: (1) empty tree with no nodes allocated, (2) intermediate nodes exist but the
936    // target leaf slot was never stored.
937    fn erase_nonexistent_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
938        let mut xa = XArray::<T, SHIFT, SIZE>::new();
939        assert!(xa.erase(999).is_none());
940
941        // Intermediate nodes exist for index 0; index 1 shares the same leaf node but its slot was
942        // never populated.
943        xa.store(0, Entry::int::<1>(), flags::GFP_KERNEL).unwrap();
944        assert!(xa.erase(1).is_none());
945        match xa.load(0) {
946            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1),
947            _ => panic!("expected Int after erasing neighbor"),
948        };
949    }
950
951    #[test]
952    fn erase_nonexistent() {
953        for_each_xarray!(erase_nonexistent_impl);
954    }
955
956    // After erase frees intermediate nodes, re-store at the same index must re-allocate them.
957    fn erase_and_restore_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
958        let mut xa = XArray::<T, SHIFT, SIZE>::new();
959        xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
960            .unwrap();
961
962        let erased = xa.erase(137);
963        match erased {
964            Some(Entry::Int(v)) => assert_eq!(v, 1001),
965            _ => panic!("expected erased Int"),
966        }
967        assert!(xa.load(137).is_none());
968
969        let old = xa
970            .store(137, Entry::int::<2002>(), flags::GFP_KERNEL)
971            .unwrap();
972        assert!(old.is_none());
973        match xa.load(137) {
974            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 2002),
975            _ => panic!("expected Int"),
976        };
977    }
978
979    #[test]
980    fn erase_and_restore() {
981        for_each_xarray!(erase_and_restore_impl);
982    }
983
984    // Stores at node boundaries to exercise tree structure:
985    // - SIZE-1: last slot in the first leaf node.
986    // - SIZE: first index requiring a second leaf node.
987    // - SIZE*SIZE-1: last index in the first level-1 subtree.
988    // - SIZE*SIZE: first index requiring a third tree level.
989    fn store_at_boundaries_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
990        let mut xa = XArray::<T, SHIFT, SIZE>::new();
991        xa.store(SIZE - 1, Entry::int::<0xA>(), flags::GFP_KERNEL)
992            .unwrap();
993        xa.store(SIZE, Entry::int::<0xB>(), flags::GFP_KERNEL)
994            .unwrap();
995        xa.store(SIZE * SIZE - 1, Entry::int::<0xC>(), flags::GFP_KERNEL)
996            .unwrap();
997        xa.store(SIZE * SIZE, Entry::int::<0xD>(), flags::GFP_KERNEL)
998            .unwrap();
999
1000        match xa.load(SIZE - 1) {
1001            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xA),
1002            _ => panic!("expected Int at SIZE-1"),
1003        }
1004        match xa.load(SIZE) {
1005            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xB),
1006            _ => panic!("expected Int at SIZE"),
1007        }
1008        match xa.load(SIZE * SIZE - 1) {
1009            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xC),
1010            _ => panic!("expected Int at SIZE*SIZE-1"),
1011        }
1012        match xa.load(SIZE * SIZE) {
1013            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xD),
1014            _ => panic!("expected Int at SIZE*SIZE"),
1015        }
1016        assert!(xa.load(0).is_none());
1017    }
1018
1019    #[test]
1020    fn store_at_boundaries() {
1021        for_each_xarray!(store_at_boundaries_impl);
1022    }
1023
1024    // For XArray6 this allocates 10 intermediate nodes; for XArray4, 15. Erasing verifies cascading
1025    // cleanup frees all intermediate nodes back to the root.
1026    fn store_at_max_index_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1027        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1028        xa.store(usize::MAX, Entry::int::<0xFF>(), flags::GFP_KERNEL)
1029            .unwrap();
1030        match xa.load(usize::MAX) {
1031            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xFF),
1032            _ => panic!("expected Int at usize::MAX"),
1033        }
1034        assert!(xa.load(0).is_none());
1035
1036        match xa.erase(usize::MAX) {
1037            Some(Entry::Int(v)) => assert_eq!(v, 0xFF),
1038            _ => panic!("expected erased Int at usize::MAX"),
1039        }
1040        assert!(xa.load(usize::MAX).is_none());
1041        assert!(xa.is_empty());
1042    }
1043
1044    #[test]
1045    fn store_at_max_index() {
1046        for_each_xarray!(store_at_max_index_impl);
1047    }
1048
1049    // SIZE*3 entries spanning multiple leaf nodes. Erases even indices and verifies odd indices
1050    // remain intact. Erase return values are not checked here; that path is covered by erase_value.
1051    fn bulk_operations_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1052        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1053        let count = SIZE * 3;
1054
1055        for i in 0..count {
1056            xa.store(i, Entry::try_int(i * 10).unwrap(), flags::GFP_KERNEL)
1057                .unwrap();
1058        }
1059
1060        for i in 0..count {
1061            if i % 2 == 0 {
1062                xa.erase(i);
1063            }
1064        }
1065
1066        for i in 0..count {
1067            match xa.load(i) {
1068                Some(BorrowedEntry::Int(v)) => {
1069                    assert_eq!(i % 2, 1);
1070                    assert_eq!(v, i * 10);
1071                }
1072                Some(BorrowedEntry::Pointer(_)) => {
1073                    panic!("unexpected Pointer in value-only tree")
1074                }
1075                None => assert_eq!(i % 2, 0),
1076            }
1077        }
1078    }
1079
1080    #[test]
1081    fn bulk_operations() {
1082        for_each_xarray!(bulk_operations_impl);
1083    }
1084
1085    // Stores entries in different subtrees (indices 0 and SIZE diverge at level 1), then erases
1086    // both. The second erase cascades cleanup through intermediate nodes that no longer have any
1087    // children.
1088    fn erase_all_restores_empty_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1089        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1090        xa.store(0, Entry::int::<1>(), flags::GFP_KERNEL).unwrap();
1091        xa.store(SIZE, Entry::int::<2>(), flags::GFP_KERNEL)
1092            .unwrap();
1093        assert!(!xa.is_empty());
1094
1095        xa.erase(0);
1096        assert!(!xa.is_empty());
1097        xa.erase(SIZE);
1098        assert!(xa.is_empty());
1099    }
1100
1101    #[test]
1102    fn erase_all_restores_empty() {
1103        for_each_xarray!(erase_all_restores_empty_impl);
1104    }
1105
1106    // Entry::int::<0>() encodes as (0 << 1) | 1 = 1; must not be confused with the empty slot
1107    // encoding (0).
1108    fn value_zero_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1109        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1110        xa.store(0, Entry::int::<0>(), flags::GFP_KERNEL).unwrap();
1111        assert!(!xa.is_empty());
1112        match xa.load(0) {
1113            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0),
1114            _ => panic!("expected Int"),
1115        }
1116
1117        match xa.erase(0) {
1118            Some(Entry::Int(v)) => assert_eq!(v, 0),
1119            _ => panic!("expected erased Int"),
1120        }
1121        assert!(xa.load(0).is_none());
1122    }
1123
1124    #[test]
1125    fn value_zero() {
1126        for_each_xarray!(value_zero_impl);
1127    }
1128
1129    // Pointer-specific tests (ForeignOwnable path with KBox<u64>).
1130
1131    fn store_load_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1132        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1133        let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1134        let old = xa
1135            .store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1136            .unwrap();
1137        assert!(old.is_none());
1138
1139        match xa.load(0) {
1140            Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1141            _ => panic!("expected Pointer"),
1142        }
1143    }
1144
1145    #[test]
1146    fn store_load_pointer() {
1147        for_each_xarray!(ptr, store_load_pointer_impl);
1148    }
1149
1150    // Erase returns the owned KBox, verifying that Slot::decode transfers ownership via
1151    // ManuallyDrop without double-free or leak.
1152    fn erase_returns_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1153        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1154        let boxed = KBox::new(99u64, flags::GFP_KERNEL).unwrap();
1155        xa.store(5, Entry::Pointer(boxed), flags::GFP_KERNEL)
1156            .unwrap();
1157
1158        match xa.erase(5) {
1159            Some(Entry::Pointer(owned)) => assert_eq!(*owned, 99u64),
1160            _ => panic!("expected owned Pointer"),
1161        }
1162        assert!(xa.load(5).is_none());
1163    }
1164
1165    #[test]
1166    fn erase_returns_pointer() {
1167        for_each_xarray!(ptr, erase_returns_pointer_impl);
1168    }
1169
1170    fn overwrite_pointer_with_value_impl<const SHIFT: usize, const SIZE: usize>() {
1171        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1172        let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1173        xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1174            .unwrap();
1175
1176        let old = xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1177        match old {
1178            Some(Entry::Pointer(p)) => assert_eq!(*p, 42u64),
1179            _ => panic!("expected old Pointer"),
1180        }
1181        match xa.load(0) {
1182            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 137),
1183            _ => panic!("expected Int"),
1184        }
1185    }
1186
1187    #[test]
1188    fn overwrite_pointer_with_value() {
1189        for_each_xarray!(ptr, overwrite_pointer_with_value_impl);
1190    }
1191
1192    fn overwrite_value_with_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1193        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1194        xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1195
1196        let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1197        let old = xa
1198            .store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1199            .unwrap();
1200        match old {
1201            Some(Entry::Int(v)) => assert_eq!(v, 137),
1202            _ => panic!("expected old Int"),
1203        }
1204        match xa.load(0) {
1205            Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1206            _ => panic!("expected Pointer"),
1207        }
1208    }
1209
1210    #[test]
1211    fn overwrite_value_with_pointer() {
1212        for_each_xarray!(ptr, overwrite_value_with_pointer_impl);
1213    }
1214
1215    fn mixed_values_and_pointers_impl<const SHIFT: usize, const SIZE: usize>() {
1216        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1217        let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1218        xa.store(0, Entry::int::<100>(), flags::GFP_KERNEL).unwrap();
1219        xa.store(1, Entry::Pointer(boxed), flags::GFP_KERNEL)
1220            .unwrap();
1221
1222        match xa.load(0) {
1223            Some(BorrowedEntry::Int(v)) => assert_eq!(v, 100),
1224            _ => panic!("expected Int"),
1225        }
1226        match xa.load(1) {
1227            Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1228            _ => panic!("expected Pointer"),
1229        }
1230    }
1231
1232    #[test]
1233    fn mixed_values_and_pointers() {
1234        for_each_xarray!(ptr, mixed_values_and_pointers_impl);
1235    }
1236
1237    // Drops a tree with mixed Int (even indices) and Pointer (odd indices) entries. Correctness
1238    // depends on KASAN/kmemleak detecting leaks or double-frees.
1239    fn drop_frees_pointers_impl<const SHIFT: usize, const SIZE: usize>() {
1240        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1241        let count = SIZE * 2;
1242        for i in 0..count {
1243            if i % 2 == 0 {
1244                xa.store(i, Entry::try_int(i * 10).unwrap(), flags::GFP_KERNEL)
1245                    .unwrap();
1246            } else {
1247                let b = KBox::new(i as u64, flags::GFP_KERNEL).unwrap();
1248                xa.store(i, Entry::Pointer(b), flags::GFP_KERNEL).unwrap();
1249            }
1250        }
1251    }
1252
1253    #[test]
1254    fn drop_frees_pointers() {
1255        for_each_xarray!(ptr, drop_frees_pointers_impl);
1256    }
1257
1258    // usize::MAX >> 1 is the maximum valid integer entry. Exercises both compile-time validation
1259    // (Entry::int) and runtime validation (Entry::try_int).
1260    fn value_encoding_boundary_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1261        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1262        let max = usize::MAX >> 1;
1263
1264        // Runtime: try_int accepts max, rejects max+1.
1265        assert!(Entry::<T>::try_int(max).is_some());
1266        assert!(Entry::<T>::try_int(max + 1).is_none());
1267        assert!(Entry::<T>::try_int(usize::MAX).is_none());
1268
1269        // Compile-time: `Entry::int` validates via `const_assert!` in `Bounded::new`.
1270        xa.store(0, Entry::int::<{ usize::MAX >> 1 }>(), flags::GFP_KERNEL)
1271            .unwrap();
1272        match xa.load(0) {
1273            Some(BorrowedEntry::Int(v)) => assert_eq!(v, max),
1274            _ => panic!("expected max value"),
1275        };
1276    }
1277
1278    #[test]
1279    fn value_encoding_boundary() {
1280        for_each_xarray!(value_encoding_boundary_impl);
1281    }
1282
1283    fn overwrite_pointer_with_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1284        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1285        let first = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1286        xa.store(0, Entry::Pointer(first), flags::GFP_KERNEL)
1287            .unwrap();
1288
1289        let second = KBox::new(99u64, flags::GFP_KERNEL).unwrap();
1290        let old = xa
1291            .store(0, Entry::Pointer(second), flags::GFP_KERNEL)
1292            .unwrap();
1293        match old {
1294            Some(Entry::Pointer(p)) => assert_eq!(*p, 42u64),
1295            _ => panic!("expected old Pointer"),
1296        }
1297        match xa.load(0) {
1298            Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 99u64),
1299            _ => panic!("expected new Pointer"),
1300        }
1301    }
1302
1303    #[test]
1304    fn overwrite_pointer_with_pointer() {
1305        for_each_xarray!(ptr, overwrite_pointer_with_pointer_impl);
1306    }
1307
1308    fn erase_at_boundaries_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1309        let mut xa = XArray::<T, SHIFT, SIZE>::new();
1310        xa.store(SIZE - 1, Entry::int::<0xA>(), flags::GFP_KERNEL)
1311            .unwrap();
1312        xa.store(SIZE, Entry::int::<0xB>(), flags::GFP_KERNEL)
1313            .unwrap();
1314        xa.store(SIZE * SIZE - 1, Entry::int::<0xC>(), flags::GFP_KERNEL)
1315            .unwrap();
1316        xa.store(SIZE * SIZE, Entry::int::<0xD>(), flags::GFP_KERNEL)
1317            .unwrap();
1318
1319        match xa.erase(SIZE * SIZE) {
1320            Some(Entry::Int(v)) => assert_eq!(v, 0xD),
1321            _ => panic!("expected erased Int at SIZE*SIZE"),
1322        }
1323        match xa.erase(SIZE * SIZE - 1) {
1324            Some(Entry::Int(v)) => assert_eq!(v, 0xC),
1325            _ => panic!("expected erased Int at SIZE*SIZE-1"),
1326        }
1327        match xa.erase(SIZE) {
1328            Some(Entry::Int(v)) => assert_eq!(v, 0xB),
1329            _ => panic!("expected erased Int at SIZE"),
1330        }
1331        match xa.erase(SIZE - 1) {
1332            Some(Entry::Int(v)) => assert_eq!(v, 0xA),
1333            _ => panic!("expected erased Int at SIZE-1"),
1334        }
1335        assert!(xa.is_empty());
1336    }
1337
1338    #[test]
1339    fn erase_at_boundaries() {
1340        for_each_xarray!(erase_at_boundaries_impl);
1341    }
1342
1343    // Erasing the sole pointer must return the owned KBox and free all intermediate nodes.
1344    fn erase_last_pointer_cascading_impl<const SHIFT: usize, const SIZE: usize>() {
1345        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1346        let boxed = KBox::new(777u64, flags::GFP_KERNEL).unwrap();
1347        xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1348            .unwrap();
1349
1350        match xa.erase(0) {
1351            Some(Entry::Pointer(p)) => assert_eq!(*p, 777u64),
1352            _ => panic!("expected owned Pointer"),
1353        }
1354        assert!(xa.is_empty());
1355    }
1356
1357    #[test]
1358    fn erase_last_pointer_cascading() {
1359        for_each_xarray!(ptr, erase_last_pointer_cascading_impl);
1360    }
1361
1362    fn load_mut_entries_impl<const SHIFT: usize, const SIZE: usize>() {
1363        let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1364        assert!(xa.load_mut(0).is_none());
1365
1366        let boxed = KBox::new(137u64, flags::GFP_KERNEL).unwrap();
1367        xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1368            .unwrap();
1369        xa.store(1, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1370
1371        match xa.load_mut(0) {
1372            Some(BorrowedEntryMut::Pointer(val)) => *val = 131u64,
1373            _ => panic!("expected Pointer"),
1374        }
1375        match xa.load(0) {
1376            Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 131u64),
1377            _ => panic!("expected Pointer"),
1378        }
1379        match xa.load_mut(1) {
1380            Some(BorrowedEntryMut::Int(val)) => assert_eq!(val, 137),
1381            _ => panic!("expected Int"),
1382        }
1383    }
1384
1385    #[test]
1386    fn load_mut_entries() {
1387        for_each_xarray!(ptr, load_mut_entries_impl);
1388    }
1389
1390    fn store_error_impl<const SHIFT: usize, const SIZE: usize>() {
1391        let err = StoreError {
1392            error: ENOMEM,
1393            entry: Entry::<KBox<u64>>::int::<137>(),
1394        };
1395        match &err.entry {
1396            Entry::Int(value) => assert_eq!(*value, 137),
1397            _ => panic!("expected Int"),
1398        }
1399        let e: Error = err.into();
1400        assert_eq!(e.to_errno(), ENOMEM.to_errno());
1401    }
1402
1403    #[test]
1404    fn store_error() {
1405        for_each_xarray!(ptr, store_error_impl);
1406    }
1407}