Skip to main content

triblespace_core/
patch.rs

1//! Persistent Adaptive Trie with Cuckoo-compression and
2//! Hash-maintenance (PATCH).
3//!
4//! See the [PATCH](../book/src/deep-dive/patch.md) chapter of the Tribles Book
5//! for the full design description and hashing scheme.
6//!
7//! Values stored in leaves are not part of hashing or equality comparisons.
8//! Two [`PATCH`](crate::patch::PATCH)es are considered equal if they contain the same set of keys,
9//! even if the associated values differ. This allows using the structure as an
10//! idempotent blobstore where a value's hash determines its key.
11//!
12#![allow(unstable_name_collisions)]
13
14mod branch;
15/// Byte-indexed lookup tables used by PATCH branch nodes.
16pub mod bytetable;
17mod entry;
18mod leaf;
19
20use arrayvec::ArrayVec;
21
22use branch::*;
23/// Re-export of [`Entry`](entry::Entry).
24pub use entry::Entry;
25use leaf::*;
26
27/// Re-export of all byte table utilities.
28pub use bytetable::*;
29use rand::thread_rng;
30use rand::RngCore;
31use std::cmp::Reverse;
32use std::convert::TryInto;
33use std::fmt;
34use std::fmt::Debug;
35use std::marker::PhantomData;
36use std::ptr::NonNull;
37use std::sync::Once;
38
39#[cfg(not(target_pointer_width = "64"))]
40compile_error!("PATCH tagged pointers require 64-bit targets");
41
42static mut SIP_KEY: [u8; 16] = [0; 16];
43static INIT: Once = Once::new();
44
45/// Minimum `other.leaf_count` at which [`Head::par_union`] takes the
46/// scatter + bitset + rayon::scope-spawn path on the equal-depth-
47/// branch arm. Below this, the per-key `modify_child` loop wins
48/// because asymmetric merges only touch a handful of slots.
49#[cfg(feature = "parallel")]
50const PARALLEL_PATCH_UNION_THRESHOLD: usize = 4096;
51
52/// Parallel-aware PATCH union, with a shared work-stealing budget
53/// carried across the entire recursive descent.
54///
55/// Two-phase model per parallel call:
56///   1. Spawn phase (collect sequentially, dispatch per child):
57///      drain "both" pairs, for each: claim 1 unit from the
58///      shared budget — if successful, spawn the child union as
59///      a `rayon::scope` task; if budget is exhausted, run the
60///      child serially via `Head::union`.
61///   2. Install phase (purely serial): scatter-collected resolved
62///      heads + single-side pass-throughs land in the parent
63///      branch, then `recompute_aggregates` rebuilds the
64///      hash/leaf_count/segment_count/childleaf in one pass.
65///
66/// The budget is a single shared atomic — `num_threads²` total
67/// spawns across the entire descent, after which everything is
68/// sequential. This caps overhead without restricting the depth
69/// at which parallelism is reached: a heavy subtree near the
70/// root claims many units; a balanced descent spreads them.
71#[cfg(feature = "parallel")]
72mod parallel_union {
73    use core::sync::atomic::{AtomicUsize, Ordering};
74
75    /// Carries the shared spawn budget across recursive
76    /// `par_union_with_ctx` calls.
77    pub(crate) struct ParUnionCtx {
78        pub(crate) budget: AtomicUsize,
79    }
80
81    impl ParUnionCtx {
82        pub(crate) fn new() -> Self {
83            let n = rayon::current_num_threads();
84            Self {
85                budget: AtomicUsize::new(n.saturating_mul(n).max(2)),
86            }
87        }
88
89        /// Try to claim one spawn unit. Returns `true` if a unit was
90        /// claimed (caller should spawn), `false` if the budget was
91        /// already exhausted (caller should run serially).
92        ///
93        /// A naive `fetch_sub(1)` would wrap `0 → usize::MAX` on
94        /// over-subtract, briefly letting other threads see a huge
95        /// budget — so we use compare-exchange to refuse the claim
96        /// without ever observing the underflow.
97        pub(crate) fn try_claim(&self) -> bool {
98            let mut current = self.budget.load(Ordering::Relaxed);
99            loop {
100                if current == 0 {
101                    return false;
102                }
103                match self.budget.compare_exchange_weak(
104                    current,
105                    current - 1,
106                    Ordering::Relaxed,
107                    Ordering::Relaxed,
108                ) {
109                    Ok(_) => return true,
110                    Err(observed) => current = observed,
111                }
112            }
113        }
114    }
115
116    /// Raw-pointer wrapper for the scatter-write target. Each
117    /// spawned task writes to `resolved[k]` for its specific key
118    /// byte `k`; keys are pairwise distinct by construction (each
119    /// "both" bit in the partition uniquely identifies a slot), so
120    /// the writes are non-aliasing despite sharing a `*mut` across
121    /// threads.
122    ///
123    /// `write_at` exists as an inherent method (rather than callers
124    /// reading the `*mut` field directly) so that move closures
125    /// capture the whole wrapper — Rust 2021 precise-capture would
126    /// otherwise grab the raw pointer field, dropping the manual
127    /// `Send`/`Sync` impls and triggering a Send error.
128    pub(crate) struct ScatterPtr<T>(pub *mut T);
129
130    // Manual `Copy`/`Clone` impls so `T` doesn't get a spurious
131    // `T: Copy` / `T: Clone` bound from derive — the wrapper holds a
132    // raw pointer, which is always `Copy` regardless of `T`.
133    impl<T> Clone for ScatterPtr<T> {
134        fn clone(&self) -> Self {
135            *self
136        }
137    }
138    impl<T> Copy for ScatterPtr<T> {}
139
140    unsafe impl<T> Send for ScatterPtr<T> {}
141    unsafe impl<T> Sync for ScatterPtr<T> {}
142
143    impl<T> ScatterPtr<T> {
144        /// SAFETY: `i` must be in-bounds of the underlying buffer,
145        /// and the caller must guarantee no other thread is writing
146        /// to slot `i` concurrently.
147        pub(crate) unsafe fn write_at(self, i: usize, v: T) {
148            self.0.add(i).write(v);
149        }
150    }
151}
152
153/// Initializes the SIP key used for key hashing.
154/// This function is called automatically when a new PATCH is created.
155fn init_sip_key() {
156    INIT.call_once(|| {
157        bytetable::init();
158
159        let mut rng = thread_rng();
160        unsafe {
161            rng.fill_bytes(&mut SIP_KEY[..]);
162        }
163    });
164}
165
166/// Builds a per-byte segment map from the segment lengths.
167///
168/// The returned table maps each key byte to its segment index.
169pub const fn build_segmentation<const N: usize, const M: usize>(lens: [usize; M]) -> [usize; N] {
170    let mut res = [0; N];
171    let mut seg = 0;
172    let mut off = 0;
173    while seg < M {
174        let len = lens[seg];
175        let mut i = 0;
176        while i < len {
177            res[off + i] = seg;
178            i += 1;
179        }
180        off += len;
181        seg += 1;
182    }
183    res
184}
185
186/// Builds an identity permutation table of length `N`.
187pub const fn identity_map<const N: usize>() -> [usize; N] {
188    let mut res = [0; N];
189    let mut i = 0;
190    while i < N {
191        res[i] = i;
192        i += 1;
193    }
194    res
195}
196
197/// Builds a table translating indices from key order to tree order.
198///
199/// `lens` describes the segment lengths in key order and `perm` is the
200/// permutation of those segments in tree order.
201pub const fn build_key_to_tree<const N: usize, const M: usize>(
202    lens: [usize; M],
203    perm: [usize; M],
204) -> [usize; N] {
205    let mut key_starts = [0; M];
206    let mut off = 0;
207    let mut i = 0;
208    while i < M {
209        key_starts[i] = off;
210        off += lens[i];
211        i += 1;
212    }
213
214    let mut tree_starts = [0; M];
215    off = 0;
216    i = 0;
217    while i < M {
218        let seg = perm[i];
219        tree_starts[seg] = off;
220        off += lens[seg];
221        i += 1;
222    }
223
224    let mut res = [0; N];
225    let mut seg = 0;
226    while seg < M {
227        let len = lens[seg];
228        let ks = key_starts[seg];
229        let ts = tree_starts[seg];
230        let mut j = 0;
231        while j < len {
232            res[ks + j] = ts + j;
233            j += 1;
234        }
235        seg += 1;
236    }
237    res
238}
239
240/// Inverts a permutation table.
241pub const fn invert<const N: usize>(arr: [usize; N]) -> [usize; N] {
242    let mut res = [0; N];
243    let mut i = 0;
244    while i < N {
245        res[arr[i]] = i;
246        i += 1;
247    }
248    res
249}
250
251#[doc(hidden)]
252#[macro_export]
253macro_rules! key_segmentation {
254    (@count $($e:expr),* $(,)?) => {
255        <[()]>::len(&[$($crate::key_segmentation!(@sub $e)),*])
256    };
257    (@sub $e:expr) => { () };
258    ($(#[$meta:meta])* $name:ident, $len:expr, [$($seg_len:expr),+ $(,)?]) => {
259        $(#[$meta])*
260        #[derive(Copy, Clone, Debug)]
261        pub struct $name;
262        impl $name {
263            pub const SEG_LENS: [usize; $crate::key_segmentation!(@count $($seg_len),*)] = [$($seg_len),*];
264        }
265        impl $crate::patch::KeySegmentation<$len> for $name {
266            const SEGMENTS: [usize; $len] = $crate::patch::build_segmentation::<$len, {$crate::key_segmentation!(@count $($seg_len),*)}>(Self::SEG_LENS);
267        }
268    };
269}
270
271#[doc(hidden)]
272#[macro_export]
273macro_rules! key_schema {
274    (@count $($e:expr),* $(,)?) => {
275        <[()]>::len(&[$($crate::key_schema!(@sub $e)),*])
276    };
277    (@sub $e:expr) => { () };
278    ($(#[$meta:meta])* $name:ident, $seg:ty, $len:expr, [$($perm:expr),+ $(,)?]) => {
279        $(#[$meta])*
280        #[derive(Copy, Clone, Debug)]
281        pub struct $name;
282        impl $crate::patch::KeySchema<$len> for $name {
283            type Segmentation = $seg;
284            const SEGMENT_PERM: &'static [usize] = &[$($perm),*];
285            const KEY_TO_TREE: [usize; $len] = $crate::patch::build_key_to_tree::<$len, {$crate::key_schema!(@count $($perm),*)}>(<$seg>::SEG_LENS, [$($perm),*]);
286            const TREE_TO_KEY: [usize; $len] = $crate::patch::invert(Self::KEY_TO_TREE);
287        }
288    };
289}
290
291/// A trait is used to provide a re-ordered view of the keys stored in the PATCH.
292/// This allows for different PATCH instances share the same leaf nodes,
293/// independent of the key ordering used in the tree.
294pub trait KeySchema<const KEY_LEN: usize>: Copy + Clone + Debug {
295    /// The segmentation this ordering operates over.
296    type Segmentation: KeySegmentation<KEY_LEN>;
297    /// Order of segments from key layout to tree layout.
298    const SEGMENT_PERM: &'static [usize];
299    /// Maps each key index to its position in the tree view.
300    const KEY_TO_TREE: [usize; KEY_LEN];
301    /// Maps each tree index to its position in the key view.
302    const TREE_TO_KEY: [usize; KEY_LEN];
303
304    /// Reorders the key from the shared key ordering to the tree ordering.
305    fn tree_ordered(key: &[u8; KEY_LEN]) -> [u8; KEY_LEN] {
306        let mut new_key = [0; KEY_LEN];
307        let mut i = 0;
308        while i < KEY_LEN {
309            new_key[Self::KEY_TO_TREE[i]] = key[i];
310            i += 1;
311        }
312        new_key
313    }
314
315    /// Reorders the key from the tree ordering to the shared key ordering.
316    fn key_ordered(tree_key: &[u8; KEY_LEN]) -> [u8; KEY_LEN] {
317        let mut new_key = [0; KEY_LEN];
318        let mut i = 0;
319        while i < KEY_LEN {
320            new_key[Self::TREE_TO_KEY[i]] = tree_key[i];
321            i += 1;
322        }
323        new_key
324    }
325
326    /// Return the segment index for the byte at `at_depth` in tree ordering.
327    ///
328    /// Default implementation reads the static segmentation table and the
329    /// tree->key mapping. Having this as a method makes call sites clearer and
330    /// reduces the verbosity of expressions that access the segmentation table.
331    fn segment_of_tree_depth(at_depth: usize) -> usize {
332        <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[at_depth]]
333    }
334
335    /// Return true if the tree-ordered bytes at `a` and `b` belong to the same
336    /// logical segment.
337    fn same_segment_tree(a: usize, b: usize) -> bool {
338        <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[a]]
339            == <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[b]]
340    }
341}
342
343/// This trait is used to segment keys stored in the PATCH.
344/// The segmentation is used to determine sub-fields of the key,
345/// allowing for segment based operations, like counting the number
346/// of elements in a segment with a given prefix without traversing the tree.
347///
348/// Note that the segmentation is defined on the shared key ordering,
349/// and should thus be only implemented once, independent of additional key orderings.
350///
351/// See [TribleSegmentation](crate::trible::TribleSegmentation) for an example that segments keys into entity,
352/// attribute, and value segments.
353pub trait KeySegmentation<const KEY_LEN: usize>: Copy + Clone + Debug {
354    /// Segment index for each position in the key.
355    const SEGMENTS: [usize; KEY_LEN];
356}
357
358/// A `KeySchema` that does not reorder the keys.
359/// This is useful for keys that are already ordered in the desired way.
360/// This is the default ordering.
361#[derive(Copy, Clone, Debug)]
362pub struct IdentitySchema {}
363
364/// A `KeySegmentation` that does not segment the keys.
365/// This is useful for keys that do not have a segment structure.
366/// This is the default segmentation.
367#[derive(Copy, Clone, Debug)]
368pub struct SingleSegmentation {}
369impl<const KEY_LEN: usize> KeySchema<KEY_LEN> for IdentitySchema {
370    type Segmentation = SingleSegmentation;
371    const SEGMENT_PERM: &'static [usize] = &[0];
372    const KEY_TO_TREE: [usize; KEY_LEN] = identity_map::<KEY_LEN>();
373    const TREE_TO_KEY: [usize; KEY_LEN] = identity_map::<KEY_LEN>();
374}
375
376impl<const KEY_LEN: usize> KeySegmentation<KEY_LEN> for SingleSegmentation {
377    const SEGMENTS: [usize; KEY_LEN] = [0; KEY_LEN];
378}
379
380#[allow(dead_code)]
381#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
382#[repr(u8)]
383pub(crate) enum HeadTag {
384    // Stored in the low 4 bits of `Head::tptr` (see Head::new).
385    //
386    // Branch values encode log2(branch_size) (i.e. `Branch2 == 1`, `Branch256
387    // == 8`). `0` is reserved for leaf nodes, which lets us compute the branch
388    // size as `1 << tag` without any offset. The derived `Ord` therefore
389    // compares branch sizes — `tag_a > tag_b` ⟺ `size_a > size_b`, and the
390    // 2× swap threshold reduces to a single tag-byte compare.
391    Leaf = 0,
392    Branch2 = 1,
393    Branch4 = 2,
394    Branch8 = 3,
395    Branch16 = 4,
396    Branch32 = 5,
397    Branch64 = 6,
398    Branch128 = 7,
399    Branch256 = 8,
400}
401
402impl HeadTag {
403    #[inline]
404    fn from_raw(raw: u8) -> Self {
405        debug_assert!(raw <= HeadTag::Branch256 as u8);
406        // SAFETY: `HeadTag` is `#[repr(u8)]` with a contiguous discriminant
407        // range 0..=8. The tag bits are written by Head::new/set_body and
408        // Branch::tag, which only emit valid discriminants.
409        unsafe { std::mem::transmute(raw) }
410    }
411}
412
413pub(crate) enum BodyPtr<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
414    Leaf(NonNull<Leaf<KEY_LEN, V>>),
415    Branch(branch::BranchNN<KEY_LEN, O, V>),
416}
417
418/// Immutable borrow view of a Head body.
419/// Returned by `body_ref()` and tied to the lifetime of the `&Head`.
420pub(crate) enum BodyRef<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
421    Leaf(&'a Leaf<KEY_LEN, V>),
422    Branch(&'a Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V>>], V>),
423}
424
425/// Mutable borrow view of a Head body.
426/// Returned by `body_mut()` and tied to the lifetime of the `&mut Head`.
427pub(crate) enum BodyMut<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
428    Leaf(&'a mut Leaf<KEY_LEN, V>),
429    Branch(&'a mut Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V>>], V>),
430}
431
432pub(crate) trait Body {
433    fn tag(body: NonNull<Self>) -> HeadTag;
434}
435
436#[repr(C)]
437pub(crate) struct Head<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
438    tptr: std::ptr::NonNull<u8>,
439    key_ordering: PhantomData<O>,
440    key_segments: PhantomData<O::Segmentation>,
441    value: PhantomData<V>,
442}
443
444unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Send for Head<KEY_LEN, O, V> {}
445unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Sync for Head<KEY_LEN, O, V> {}
446
447impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Head<KEY_LEN, O, V> {
448    // Tagged pointer layout (64-bit only):
449    // - bits 0..=3:   HeadTag (requires 16-byte aligned bodies)
450    // - bits 4..=55:  body pointer bits (52 bits)
451    // - bits 56..=63: key byte for cuckoo table lookup
452    const TAG_MASK: u64 = 0x0f;
453    const BODY_MASK: u64 = 0x00_ff_ff_ff_ff_ff_ff_f0;
454    const KEY_MASK: u64 = 0xff_00_00_00_00_00_00_00;
455
456    pub(crate) fn new<T: Body + ?Sized>(key: u8, body: NonNull<T>) -> Self {
457        unsafe {
458            let tptr =
459                std::ptr::NonNull::new_unchecked((body.as_ptr() as *mut u8).map_addr(|addr| {
460                    debug_assert_eq!(addr as u64 & Self::TAG_MASK, 0);
461                    ((addr as u64 & Self::BODY_MASK)
462                        | ((key as u64) << 56)
463                        | (<T as Body>::tag(body) as u64)) as usize
464                }));
465            Self {
466                tptr,
467                key_ordering: PhantomData,
468                key_segments: PhantomData,
469                value: PhantomData,
470            }
471        }
472    }
473
474    #[inline]
475    pub(crate) fn tag(&self) -> HeadTag {
476        HeadTag::from_raw((self.tptr.as_ptr() as u64 & Self::TAG_MASK) as u8)
477    }
478
479    #[inline]
480    pub(crate) fn key(&self) -> u8 {
481        (self.tptr.as_ptr() as u64 >> 56) as u8
482    }
483
484    #[inline]
485    pub(crate) fn with_key(mut self, key: u8) -> Self {
486        self.tptr =
487            std::ptr::NonNull::new(self.tptr.as_ptr().map_addr(|addr| {
488                ((addr as u64 & !Self::KEY_MASK) | ((key as u64) << 56)) as usize
489            }))
490            .unwrap();
491        self
492    }
493
494    #[inline]
495    pub(crate) fn set_body<T: Body + ?Sized>(&mut self, body: NonNull<T>) {
496        unsafe {
497            self.tptr = NonNull::new_unchecked((body.as_ptr() as *mut u8).map_addr(|addr| {
498                debug_assert_eq!(addr as u64 & Self::TAG_MASK, 0);
499                ((addr as u64 & Self::BODY_MASK)
500                    | (self.tptr.as_ptr() as u64 & Self::KEY_MASK)
501                    | (<T as Body>::tag(body) as u64)) as usize
502            }))
503        }
504    }
505
506    pub(crate) fn with_start(self, new_start_depth: usize) -> Head<KEY_LEN, O, V> {
507        let leaf_key = self.childleaf_key();
508        let i = O::TREE_TO_KEY[new_start_depth];
509        let key = leaf_key[i];
510        self.with_key(key)
511    }
512
513    // Removed childleaf_matches_key_from in favor of composing the existing
514    // has_prefix primitives directly at call sites. Use
515    // `self.has_prefix::<KEY_LEN>(at_depth, key)` or for partial checks
516    // `self.childleaf().has_prefix::<O>(at_depth, &key[..limit])` instead.
517
518    pub(crate) fn body(&self) -> BodyPtr<KEY_LEN, O, V> {
519        unsafe {
520            let ptr = NonNull::new_unchecked(self.tptr.as_ptr().map_addr(|addr| {
521                let masked = (addr as u64) & Self::BODY_MASK;
522                masked as usize
523            }));
524            match self.tag() {
525                HeadTag::Leaf => BodyPtr::Leaf(ptr.cast()),
526                branch_tag => {
527                    let count = 1 << (branch_tag as usize);
528                    BodyPtr::Branch(NonNull::new_unchecked(std::ptr::slice_from_raw_parts(
529                        ptr.as_ptr(),
530                        count,
531                    )
532                        as *mut Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V>>], V>))
533                }
534            }
535        }
536    }
537
538    pub(crate) fn body_mut(&mut self) -> BodyMut<'_, KEY_LEN, O, V> {
539        unsafe {
540            match self.body() {
541                BodyPtr::Leaf(mut leaf) => BodyMut::Leaf(leaf.as_mut()),
542                BodyPtr::Branch(mut branch) => {
543                    // Ensure ownership: try copy-on-write and update local pointer if needed.
544                    let mut branch_nn = branch;
545                    if Branch::rc_cow(&mut branch_nn).is_some() {
546                        self.set_body(branch_nn);
547                        BodyMut::Branch(branch_nn.as_mut())
548                    } else {
549                        BodyMut::Branch(branch.as_mut())
550                    }
551                }
552            }
553        }
554    }
555
556    /// Returns an immutable borrow of the body (Leaf or Branch) tied to &self.
557    pub(crate) fn body_ref(&self) -> BodyRef<'_, KEY_LEN, O, V> {
558        match self.body() {
559            BodyPtr::Leaf(nn) => BodyRef::Leaf(unsafe { nn.as_ref() }),
560            BodyPtr::Branch(nn) => BodyRef::Branch(unsafe { nn.as_ref() }),
561        }
562    }
563
564    pub(crate) fn count(&self) -> u64 {
565        match self.body_ref() {
566            BodyRef::Leaf(_) => 1,
567            BodyRef::Branch(branch) => branch.leaf_count,
568        }
569    }
570
571    pub(crate) fn count_segment(&self, at_depth: usize) -> u64 {
572        match self.body_ref() {
573            BodyRef::Leaf(_) => 1,
574            BodyRef::Branch(branch) => branch.count_segment(at_depth),
575        }
576    }
577
578    pub(crate) fn hash(&self) -> u128 {
579        match self.body_ref() {
580            BodyRef::Leaf(leaf) => leaf.hash,
581            BodyRef::Branch(branch) => branch.hash,
582        }
583    }
584
585    pub(crate) fn end_depth(&self) -> usize {
586        match self.body_ref() {
587            BodyRef::Leaf(_) => KEY_LEN,
588            BodyRef::Branch(branch) => branch.end_depth as usize,
589        }
590    }
591
592    /// Return the raw pointer to the child leaf for use in low-level
593    /// operations (for example when constructing a Branch). Prefer
594    /// `childleaf_key()` or other safe accessors when you only need the
595    /// key or value; those avoid unsafe dereferences.
596    pub(crate) fn childleaf_ptr(&self) -> *const Leaf<KEY_LEN, V> {
597        match self.body_ref() {
598            BodyRef::Leaf(leaf) => leaf as *const Leaf<KEY_LEN, V>,
599            BodyRef::Branch(branch) => branch.childleaf_ptr(),
600        }
601    }
602
603    pub(crate) fn childleaf_key(&self) -> &[u8; KEY_LEN] {
604        match self.body_ref() {
605            BodyRef::Leaf(leaf) => &leaf.key,
606            BodyRef::Branch(branch) => &branch.childleaf().key,
607        }
608    }
609
610    // Slot wrapper defined at module level (moved to below the impl block)
611
612    /// Find the first depth in [start_depth, limit) where the tree-ordered
613    /// bytes of `self` and `other` differ. The comparison limit is computed
614    /// as min(self.end_depth(), other.end_depth(), KEY_LEN) which is the
615    /// natural bound for comparing two heads. Returns `Some((depth, a, b))`
616    /// where `a` and `b` are the differing bytes at that depth, or `None`
617    /// if no divergence is found in the range.
618    pub(crate) fn first_divergence(
619        &self,
620        other: &Self,
621        start_depth: usize,
622    ) -> Option<(usize, u8, u8)> {
623        let limit = std::cmp::min(std::cmp::min(self.end_depth(), other.end_depth()), KEY_LEN);
624        debug_assert!(limit <= KEY_LEN);
625        let this_key = self.childleaf_key();
626        let other_key = other.childleaf_key();
627        let mut depth = start_depth;
628        while depth < limit {
629            let i = O::TREE_TO_KEY[depth];
630            let a = this_key[i];
631            let b = other_key[i];
632            if a != b {
633                return Some((depth, a, b));
634            }
635            depth += 1;
636        }
637        None
638    }
639
640    // Mutable access to the child slots for this head. If the head is a
641    // branch, returns a mutable slice referencing the underlying child table
642    // (each element is Option<Head>). If the head is a leaf an empty slice
643    // is returned.
644    //
645    // The caller receives a &mut slice tied to the borrow of `self` and may
646    // reorder entries in-place (e.g., sort_unstable) and then take them using
647    // `Option::take()` to extract Head values. The call uses `body_mut()` so
648    // COW semantics are preserved and callers have exclusive access to the
649    // branch storage while the mutable borrow lasts.
650    // NOTE: mut_children removed — prefer matching on BodyRef returned by
651    // `body_mut()` and operating directly on the `&mut Branch` reference.
652
653    pub(crate) fn remove_leaf(
654        slot: &mut Option<Self>,
655        leaf_key: &[u8; KEY_LEN],
656        start_depth: usize,
657    ) {
658        if let Some(this) = slot {
659            let end_depth = std::cmp::min(this.end_depth(), KEY_LEN);
660            // Check reachable equality by asking the head to test the prefix
661            // up to its end_depth. Using the head/leaf primitive centralises the
662            // unsafe deref into Branch::childleaf()/Leaf::has_prefix.
663            if !this.has_prefix::<KEY_LEN>(start_depth, leaf_key) {
664                return;
665            }
666            if this.tag() == HeadTag::Leaf {
667                slot.take();
668            } else {
669                let mut ed = crate::patch::branch::BranchMut::from_head(this);
670                let key = leaf_key[end_depth];
671                ed.modify_child(key, |mut opt| {
672                    Self::remove_leaf(&mut opt, leaf_key, end_depth);
673                    opt
674                });
675
676                // If the branch now contains a single remaining child we
677                // collapse the branch upward into that child. We must pull
678                // the remaining child out while `ed` is still borrowed,
679                // then drop `ed` before writing back into `slot` to avoid
680                // double mutable borrows of the slot.
681                if ed.leaf_count == 1 {
682                    let mut remaining: Option<Head<KEY_LEN, O, V>> = None;
683                    for slot_child in &mut ed.child_table {
684                        if let Some(child) = slot_child.take() {
685                            remaining = Some(child.with_start(start_depth));
686                            break;
687                        }
688                    }
689                    drop(ed);
690                    if let Some(child) = remaining {
691                        slot.replace(child);
692                    }
693                } else {
694                    // ensure we drop the editor when not collapsing so the
695                    // final pointer is committed back into the head.
696                    drop(ed);
697                }
698            }
699        }
700    }
701
702    // NOTE: slot-level wrappers removed; callers should take the slot and call
703    // the owned helpers (insert_leaf / replace_leaf / union)
704    // directly. This reduces the indirection and keeps ownership semantics
705    // explicit at the call site.
706
707    // Owned variants of the slot-based helpers. These accept the existing
708    // Head by value and return the new Head after performing the
709    // modification. They are used with the split `insert_child` /
710    // `update_child` APIs so we no longer need `Branch::upsert_child`.
711    pub(crate) fn insert_leaf(mut this: Self, leaf: Self, start_depth: usize) -> Self {
712        if let Some((depth, this_byte_key, leaf_byte_key)) =
713            this.first_divergence(&leaf, start_depth)
714        {
715            let old_key = this.key();
716            let new_body = Branch::new(
717                depth,
718                this.with_key(this_byte_key),
719                leaf.with_key(leaf_byte_key),
720            );
721            return Head::new(old_key, new_body);
722        }
723
724        let end_depth = this.end_depth();
725        if end_depth != KEY_LEN {
726            // Use the editable BranchMut view to perform mutations without
727            // exposing pointer juggling at the call site.
728            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
729            let inserted = leaf.with_start(ed.end_depth as usize);
730            let key = inserted.key();
731            ed.modify_child(key, |opt| match opt {
732                Some(old) => Some(Head::insert_leaf(old, inserted, end_depth)),
733                None => Some(inserted),
734            });
735        }
736        this
737    }
738
739    pub(crate) fn replace_leaf(mut this: Self, leaf: Self, start_depth: usize) -> Self {
740        if let Some((depth, this_byte_key, leaf_byte_key)) =
741            this.first_divergence(&leaf, start_depth)
742        {
743            let old_key = this.key();
744            let new_body = Branch::new(
745                depth,
746                this.with_key(this_byte_key),
747                leaf.with_key(leaf_byte_key),
748            );
749
750            return Head::new(old_key, new_body);
751        }
752
753        let end_depth = this.end_depth();
754        if end_depth == KEY_LEN {
755            let old_key = this.key();
756            return leaf.with_key(old_key);
757        } else {
758            // Use the editor view for branch mutation instead of raw pointer ops.
759            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
760            let inserted = leaf.with_start(ed.end_depth as usize);
761            let key = inserted.key();
762            ed.modify_child(key, |opt| match opt {
763                Some(old) => Some(Head::replace_leaf(old, inserted, end_depth)),
764                None => Some(inserted),
765            });
766        }
767        this
768    }
769
770    /// Sequential PATCH-trie union. Always serial; the parallel
771    /// dispatch lives in [`Self::par_union`] which calls back into
772    /// `union` once budget is exhausted.
773    pub(crate) fn union(mut this: Self, mut other: Self, at_depth: usize) -> Self {
774        if this.hash() == other.hash() {
775            return this;
776        }
777
778        if let Some((depth, this_byte_key, other_byte_key)) =
779            this.first_divergence(&other, at_depth)
780        {
781            let old_key = this.key();
782            let new_body = Branch::new(
783                depth,
784                this.with_key(this_byte_key),
785                other.with_key(other_byte_key),
786            );
787
788            return Head::new(old_key, new_body);
789        }
790
791        let this_depth = this.end_depth();
792        let other_depth = other.end_depth();
793        if this_depth < other_depth {
794            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
795            let inserted = other.with_start(ed.end_depth as usize);
796            let key = inserted.key();
797            ed.modify_child(key, |opt| match opt {
798                Some(old) => Some(Head::union(old, inserted, this_depth)),
799                None => Some(inserted),
800            });
801            drop(ed);
802            return this;
803        }
804
805        if other_depth < this_depth {
806            let old_key = this.key();
807            let this_head = this;
808            let mut ed = crate::patch::branch::BranchMut::from_head(&mut other);
809            let inserted = this_head.with_start(ed.end_depth as usize);
810            let key = inserted.key();
811            ed.modify_child(key, |opt| match opt {
812                Some(old) => Some(Head::union(old, inserted, other_depth)),
813                None => Some(inserted),
814            });
815            drop(ed);
816            return other.with_key(old_key);
817        }
818
819        // Equal depth, hashes differ → walk `other`'s children,
820        // resolving collisions via recursive `Head::union` and the
821        // `modify_child`'s per-call accounting.
822        //
823        // Union is commutative; mutating either side in place is
824        // semantically equivalent. Swap when `other`'s child_table
825        // is at least 2× larger than `this`'s — start with the
826        // bigger capacity so cuckoo grows are mostly avoided during
827        // insert. Branch tags encode `log2(child_table_size)`, so
828        // the 2× ratio reduces to `other_tag > this_tag` (no body
829        // deref needed; the tag bits live in the head's pointer).
830        if other.tag() > this.tag() {
831            std::mem::swap(&mut this, &mut other);
832        }
833        let BodyMut::Branch(other_branch_ref) = other.body_mut() else {
834            unreachable!();
835        };
836        let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
837        for other_child in other_branch_ref
838            .child_table
839            .iter_mut()
840            .filter_map(Option::take)
841        {
842            let inserted = other_child.with_start(ed.end_depth as usize);
843            let key = inserted.key();
844            ed.modify_child(key, |opt| match opt {
845                Some(old) => Some(Head::union(old, inserted, this_depth)),
846                None => Some(inserted),
847            });
848        }
849        drop(ed);
850        this
851    }
852
853    /// Parallel-aware top-level union entry. Allocates a fresh
854    /// [`parallel_union::ParUnionCtx`] with a budget of
855    /// `num_threads²` shared spawns, then delegates to
856    /// [`Self::par_union_with_ctx`]. The budget persists across the
857    /// entire recursive descent — once exhausted, the rest is
858    /// sequential.
859    #[cfg(feature = "parallel")]
860    pub(crate) fn par_union(this: Self, other: Self, at_depth: usize) -> Self
861    where
862        O: Send + Sync,
863        V: Send + Sync,
864    {
865        let ctx = parallel_union::ParUnionCtx::new();
866        Self::par_union_with_ctx(this, other, at_depth, &ctx)
867    }
868
869    /// Recursive parallel-aware union: at the equal-depth-branch
870    /// arm, drains the "both" pairs and, for each pair, either
871    /// claims a budget unit and spawns a parallel task or falls
872    /// back to serial `Self::union`. All other arms (hash-equal,
873    /// divergence, asymmetric depth) delegate to `Self::union` —
874    /// they don't generate fan-out work for the budget to spend.
875    #[cfg(feature = "parallel")]
876    pub(crate) fn par_union_with_ctx(
877        mut this: Self,
878        mut other: Self,
879        at_depth: usize,
880        ctx: &parallel_union::ParUnionCtx,
881    ) -> Self
882    where
883        O: Send + Sync,
884        V: Send + Sync,
885    {
886        if this.hash() == other.hash() {
887            return this;
888        }
889
890        if let Some((depth, this_byte_key, other_byte_key)) =
891            this.first_divergence(&other, at_depth)
892        {
893            let old_key = this.key();
894            let new_body = Branch::new(
895                depth,
896                this.with_key(this_byte_key),
897                other.with_key(other_byte_key),
898            );
899            return Head::new(old_key, new_body);
900        }
901
902        let this_depth = this.end_depth();
903        let other_depth = other.end_depth();
904        if this_depth != other_depth {
905            // Asymmetric — no fan-out opportunity, serial path wins.
906            return Self::union(this, other, at_depth);
907        }
908
909        // Equal depth, hashes differ → branch merge. Swap when
910        // `other`'s child_table is ≥2× `this`'s so the in-place
911        // target starts with the bigger capacity (fewer cuckoo
912        // grows when scattering children back via
913        // `install_child_growing`). Branch tags encode
914        // `log2(child_table_size)`, so the 2× ratio reduces to
915        // `other_tag > this_tag` — single byte compare from the
916        // head pointer, no body deref / CoW risk.
917        if other.tag() > this.tag() {
918            std::mem::swap(&mut this, &mut other);
919        }
920
921        // Threshold check via `body_ref` (no CoW); fall back to
922        // serial when the source side is too small to amortise the
923        // scatter machinery.
924        let small = match other.body_ref() {
925            BodyRef::Branch(b) => (b.leaf_count as usize) < PARALLEL_PATCH_UNION_THRESHOLD,
926            BodyRef::Leaf(_) => unreachable!(),
927        };
928        if small {
929            return Self::union(this, other, at_depth);
930        }
931
932        let BodyMut::Branch(other_branch_ref) = other.body_mut() else {
933            unreachable!();
934        };
935
936        {
937            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
938            let end_depth = ed.end_depth as usize;
939
940            // Scatter both child tables into key-indexed 256-slot
941            // arrays + present bitsets. The bitset partition tells us
942            // which keys need a recursive union ("both") vs which are
943            // simple pass-throughs ("only").
944            let mut this_arr: [Option<Head<KEY_LEN, O, V>>; 256] =
945                std::array::from_fn(|_| None);
946            let mut other_arr: [Option<Head<KEY_LEN, O, V>>; 256] =
947                std::array::from_fn(|_| None);
948            let mut this_present = crate::patch::bytetable::ByteSet::new_empty();
949            let mut other_present = crate::patch::bytetable::ByteSet::new_empty();
950
951            for slot in ed.child_table.iter_mut() {
952                if let Some(head) = slot.take() {
953                    let key = head.key();
954                    this_present.insert(key);
955                    this_arr[key as usize] = Some(head);
956                }
957            }
958            for slot in other_branch_ref.child_table.iter_mut() {
959                if let Some(head) = slot.take() {
960                    let head = head.with_start(end_depth);
961                    let key = head.key();
962                    other_present.insert(key);
963                    other_arr[key as usize] = Some(head);
964                }
965            }
966
967            let mut both = this_present.intersect(&other_present);
968            let mut only = this_present.symmetric_difference(&other_present);
969
970            // Pre-allocated scatter-write target. Each spawned task
971            // writes to `resolved[k]` for its specific key byte —
972            // disjoint by construction. The raw pointer wrapper
973            // (`ScatterPtr`) makes the cross-thread sharing explicit.
974            let mut resolved: [Option<Head<KEY_LEN, O, V>>; 256] =
975                std::array::from_fn(|_| None);
976            let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
977
978            rayon::scope(|s| {
979                // Drain `both` pairs serially in the parent; per
980                // pair, either claim a spawn unit and dispatch as a
981                // task, or run serially via `Head::union` here on
982                // the parent thread. The atomic budget is shared
983                // with all nested `par_union_with_ctx` calls.
984                while let Some(k) = both.drain_next_ascending() {
985                    let i = k as usize;
986                    let t = this_arr[i].take().expect("both ⇒ this");
987                    let o = other_arr[i].take().expect("both ⇒ other");
988                    if ctx.try_claim() {
989                        s.spawn(move |_| {
990                            let head = Self::par_union_with_ctx(t, o, this_depth, ctx);
991                            // SAFETY: each task has a distinct
992                            // key `k`, so the writes to
993                            // `resolved[i]` are non-aliasing.
994                            unsafe {
995                                resolved_ptr.write_at(i, Some(head));
996                            }
997                        });
998                    } else {
999                        // Budget exhausted — fall back to fully
1000                        // serial union on this pair, then scatter
1001                        // the result. SAFETY: same disjointness
1002                        // invariant; the parent thread races only
1003                        // with tasks targeting distinct keys.
1004                        let head = Self::union(t, o, this_depth);
1005                        unsafe {
1006                            resolved_ptr.write_at(i, Some(head));
1007                        }
1008                    }
1009                }
1010            });
1011            // After scope: all spawned tasks have completed; the
1012            // scatter writes to `resolved` are all sequenced-before
1013            // here by rayon's join semantics.
1014
1015            for slot in resolved.iter_mut() {
1016                if let Some(head) = slot.take() {
1017                    ed.install_child_growing(head);
1018                }
1019            }
1020            while let Some(k) = only.drain_next_ascending() {
1021                let i = k as usize;
1022                let head = this_arr[i]
1023                    .take()
1024                    .or_else(|| other_arr[i].take())
1025                    .expect("only ⇒ exactly one side");
1026                ed.install_child_growing(head);
1027            }
1028
1029            ed.recompute_aggregates();
1030        }
1031        this
1032    }
1033
1034    /// Parallel-aware top-level intersect entry. Allocates a fresh
1035    /// [`parallel_union::ParUnionCtx`] (shared budget across the
1036    /// descent) and delegates to [`Self::par_intersect_with_ctx`].
1037    /// Intersect builds a fresh tree, so there is no in-place
1038    /// target — the parallel work is purely "compute per-pair
1039    /// intersections in parallel, then collect into a new Branch."
1040    #[cfg(feature = "parallel")]
1041    pub(crate) fn par_intersect(&self, other: &Self, at_depth: usize) -> Option<Self>
1042    where
1043        O: Send + Sync,
1044        V: Send + Sync,
1045    {
1046        let ctx = parallel_union::ParUnionCtx::new();
1047        self.par_intersect_with_ctx(other, at_depth, &ctx)
1048    }
1049
1050    /// Recursive parallel-aware intersect. At the equal-depth-branch
1051    /// arm, scatter-spawns one task per matching `(self_child,
1052    /// other_child)` pair (under budget), then collects results
1053    /// into a fresh `Branch`. Hash-equal / divergence / asymmetric-
1054    /// depth arms delegate to serial [`Self::intersect`] — they
1055    /// don't generate fan-out work.
1056    #[cfg(feature = "parallel")]
1057    pub(crate) fn par_intersect_with_ctx(
1058        &self,
1059        other: &Self,
1060        at_depth: usize,
1061        ctx: &parallel_union::ParUnionCtx,
1062    ) -> Option<Self>
1063    where
1064        O: Send + Sync,
1065        V: Send + Sync,
1066    {
1067        if self.hash() == other.hash() {
1068            return Some(self.clone());
1069        }
1070        if self.first_divergence(other, at_depth).is_some() {
1071            return None;
1072        }
1073        let self_depth = self.end_depth();
1074        let other_depth = other.end_depth();
1075        if self_depth != other_depth {
1076            return self.intersect(other, at_depth);
1077        }
1078
1079        let BodyRef::Branch(self_branch) = self.body_ref() else {
1080            unreachable!();
1081        };
1082        let BodyRef::Branch(other_branch) = other.body_ref() else {
1083            unreachable!();
1084        };
1085
1086        // Intersect work is bounded by the smaller side — pairs only
1087        // exist where keys appear in both branches.
1088        let min_leaves = self_branch.leaf_count.min(other_branch.leaf_count) as usize;
1089        if min_leaves < PARALLEL_PATCH_UNION_THRESHOLD {
1090            return self.intersect(other, at_depth);
1091        }
1092
1093        let mut resolved: [Option<Head<KEY_LEN, O, V>>; 256] =
1094            std::array::from_fn(|_| None);
1095        let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
1096
1097        // `in_place_scope` runs the outer closure on the calling
1098        // thread (no `Send` bound), which lets us hold `&Branch`
1099        // borrows across the spawn loop. `Branch` is `!Sync` due
1100        // to its raw `*const Leaf` pointer field, so a regular
1101        // `rayon::scope` would reject the captures.
1102        rayon::in_place_scope(|s| {
1103            for slot in self_branch.child_table.iter() {
1104                let Some(self_child) = slot.as_ref() else {
1105                    continue;
1106                };
1107                let key = self_child.key();
1108                let Some(other_child) = other_branch.child_table.table_get(key) else {
1109                    continue;
1110                };
1111
1112                if ctx.try_claim() {
1113                    s.spawn(move |_| {
1114                        let result =
1115                            self_child.par_intersect_with_ctx(other_child, self_depth, ctx);
1116                        // SAFETY: distinct keys → disjoint slots.
1117                        unsafe {
1118                            resolved_ptr.write_at(key as usize, result);
1119                        }
1120                    });
1121                } else {
1122                    let result = self_child.intersect(other_child, self_depth);
1123                    unsafe {
1124                        resolved_ptr.write_at(key as usize, result);
1125                    }
1126                }
1127            }
1128        });
1129
1130        // Collect non-None results into a fresh Branch. Stick with
1131        // per-key `modify_child` here — intersect's collection
1132        // phase typically has FEW children (heavy filtering kept
1133        // only the matching subset), so the per-call aggregate
1134        // updates beat the fixed `recompute_aggregates` cost. Bench
1135        // sanity-checked: install+recompute regressed intersect
1136        // +18% on the 4M/50%-overlap dataset.
1137        let mut iter = resolved.into_iter().flatten();
1138        let first = iter.next()?;
1139        let Some(second) = iter.next() else {
1140            return Some(first);
1141        };
1142        let new_branch = Branch::new(
1143            self_depth,
1144            first.with_start(self_depth),
1145            second.with_start(self_depth),
1146        );
1147        let mut head_for_branch = Head::new(0, new_branch);
1148        {
1149            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
1150            for child in iter {
1151                let inserted = child.with_start(self_depth);
1152                let k = inserted.key();
1153                ed.modify_child(k, |_opt| Some(inserted));
1154            }
1155        }
1156        Some(head_for_branch)
1157    }
1158
1159    /// Parallel-aware top-level difference entry. Allocates a fresh
1160    /// [`parallel_union::ParUnionCtx`] and delegates to
1161    /// [`Self::par_difference_with_ctx`].
1162    #[cfg(feature = "parallel")]
1163    pub(crate) fn par_difference(&self, other: &Self, at_depth: usize) -> Option<Self>
1164    where
1165        O: Send + Sync,
1166        V: Send + Sync,
1167    {
1168        let ctx = parallel_union::ParUnionCtx::new();
1169        self.par_difference_with_ctx(other, at_depth, &ctx)
1170    }
1171
1172    /// Recursive parallel-aware difference. Same scatter-and-spawn
1173    /// shape as `par_intersect_with_ctx`, plus the "no match in
1174    /// other" branch where we clone `self_child` unchanged into
1175    /// the resolved array (no recursive work).
1176    #[cfg(feature = "parallel")]
1177    pub(crate) fn par_difference_with_ctx(
1178        &self,
1179        other: &Self,
1180        at_depth: usize,
1181        ctx: &parallel_union::ParUnionCtx,
1182    ) -> Option<Self>
1183    where
1184        O: Send + Sync,
1185        V: Send + Sync,
1186    {
1187        if self.hash() == other.hash() {
1188            return None;
1189        }
1190        if self.first_divergence(other, at_depth).is_some() {
1191            return Some(self.clone());
1192        }
1193        let self_depth = self.end_depth();
1194        let other_depth = other.end_depth();
1195        if self_depth != other_depth {
1196            return self.difference(other, at_depth);
1197        }
1198
1199        let BodyRef::Branch(self_branch) = self.body_ref() else {
1200            unreachable!();
1201        };
1202        let BodyRef::Branch(other_branch) = other.body_ref() else {
1203            unreachable!();
1204        };
1205
1206        // Difference work is bounded by `self` (every key in self is
1207        // either kept or filtered against other).
1208        if (self_branch.leaf_count as usize) < PARALLEL_PATCH_UNION_THRESHOLD {
1209            return self.difference(other, at_depth);
1210        }
1211
1212        let mut resolved: [Option<Head<KEY_LEN, O, V>>; 256] =
1213            std::array::from_fn(|_| None);
1214        let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
1215
1216        // See `par_intersect_with_ctx` for why this is
1217        // `in_place_scope` rather than `scope`.
1218        rayon::in_place_scope(|s| {
1219            for slot in self_branch.child_table.iter() {
1220                let Some(self_child) = slot.as_ref() else {
1221                    continue;
1222                };
1223                let key = self_child.key();
1224
1225                match other_branch.child_table.table_get(key) {
1226                    Some(other_child) => {
1227                        if ctx.try_claim() {
1228                            s.spawn(move |_| {
1229                                let result = self_child.par_difference_with_ctx(
1230                                    other_child,
1231                                    self_depth,
1232                                    ctx,
1233                                );
1234                                unsafe {
1235                                    resolved_ptr.write_at(key as usize, result);
1236                                }
1237                            });
1238                        } else {
1239                            let result = self_child.difference(other_child, self_depth);
1240                            unsafe {
1241                                resolved_ptr.write_at(key as usize, result);
1242                            }
1243                        }
1244                    }
1245                    None => {
1246                        // No match in other ⇒ keep `self_child`
1247                        // unchanged. Clone is cheap (Arc-style rc
1248                        // bump on Branch, leaf is small).
1249                        let cloned = self_child.clone();
1250                        unsafe {
1251                            resolved_ptr.write_at(key as usize, Some(cloned));
1252                        }
1253                    }
1254                }
1255            }
1256        });
1257
1258        // Collect non-None results into a fresh Branch. Difference's
1259        // collection phase typically has MANY children (most keys
1260        // in `self` survive — only matching+empty subtrees get
1261        // filtered), so `install_child_growing` + one
1262        // `recompute_aggregates` pass wins handily over per-call
1263        // `modify_child`. Mirror of the union pattern; intersect
1264        // uses `modify_child` because its collection phase has
1265        // far fewer children (heavy filtering).
1266        let mut iter = resolved.into_iter().flatten();
1267        let first = iter.next()?;
1268        let Some(second) = iter.next() else {
1269            return Some(first);
1270        };
1271        let new_branch = Branch::new(
1272            self_depth,
1273            first.with_start(self_depth),
1274            second.with_start(self_depth),
1275        );
1276        let mut head_for_branch = Head::new(0, new_branch);
1277        {
1278            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
1279            for child in iter {
1280                ed.install_child_growing(child.with_start(self_depth));
1281            }
1282            ed.recompute_aggregates();
1283        }
1284        Some(head_for_branch)
1285    }
1286
1287    pub(crate) fn infixes<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
1288        &self,
1289        prefix: &[u8; PREFIX_LEN],
1290        at_depth: usize,
1291        f: &mut F,
1292    ) where
1293        F: FnMut(&[u8; INFIX_LEN]),
1294    {
1295        match self.body_ref() {
1296            BodyRef::Leaf(leaf) => leaf.infixes::<PREFIX_LEN, INFIX_LEN, O, F>(prefix, at_depth, f),
1297            BodyRef::Branch(branch) => {
1298                branch.infixes::<PREFIX_LEN, INFIX_LEN, F>(prefix, at_depth, f)
1299            }
1300        }
1301    }
1302
1303    pub(crate) fn infixes_range<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
1304        &self,
1305        prefix: &[u8; PREFIX_LEN],
1306        at_depth: usize,
1307        min_infix: &[u8; INFIX_LEN],
1308        max_infix: &[u8; INFIX_LEN],
1309        f: &mut F,
1310    ) where
1311        F: FnMut(&[u8; INFIX_LEN]),
1312    {
1313        match self.body_ref() {
1314            BodyRef::Leaf(leaf) => leaf.infixes_range::<PREFIX_LEN, INFIX_LEN, O, F>(
1315                prefix, at_depth, min_infix, max_infix, f,
1316            ),
1317            BodyRef::Branch(branch) => branch.infixes_range::<PREFIX_LEN, INFIX_LEN, F>(
1318                prefix, at_depth, min_infix, max_infix, f,
1319            ),
1320        }
1321    }
1322
1323    pub(crate) fn count_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
1324        &self,
1325        prefix: &[u8; PREFIX_LEN],
1326        at_depth: usize,
1327        min_infix: &[u8; INFIX_LEN],
1328        max_infix: &[u8; INFIX_LEN],
1329    ) -> u64 {
1330        match self.body_ref() {
1331            BodyRef::Leaf(leaf) => {
1332                leaf.count_range::<PREFIX_LEN, INFIX_LEN, O>(prefix, at_depth, min_infix, max_infix)
1333            }
1334            BodyRef::Branch(branch) => {
1335                branch.count_range::<PREFIX_LEN, INFIX_LEN>(prefix, at_depth, min_infix, max_infix)
1336            }
1337        }
1338    }
1339
1340    pub(crate) fn has_prefix<const PREFIX_LEN: usize>(
1341        &self,
1342        at_depth: usize,
1343        prefix: &[u8; PREFIX_LEN],
1344    ) -> bool {
1345        const {
1346            assert!(PREFIX_LEN <= KEY_LEN);
1347        }
1348        match self.body_ref() {
1349            BodyRef::Leaf(leaf) => leaf.has_prefix::<O>(at_depth, prefix),
1350            BodyRef::Branch(branch) => branch.has_prefix::<PREFIX_LEN>(at_depth, prefix),
1351        }
1352    }
1353
1354    pub(crate) fn get<'a>(&'a self, at_depth: usize, key: &[u8; KEY_LEN]) -> Option<&'a V>
1355    where
1356        O: 'a,
1357    {
1358        match self.body_ref() {
1359            BodyRef::Leaf(leaf) => leaf.get::<O>(at_depth, key),
1360            BodyRef::Branch(branch) => branch.get(at_depth, key),
1361        }
1362    }
1363
1364    pub(crate) fn segmented_len<const PREFIX_LEN: usize>(
1365        &self,
1366        at_depth: usize,
1367        prefix: &[u8; PREFIX_LEN],
1368    ) -> u64 {
1369        match self.body_ref() {
1370            BodyRef::Leaf(leaf) => leaf.segmented_len::<O, PREFIX_LEN>(at_depth, prefix),
1371            BodyRef::Branch(branch) => branch.segmented_len::<PREFIX_LEN>(at_depth, prefix),
1372        }
1373    }
1374
1375    // NOTE: slot-level union wrapper removed; callers should take the slot and
1376    // call the owned helper `union` directly.
1377
1378    pub(crate) fn intersect(&self, other: &Self, at_depth: usize) -> Option<Self> {
1379        if self.hash() == other.hash() {
1380            return Some(self.clone());
1381        }
1382
1383        if self.first_divergence(other, at_depth).is_some() {
1384            return None;
1385        }
1386
1387        let self_depth = self.end_depth();
1388        let other_depth = other.end_depth();
1389        if self_depth < other_depth {
1390            // This means that there can be at most one child in self
1391            // that might intersect with other.
1392            let BodyRef::Branch(branch) = self.body_ref() else {
1393                unreachable!();
1394            };
1395            return branch
1396                .child_table
1397                .table_get(other.childleaf_key()[O::TREE_TO_KEY[self_depth]])
1398                .and_then(|self_child| other.intersect(self_child, self_depth));
1399        }
1400
1401        if other_depth < self_depth {
1402            // This means that there can be at most one child in other
1403            // that might intersect with self.
1404            // If the depth of other is less than the depth of self, then it can't be a leaf.
1405            let BodyRef::Branch(other_branch) = other.body_ref() else {
1406                unreachable!();
1407            };
1408            return other_branch
1409                .child_table
1410                .table_get(self.childleaf_key()[O::TREE_TO_KEY[other_depth]])
1411                .and_then(|other_child| self.intersect(other_child, other_depth));
1412        }
1413
1414        // If we reached this point then the depths are equal. The only way to have a leaf
1415        // is if the other is a leaf as well, which is already handled by the hash check if they are equal,
1416        // and by the key check if they are not equal.
1417        // If one of them is a leaf and the other is a branch, then they would also have different depths,
1418        // which is already handled by the above code.
1419        let BodyRef::Branch(self_branch) = self.body_ref() else {
1420            unreachable!();
1421        };
1422        let BodyRef::Branch(other_branch) = other.body_ref() else {
1423            unreachable!();
1424        };
1425
1426        let mut intersected_children = self_branch
1427            .child_table
1428            .iter()
1429            .filter_map(Option::as_ref)
1430            .filter_map(|self_child| {
1431                let other_child = other_branch.child_table.table_get(self_child.key())?;
1432                self_child.intersect(other_child, self_depth)
1433            });
1434        let first_child = intersected_children.next()?;
1435        let Some(second_child) = intersected_children.next() else {
1436            return Some(first_child);
1437        };
1438        let new_branch = Branch::new(
1439            self_depth,
1440            first_child.with_start(self_depth),
1441            second_child.with_start(self_depth),
1442        );
1443        // Use a BranchMut editor to perform all child insertions via the
1444        // safe editor API instead of manipulating the NonNull pointer
1445        // directly. The editor will perform COW and commit the final
1446        // pointer into the Head when it is dropped.
1447        let mut head_for_branch = Head::new(0, new_branch);
1448        {
1449            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
1450            for child in intersected_children {
1451                let inserted = child.with_start(self_depth);
1452                let k = inserted.key();
1453                ed.modify_child(k, |_opt| Some(inserted));
1454            }
1455            // ed dropped here commits the final branch pointer into head_for_branch
1456        }
1457        Some(head_for_branch)
1458    }
1459
1460    /// Returns the difference between self and other.
1461    /// This is the set of elements that are in self but not in other.
1462    /// If the difference is empty, None is returned.
1463    pub(crate) fn difference(&self, other: &Self, at_depth: usize) -> Option<Self> {
1464        if self.hash() == other.hash() {
1465            return None;
1466        }
1467
1468        if self.first_divergence(other, at_depth).is_some() {
1469            return Some(self.clone());
1470        }
1471
1472        let self_depth = self.end_depth();
1473        let other_depth = other.end_depth();
1474        if self_depth < other_depth {
1475            // This means that there can be at most one child in self
1476            // that might intersect with other. It's the only child that may not be in the difference.
1477            // The other children are definitely in the difference, as they have no corresponding byte in other.
1478            // Thus the cheapest way to compute the difference is compute the difference of the only child
1479            // that might intersect with other, copy self with it's correctly filled byte table, then
1480            // remove the old child, and insert the new child.
1481            let mut new_branch = self.clone();
1482            let other_byte_key = other.childleaf_key()[O::TREE_TO_KEY[self_depth]];
1483            {
1484                let mut ed = crate::patch::branch::BranchMut::from_head(&mut new_branch);
1485                ed.modify_child(other_byte_key, |opt| {
1486                    opt.and_then(|child| child.difference(other, self_depth))
1487                });
1488            }
1489            return Some(new_branch);
1490        }
1491
1492        if other_depth < self_depth {
1493            // This means that we need to check if there is a child in other
1494            // that matches the path at the current depth of self.
1495            // There is no such child, then then self must be in the difference.
1496            // If there is such a child, then we have to compute the difference
1497            // between self and that child.
1498            // We know that other must be a branch.
1499            let BodyRef::Branch(other_branch) = other.body_ref() else {
1500                unreachable!();
1501            };
1502            let self_byte_key = self.childleaf_key()[O::TREE_TO_KEY[other_depth]];
1503            if let Some(other_child) = other_branch.child_table.table_get(self_byte_key) {
1504                return self.difference(other_child, at_depth);
1505            } else {
1506                return Some(self.clone());
1507            }
1508        }
1509
1510        // If we reached this point then the depths are equal. The only way to have a leaf
1511        // is if the other is a leaf as well, which is already handled by the hash check if they are equal,
1512        // and by the key check if they are not equal.
1513        // If one of them is a leaf and the other is a branch, then they would also have different depths,
1514        // which is already handled by the above code.
1515        let BodyRef::Branch(self_branch) = self.body_ref() else {
1516            unreachable!();
1517        };
1518        let BodyRef::Branch(other_branch) = other.body_ref() else {
1519            unreachable!();
1520        };
1521
1522        let mut differenced_children = self_branch
1523            .child_table
1524            .iter()
1525            .filter_map(Option::as_ref)
1526            .filter_map(|self_child| {
1527                if let Some(other_child) = other_branch.child_table.table_get(self_child.key()) {
1528                    self_child.difference(other_child, self_depth)
1529                } else {
1530                    Some(self_child.clone())
1531                }
1532            });
1533
1534        let first_child = differenced_children.next()?;
1535        let second_child = match differenced_children.next() {
1536            Some(sc) => sc,
1537            None => return Some(first_child),
1538        };
1539
1540        let new_branch = Branch::new(
1541            self_depth,
1542            first_child.with_start(self_depth),
1543            second_child.with_start(self_depth),
1544        );
1545        let mut head_for_branch = Head::new(0, new_branch);
1546        {
1547            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
1548            for child in differenced_children {
1549                let inserted = child.with_start(self_depth);
1550                let k = inserted.key();
1551                ed.modify_child(k, |_opt| Some(inserted));
1552            }
1553            // ed dropped here commits the final branch pointer into head_for_branch
1554        }
1555        // The key will be set later, because we don't know it yet.
1556        // The difference might remove multiple levels of branches,
1557        // so we can't just take the key from self or other.
1558        Some(head_for_branch)
1559    }
1560}
1561
1562unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> ByteEntry for Head<KEY_LEN, O, V> {
1563    fn key(&self) -> u8 {
1564        self.key()
1565    }
1566}
1567
1568impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> fmt::Debug for Head<KEY_LEN, O, V> {
1569    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1570        self.tag().fmt(f)
1571    }
1572}
1573
1574impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Clone for Head<KEY_LEN, O, V> {
1575    fn clone(&self) -> Self {
1576        unsafe {
1577            match self.body() {
1578                BodyPtr::Leaf(leaf) => Self::new(self.key(), Leaf::rc_inc(leaf)),
1579                BodyPtr::Branch(branch) => Self::new(self.key(), Branch::rc_inc(branch)),
1580            }
1581        }
1582    }
1583}
1584
1585// The Slot wrapper was removed in favor of using BranchMut::from_slot(&mut
1586// Option<Head<...>>) directly. This keeps the API surface smaller and
1587// avoids an extra helper type that simply forwarded to BranchMut.
1588
1589impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Drop for Head<KEY_LEN, O, V> {
1590    fn drop(&mut self) {
1591        unsafe {
1592            match self.body() {
1593                BodyPtr::Leaf(leaf) => Leaf::rc_dec(leaf),
1594                BodyPtr::Branch(branch) => Branch::rc_dec(branch),
1595            }
1596        }
1597    }
1598}
1599
1600/// A PATCH is a persistent data structure that stores a set of keys.
1601/// Each key can be reordered and segmented, based on the provided key ordering and segmentation.
1602///
1603/// The patch supports efficient set operations, like union, intersection, and difference,
1604/// because it efficiently maintains a hash for all keys that are part of a sub-tree.
1605///
1606/// The tree itself is a path- and node-compressed a 256-ary trie.
1607/// Each nodes stores its children in a byte oriented cuckoo hash table,
1608/// allowing for O(1) access to children, while keeping the memory overhead low.
1609/// Table sizes are powers of two, starting at 2.
1610///
1611/// Having a single node type for all branching factors simplifies the implementation,
1612/// compared to other adaptive trie implementations, like ARTs or Judy Arrays
1613///
1614/// The PATCH allows for cheap copy-on-write operations, with `clone` being O(1).
1615#[derive(Debug)]
1616pub struct PATCH<const KEY_LEN: usize, O = IdentitySchema, V = ()>
1617where
1618    O: KeySchema<KEY_LEN>,
1619{
1620    root: Option<Head<KEY_LEN, O, V>>,
1621}
1622
1623impl<const KEY_LEN: usize, O, V> Clone for PATCH<KEY_LEN, O, V>
1624where
1625    O: KeySchema<KEY_LEN>,
1626{
1627    fn clone(&self) -> Self {
1628        Self {
1629            root: self.root.clone(),
1630        }
1631    }
1632}
1633
1634impl<const KEY_LEN: usize, O, V> Default for PATCH<KEY_LEN, O, V>
1635where
1636    O: KeySchema<KEY_LEN>,
1637{
1638    fn default() -> Self {
1639        Self::new()
1640    }
1641}
1642
1643impl<const KEY_LEN: usize, O, V> PATCH<KEY_LEN, O, V>
1644where
1645    O: KeySchema<KEY_LEN>,
1646{
1647    /// Creates a new empty PATCH.
1648    pub fn new() -> Self {
1649        init_sip_key();
1650        PATCH { root: None }
1651    }
1652
1653    /// Inserts a shared key into the PATCH.
1654    ///
1655    /// Takes an [Entry] object that can be created from a key,
1656    /// and inserted into multiple PATCH instances.
1657    ///
1658    /// If the key is already present, this is a no-op.
1659    pub fn insert(&mut self, entry: &Entry<KEY_LEN, V>) {
1660        if self.root.is_some() {
1661            let this = self.root.take().expect("root should not be empty");
1662            let new_head = Head::insert_leaf(this, entry.leaf(), 0);
1663            self.root.replace(new_head);
1664        } else {
1665            self.root.replace(entry.leaf());
1666        }
1667    }
1668
1669    /// Inserts a key into the PATCH, replacing the value if it already exists.
1670    pub fn replace(&mut self, entry: &Entry<KEY_LEN, V>) {
1671        if self.root.is_some() {
1672            let this = self.root.take().expect("root should not be empty");
1673            let new_head = Head::replace_leaf(this, entry.leaf(), 0);
1674            self.root.replace(new_head);
1675        } else {
1676            self.root.replace(entry.leaf());
1677        }
1678    }
1679
1680    /// Removes a key from the PATCH.
1681    ///
1682    /// If the key is not present, this is a no-op.
1683    pub fn remove(&mut self, key: &[u8; KEY_LEN]) {
1684        Head::remove_leaf(&mut self.root, key, 0);
1685    }
1686
1687    /// Returns the number of keys in the PATCH.
1688    pub fn len(&self) -> u64 {
1689        if let Some(root) = &self.root {
1690            root.count()
1691        } else {
1692            0
1693        }
1694    }
1695
1696    /// Returns true if the PATCH contains no keys.
1697    pub fn is_empty(&self) -> bool {
1698        self.len() == 0
1699    }
1700
1701    pub(crate) fn root_hash(&self) -> Option<u128> {
1702        self.root.as_ref().map(|root| root.hash())
1703    }
1704
1705    /// Returns the value associated with `key` if present.
1706    pub fn get(&self, key: &[u8; KEY_LEN]) -> Option<&V> {
1707        self.root.as_ref().and_then(|root| root.get(0, key))
1708    }
1709
1710    /// Allows iteratig over all infixes of a given length with a given prefix.
1711    /// Each infix is passed to the provided closure.
1712    ///
1713    /// The entire operation is performed over the tree view ordering of the keys.
1714    ///
1715    /// The length of the prefix and the infix is provided as type parameters,
1716    /// but will usually inferred from the arguments.
1717    ///
1718    /// The sum of `PREFIX_LEN` and `INFIX_LEN` must be less than or equal to `KEY_LEN`
1719    /// or a compile-time assertion will fail.
1720    ///
1721    /// Because all infixes are iterated in one go, less bookkeeping is required,
1722    /// than when using an Iterator, allowing for better performance.
1723    pub fn infixes<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
1724        &self,
1725        prefix: &[u8; PREFIX_LEN],
1726        mut for_each: F,
1727    ) where
1728        F: FnMut(&[u8; INFIX_LEN]),
1729    {
1730        const {
1731            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
1732        }
1733        assert!(
1734            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
1735                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
1736                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
1737            "INFIX_LEN must cover a whole segment"
1738        );
1739        if let Some(root) = &self.root {
1740            root.infixes(prefix, 0, &mut for_each);
1741        }
1742    }
1743
1744    /// Like [`infixes`](Self::infixes) but only yields infixes in the
1745    /// byte range `[min_infix, max_infix]` (inclusive).
1746    ///
1747    /// The trie is pruned at each depth: branches whose byte key falls
1748    /// outside the range at the current infix position are skipped
1749    /// entirely, avoiding traversal of irrelevant subtrees.
1750    pub fn infixes_range<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
1751        &self,
1752        prefix: &[u8; PREFIX_LEN],
1753        min_infix: &[u8; INFIX_LEN],
1754        max_infix: &[u8; INFIX_LEN],
1755        mut for_each: F,
1756    ) where
1757        F: FnMut(&[u8; INFIX_LEN]),
1758    {
1759        const {
1760            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
1761        }
1762        assert!(
1763            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
1764                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
1765                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
1766            "INFIX_LEN must cover a whole segment"
1767        );
1768        if let Some(root) = &self.root {
1769            root.infixes_range(prefix, 0, min_infix, max_infix, &mut for_each);
1770        }
1771    }
1772
1773    /// Count entries whose infix falls within [min_infix, max_infix].
1774    ///
1775    /// Uses cached `leaf_count` on branches to skip entire subtrees that
1776    /// are fully inside the range, making the count O(boundary_nodes)
1777    /// rather than O(matching_leaves).
1778    pub fn count_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
1779        &self,
1780        prefix: &[u8; PREFIX_LEN],
1781        min_infix: &[u8; INFIX_LEN],
1782        max_infix: &[u8; INFIX_LEN],
1783    ) -> u64 {
1784        const {
1785            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
1786        }
1787        match &self.root {
1788            Some(root) => root.count_range(prefix, 0, min_infix, max_infix),
1789            None => 0,
1790        }
1791    }
1792
1793    /// Returns true if the PATCH has a key with the given prefix.
1794    ///
1795    /// `PREFIX_LEN` must be less than or equal to `KEY_LEN` or a compile-time
1796    /// assertion will fail.
1797    pub fn has_prefix<const PREFIX_LEN: usize>(&self, prefix: &[u8; PREFIX_LEN]) -> bool {
1798        const {
1799            assert!(PREFIX_LEN <= KEY_LEN);
1800        }
1801        if let Some(root) = &self.root {
1802            root.has_prefix(0, prefix)
1803        } else {
1804            PREFIX_LEN == 0
1805        }
1806    }
1807
1808    /// Returns the number of unique segments in keys with the given prefix.
1809    pub fn segmented_len<const PREFIX_LEN: usize>(&self, prefix: &[u8; PREFIX_LEN]) -> u64 {
1810        const {
1811            assert!(PREFIX_LEN <= KEY_LEN);
1812            if PREFIX_LEN > 0 && PREFIX_LEN < KEY_LEN {
1813                assert!(
1814                    <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
1815                        [O::TREE_TO_KEY[PREFIX_LEN - 1]]
1816                        != <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
1817                            [O::TREE_TO_KEY[PREFIX_LEN]],
1818                    "PREFIX_LEN must align to segment boundary",
1819                );
1820            }
1821        }
1822        if let Some(root) = &self.root {
1823            root.segmented_len(0, prefix)
1824        } else {
1825            0
1826        }
1827    }
1828
1829    /// Iterates over all keys in the PATCH.
1830    /// The keys are returned in key ordering but random order.
1831    pub fn iter<'a>(&'a self) -> PATCHIterator<'a, KEY_LEN, O, V> {
1832        PATCHIterator::new(self)
1833    }
1834
1835    /// Iterates over all keys in the PATCH in key order.
1836    ///
1837    /// The traversal visits every key in lexicographic key order, without
1838    /// accepting a prefix filter. For prefix-aware iteration, see
1839    /// [`PATCH::iter_prefix_count`].
1840    pub fn iter_ordered<'a>(&'a self) -> PATCHOrderedIterator<'a, KEY_LEN, O, V> {
1841        PATCHOrderedIterator::new(self)
1842    }
1843
1844    /// Iterate over all prefixes of the given length in the PATCH.
1845    /// The prefixes are naturally returned in tree ordering and tree order.
1846    /// A count of the number of elements for the given prefix is also returned.
1847    pub fn iter_prefix_count<'a, const PREFIX_LEN: usize>(
1848        &'a self,
1849    ) -> PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V> {
1850        PATCHPrefixIterator::new(self)
1851    }
1852
1853    /// Unions this PATCH with another PATCH.
1854    ///
1855    /// The other PATCH is consumed, and this PATCH is updated in place.
1856    pub fn union(&mut self, other: Self)
1857    where
1858        O: Send + Sync,
1859        V: Send + Sync,
1860    {
1861        if let Some(other) = other.root {
1862            if self.root.is_some() {
1863                let this = self.root.take().expect("root should not be empty");
1864                #[cfg(feature = "parallel")]
1865                let merged = Head::par_union(this, other, 0);
1866                #[cfg(not(feature = "parallel"))]
1867                let merged = Head::union(this, other, 0);
1868                self.root.replace(merged);
1869            } else {
1870                self.root.replace(other);
1871            }
1872        }
1873    }
1874
1875    /// Intersects this PATCH with another PATCH.
1876    ///
1877    /// Returns a new PATCH that contains only the keys that are present in both PATCHes.
1878    pub fn intersect(&self, other: &Self) -> Self
1879    where
1880        O: Send + Sync,
1881        V: Send + Sync,
1882    {
1883        if let Some(root) = &self.root {
1884            if let Some(other_root) = &other.root {
1885                #[cfg(feature = "parallel")]
1886                let result = root.par_intersect(other_root, 0);
1887                #[cfg(not(feature = "parallel"))]
1888                let result = root.intersect(other_root, 0);
1889                return Self {
1890                    root: result.map(|root| root.with_start(0)),
1891                };
1892            }
1893        }
1894        Self::new()
1895    }
1896
1897    /// Returns the difference between this PATCH and another PATCH.
1898    ///
1899    /// Returns a new PATCH that contains only the keys that are present in this PATCH,
1900    /// but not in the other PATCH.
1901    pub fn difference(&self, other: &Self) -> Self
1902    where
1903        O: Send + Sync,
1904        V: Send + Sync,
1905    {
1906        if let Some(root) = &self.root {
1907            if let Some(other_root) = &other.root {
1908                #[cfg(feature = "parallel")]
1909                let result = root.par_difference(other_root, 0);
1910                #[cfg(not(feature = "parallel"))]
1911                let result = root.difference(other_root, 0);
1912                Self { root: result }
1913            } else {
1914                (*self).clone()
1915            }
1916        } else {
1917            Self::new()
1918        }
1919    }
1920
1921    /// Calculates the average fill level for branch nodes grouped by their
1922    /// branching factor. The returned array contains eight entries for branch
1923    /// sizes `2`, `4`, `8`, `16`, `32`, `64`, `128` and `256` in that order.
1924    //#[cfg(debug_assertions)]
1925    pub fn debug_branch_fill(&self) -> [f32; 8] {
1926        let mut counts = [0u64; 8];
1927        let mut used = [0u64; 8];
1928
1929        if let Some(root) = &self.root {
1930            let mut stack = Vec::new();
1931            stack.push(root);
1932
1933            while let Some(head) = stack.pop() {
1934                match head.body_ref() {
1935                    BodyRef::Leaf(_) => {}
1936                    BodyRef::Branch(b) => {
1937                        let size = b.child_table.len();
1938                        let idx = size.trailing_zeros() as usize - 1;
1939                        counts[idx] += 1;
1940                        used[idx] += b.child_table.iter().filter(|c| c.is_some()).count() as u64;
1941                        for child in b.child_table.iter().filter_map(|c| c.as_ref()) {
1942                            stack.push(child);
1943                        }
1944                    }
1945                }
1946            }
1947        }
1948
1949        let mut avg = [0f32; 8];
1950        for i in 0..8 {
1951            if counts[i] > 0 {
1952                let size = 1u64 << (i + 1);
1953                avg[i] = used[i] as f32 / (counts[i] as f32 * size as f32);
1954            }
1955        }
1956        avg
1957    }
1958}
1959
1960impl<const KEY_LEN: usize, O, V> PartialEq for PATCH<KEY_LEN, O, V>
1961where
1962    O: KeySchema<KEY_LEN>,
1963{
1964    fn eq(&self, other: &Self) -> bool {
1965        self.root.as_ref().map(|root| root.hash()) == other.root.as_ref().map(|root| root.hash())
1966    }
1967}
1968
1969impl<const KEY_LEN: usize, O, V> Eq for PATCH<KEY_LEN, O, V> where O: KeySchema<KEY_LEN> {}
1970
1971impl<'a, const KEY_LEN: usize, O, V> IntoIterator for &'a PATCH<KEY_LEN, O, V>
1972where
1973    O: KeySchema<KEY_LEN>,
1974{
1975    type Item = &'a [u8; KEY_LEN];
1976    type IntoIter = PATCHIterator<'a, KEY_LEN, O, V>;
1977
1978    fn into_iter(self) -> Self::IntoIter {
1979        PATCHIterator::new(self)
1980    }
1981}
1982
1983/// An iterator over all keys in a PATCH.
1984/// The keys are returned in key ordering but in random order.
1985pub struct PATCHIterator<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
1986    stack: ArrayVec<std::slice::Iter<'a, Option<Head<KEY_LEN, O, V>>>, KEY_LEN>,
1987    remaining: usize,
1988}
1989
1990impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> PATCHIterator<'a, KEY_LEN, O, V> {
1991    /// Creates an iterator over all keys in `patch`.
1992    pub fn new(patch: &'a PATCH<KEY_LEN, O, V>) -> Self {
1993        let mut r = PATCHIterator {
1994            stack: ArrayVec::new(),
1995            remaining: patch.len().min(usize::MAX as u64) as usize,
1996        };
1997        r.stack.push(std::slice::from_ref(&patch.root).iter());
1998        r
1999    }
2000}
2001
2002impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Iterator
2003    for PATCHIterator<'a, KEY_LEN, O, V>
2004{
2005    type Item = &'a [u8; KEY_LEN];
2006
2007    fn next(&mut self) -> Option<Self::Item> {
2008        let mut iter = self.stack.last_mut()?;
2009        loop {
2010            if let Some(child) = iter.next() {
2011                if let Some(child) = child {
2012                    match child.body_ref() {
2013                        BodyRef::Leaf(_) => {
2014                            self.remaining = self.remaining.saturating_sub(1);
2015                            // Use the safe accessor on the child reference to obtain the leaf key bytes.
2016                            return Some(child.childleaf_key());
2017                        }
2018                        BodyRef::Branch(branch) => {
2019                            self.stack.push(branch.child_table.iter());
2020                            iter = self.stack.last_mut()?;
2021                        }
2022                    }
2023                }
2024            } else {
2025                self.stack.pop();
2026                iter = self.stack.last_mut()?;
2027            }
2028        }
2029    }
2030
2031    fn size_hint(&self) -> (usize, Option<usize>) {
2032        (self.remaining, Some(self.remaining))
2033    }
2034}
2035
2036impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> ExactSizeIterator
2037    for PATCHIterator<'a, KEY_LEN, O, V>
2038{
2039}
2040
2041impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> std::iter::FusedIterator
2042    for PATCHIterator<'a, KEY_LEN, O, V>
2043{
2044}
2045
2046/// An iterator over every key in a PATCH, returned in key order.
2047///
2048/// Keys are yielded in lexicographic key order regardless of their physical
2049/// layout in the underlying tree. This iterator walks the full tree and does
2050/// not accept a prefix filter. For prefix-aware iteration, use
2051/// [`PATCHPrefixIterator`], constructed via [`PATCH::iter_prefix_count`].
2052pub struct PATCHOrderedIterator<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
2053    stack: Vec<ArrayVec<&'a Head<KEY_LEN, O, V>, 256>>,
2054    remaining: usize,
2055}
2056
2057impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> PATCHOrderedIterator<'a, KEY_LEN, O, V> {
2058    pub fn new(patch: &'a PATCH<KEY_LEN, O, V>) -> Self {
2059        let mut r = PATCHOrderedIterator {
2060            stack: Vec::with_capacity(KEY_LEN),
2061            remaining: patch.len().min(usize::MAX as u64) as usize,
2062        };
2063        if let Some(root) = &patch.root {
2064            r.stack.push(ArrayVec::new());
2065            match root.body_ref() {
2066                BodyRef::Leaf(_) => {
2067                    r.stack[0].push(root);
2068                }
2069                BodyRef::Branch(branch) => {
2070                    let first_level = &mut r.stack[0];
2071                    first_level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
2072                    first_level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
2073                }
2074            }
2075        }
2076        r
2077    }
2078}
2079
2080// --- Owned consuming iterators ---
2081/// Iterator that owns a PATCH and yields keys in key-order. The iterator
2082/// consumes the PATCH and stores it on the heap (Box) so it can safely hold
2083/// raw pointers into the patch memory while the iterator is moved.
2084pub struct PATCHIntoIterator<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
2085    queue: Vec<Head<KEY_LEN, O, V>>,
2086    remaining: usize,
2087}
2088
2089impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> PATCHIntoIterator<KEY_LEN, O, V> {}
2090
2091impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Iterator for PATCHIntoIterator<KEY_LEN, O, V> {
2092    type Item = [u8; KEY_LEN];
2093
2094    fn next(&mut self) -> Option<Self::Item> {
2095        let q = &mut self.queue;
2096        while let Some(mut head) = q.pop() {
2097            // Match on the mutable body directly. For leaves we can return the
2098            // stored key (the array is Copy), for branches we take children out
2099            // of the table and push them onto the stack so they are visited
2100            // depth-first.
2101            match head.body_mut() {
2102                BodyMut::Leaf(leaf) => {
2103                    self.remaining = self.remaining.saturating_sub(1);
2104                    return Some(leaf.key);
2105                }
2106                BodyMut::Branch(branch) => {
2107                    for slot in branch.child_table.iter_mut().rev() {
2108                        if let Some(c) = slot.take() {
2109                            q.push(c);
2110                        }
2111                    }
2112                }
2113            }
2114        }
2115        None
2116    }
2117}
2118
2119/// Iterator that owns a PATCH and yields keys in key order.
2120pub struct PATCHIntoOrderedIterator<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> {
2121    queue: Vec<Head<KEY_LEN, O, V>>,
2122    remaining: usize,
2123}
2124
2125impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Iterator
2126    for PATCHIntoOrderedIterator<KEY_LEN, O, V>
2127{
2128    type Item = [u8; KEY_LEN];
2129
2130    fn next(&mut self) -> Option<Self::Item> {
2131        let q = &mut self.queue;
2132        while let Some(mut head) = q.pop() {
2133            // Match the mutable body directly — we own `head` so calling
2134            // `body_mut()` is safe and allows returning the copied leaf key
2135            // or mutating the branch child table in-place.
2136            match head.body_mut() {
2137                BodyMut::Leaf(leaf) => {
2138                    self.remaining = self.remaining.saturating_sub(1);
2139                    return Some(leaf.key);
2140                }
2141                BodyMut::Branch(branch) => {
2142                    let slice: &mut [Option<Head<KEY_LEN, O, V>>] = &mut branch.child_table;
2143                    // Sort children by their byte-key, placing empty slots (None)
2144                    // after all occupied slots. Using `sort_unstable_by_key` with
2145                    // a simple key projection is clearer than a custom
2146                    // comparator; it also avoids allocating temporaries. The
2147                    // old comparator manually handled None/Some cases — we
2148                    // express that intent directly by sorting on the tuple
2149                    // (is_none, key_opt).
2150                    slice
2151                        .sort_unstable_by_key(|opt| (opt.is_none(), opt.as_ref().map(|h| h.key())));
2152                    for slot in slice.iter_mut().rev() {
2153                        if let Some(c) = slot.take() {
2154                            q.push(c);
2155                        }
2156                    }
2157                }
2158            }
2159        }
2160        None
2161    }
2162}
2163
2164impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> IntoIterator for PATCH<KEY_LEN, O, V> {
2165    type Item = [u8; KEY_LEN];
2166    type IntoIter = PATCHIntoIterator<KEY_LEN, O, V>;
2167
2168    fn into_iter(self) -> Self::IntoIter {
2169        let remaining = self.len().min(usize::MAX as u64) as usize;
2170        let mut q = Vec::new();
2171        if let Some(root) = self.root {
2172            q.push(root);
2173        }
2174        PATCHIntoIterator {
2175            queue: q,
2176            remaining,
2177        }
2178    }
2179}
2180
2181impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> PATCH<KEY_LEN, O, V> {
2182    /// Consume and return an iterator that yields keys in key order.
2183    pub fn into_iter_ordered(self) -> PATCHIntoOrderedIterator<KEY_LEN, O, V> {
2184        let remaining = self.len().min(usize::MAX as u64) as usize;
2185        let mut q = Vec::new();
2186        if let Some(root) = self.root {
2187            q.push(root);
2188        }
2189        PATCHIntoOrderedIterator {
2190            queue: q,
2191            remaining,
2192        }
2193    }
2194}
2195
2196impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> Iterator
2197    for PATCHOrderedIterator<'a, KEY_LEN, O, V>
2198{
2199    type Item = &'a [u8; KEY_LEN];
2200
2201    fn next(&mut self) -> Option<Self::Item> {
2202        let mut level = self.stack.last_mut()?;
2203        loop {
2204            if let Some(child) = level.pop() {
2205                match child.body_ref() {
2206                    BodyRef::Leaf(_) => {
2207                        self.remaining = self.remaining.saturating_sub(1);
2208                        return Some(child.childleaf_key());
2209                    }
2210                    BodyRef::Branch(branch) => {
2211                        self.stack.push(ArrayVec::new());
2212                        level = self.stack.last_mut()?;
2213                        level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
2214                        level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
2215                    }
2216                }
2217            } else {
2218                self.stack.pop();
2219                level = self.stack.last_mut()?;
2220            }
2221        }
2222    }
2223
2224    fn size_hint(&self) -> (usize, Option<usize>) {
2225        (self.remaining, Some(self.remaining))
2226    }
2227}
2228
2229impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> ExactSizeIterator
2230    for PATCHOrderedIterator<'a, KEY_LEN, O, V>
2231{
2232}
2233
2234impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V> std::iter::FusedIterator
2235    for PATCHOrderedIterator<'a, KEY_LEN, O, V>
2236{
2237}
2238
2239/// An iterator over all keys in a PATCH that have a given prefix.
2240/// The keys are returned in tree ordering and in tree order.
2241pub struct PATCHPrefixIterator<
2242    'a,
2243    const KEY_LEN: usize,
2244    const PREFIX_LEN: usize,
2245    O: KeySchema<KEY_LEN>,
2246    V,
2247> {
2248    stack: Vec<ArrayVec<&'a Head<KEY_LEN, O, V>, 256>>,
2249}
2250
2251impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V>
2252    PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V>
2253{
2254    fn new(patch: &'a PATCH<KEY_LEN, O, V>) -> Self {
2255        const {
2256            assert!(PREFIX_LEN <= KEY_LEN);
2257        }
2258        let mut r = PATCHPrefixIterator {
2259            stack: Vec::with_capacity(PREFIX_LEN),
2260        };
2261        if let Some(root) = &patch.root {
2262            r.stack.push(ArrayVec::new());
2263            if root.end_depth() >= PREFIX_LEN {
2264                r.stack[0].push(root);
2265            } else {
2266                let BodyRef::Branch(branch) = root.body_ref() else {
2267                    unreachable!();
2268                };
2269                let first_level = &mut r.stack[0];
2270                first_level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
2271                first_level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
2272            }
2273        }
2274        r
2275    }
2276}
2277
2278impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V> Iterator
2279    for PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V>
2280{
2281    type Item = ([u8; PREFIX_LEN], u64);
2282
2283    fn next(&mut self) -> Option<Self::Item> {
2284        let mut level = self.stack.last_mut()?;
2285        loop {
2286            if let Some(child) = level.pop() {
2287                if child.end_depth() >= PREFIX_LEN {
2288                    let key = O::tree_ordered(child.childleaf_key());
2289                    let suffix_count = child.count();
2290                    return Some((key[0..PREFIX_LEN].try_into().unwrap(), suffix_count));
2291                } else {
2292                    let BodyRef::Branch(branch) = child.body_ref() else {
2293                        unreachable!();
2294                    };
2295                    self.stack.push(ArrayVec::new());
2296                    level = self.stack.last_mut()?;
2297                    level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
2298                    level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
2299                }
2300            } else {
2301                self.stack.pop();
2302                level = self.stack.last_mut()?;
2303            }
2304        }
2305    }
2306}
2307
2308#[cfg(test)]
2309mod tests {
2310    use super::*;
2311    use itertools::Itertools;
2312    use proptest::prelude::*;
2313    use std::collections::HashSet;
2314    use std::convert::TryInto;
2315    use std::iter::FromIterator;
2316    use std::mem;
2317
2318    #[test]
2319    fn head_tag() {
2320        let head = Head::<64, IdentitySchema, ()>::new::<Leaf<64, ()>>(0, NonNull::dangling());
2321        assert_eq!(head.tag(), HeadTag::Leaf);
2322        mem::forget(head);
2323    }
2324
2325    #[test]
2326    fn head_key() {
2327        for k in 0..=255 {
2328            let head = Head::<64, IdentitySchema, ()>::new::<Leaf<64, ()>>(k, NonNull::dangling());
2329            assert_eq!(head.key(), k);
2330            mem::forget(head);
2331        }
2332    }
2333
2334    #[test]
2335    fn head_size() {
2336        assert_eq!(mem::size_of::<Head<64, IdentitySchema, ()>>(), 8);
2337    }
2338
2339    #[test]
2340    fn option_head_size() {
2341        assert_eq!(mem::size_of::<Option<Head<64, IdentitySchema, ()>>>(), 8);
2342    }
2343
2344    #[test]
2345    fn empty_tree() {
2346        let _tree = PATCH::<64, IdentitySchema, ()>::new();
2347    }
2348
2349    #[test]
2350    fn tree_put_one() {
2351        const KEY_SIZE: usize = 64;
2352        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
2353        let entry = Entry::new(&[0; KEY_SIZE]);
2354        tree.insert(&entry);
2355    }
2356
2357    #[test]
2358    fn tree_clone_one() {
2359        const KEY_SIZE: usize = 64;
2360        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
2361        let entry = Entry::new(&[0; KEY_SIZE]);
2362        tree.insert(&entry);
2363        let _clone = tree.clone();
2364    }
2365
2366    #[test]
2367    fn tree_put_same() {
2368        const KEY_SIZE: usize = 64;
2369        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
2370        let entry = Entry::new(&[0; KEY_SIZE]);
2371        tree.insert(&entry);
2372        tree.insert(&entry);
2373    }
2374
2375    #[test]
2376    fn tree_replace_existing() {
2377        const KEY_SIZE: usize = 64;
2378        let key = [1u8; KEY_SIZE];
2379        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2380        let entry1 = Entry::with_value(&key, 1);
2381        tree.insert(&entry1);
2382        let entry2 = Entry::with_value(&key, 2);
2383        tree.replace(&entry2);
2384        assert_eq!(tree.get(&key), Some(&2));
2385    }
2386
2387    #[test]
2388    fn tree_replace_childleaf_updates_branch() {
2389        const KEY_SIZE: usize = 64;
2390        let key1 = [0u8; KEY_SIZE];
2391        let key2 = [1u8; KEY_SIZE];
2392        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2393        let entry1 = Entry::with_value(&key1, 1);
2394        let entry2 = Entry::with_value(&key2, 2);
2395        tree.insert(&entry1);
2396        tree.insert(&entry2);
2397        let entry1b = Entry::with_value(&key1, 3);
2398        tree.replace(&entry1b);
2399        assert_eq!(tree.get(&key1), Some(&3));
2400        assert_eq!(tree.get(&key2), Some(&2));
2401    }
2402
2403    #[test]
2404    fn update_child_refreshes_childleaf_on_replace() {
2405        const KEY_SIZE: usize = 4;
2406        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2407
2408        let key1 = [0u8; KEY_SIZE];
2409        let key2 = [1u8; KEY_SIZE];
2410        tree.insert(&Entry::with_value(&key1, 1));
2411        tree.insert(&Entry::with_value(&key2, 2));
2412
2413        // Determine which child currently provides the branch childleaf.
2414        let root_ref = tree.root.as_ref().expect("root exists");
2415        let before_childleaf = *root_ref.childleaf_key();
2416
2417        // Find the slot key (the byte index used in the branch table) for the child
2418        // that currently provides the childleaf.
2419        let slot_key = match root_ref.body_ref() {
2420            BodyRef::Branch(branch) => branch
2421                .child_table
2422                .iter()
2423                .filter_map(|c| c.as_ref())
2424                .find(|c| c.childleaf_key() == &before_childleaf)
2425                .expect("child exists")
2426                .key(),
2427            BodyRef::Leaf(_) => panic!("root should be a branch"),
2428        };
2429
2430        // Replace that child with a new leaf that has a different childleaf key.
2431        let new_key = [2u8; KEY_SIZE];
2432        {
2433            let mut ed = crate::patch::branch::BranchMut::from_slot(&mut tree.root);
2434            ed.modify_child(slot_key, |_| {
2435                Some(Entry::with_value(&new_key, 42).leaf::<IdentitySchema>())
2436            });
2437            // drop(ed) commits
2438        }
2439
2440        let after = tree.root.as_ref().expect("root exists");
2441        assert_eq!(after.childleaf_key(), &new_key);
2442    }
2443
2444    #[test]
2445    fn remove_childleaf_updates_branch() {
2446        const KEY_SIZE: usize = 4;
2447        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2448
2449        let key1 = [0u8; KEY_SIZE];
2450        let key2 = [1u8; KEY_SIZE];
2451        tree.insert(&Entry::with_value(&key1, 1));
2452        tree.insert(&Entry::with_value(&key2, 2));
2453
2454        let childleaf_before = *tree.root.as_ref().unwrap().childleaf_key();
2455        // remove the leaf that currently provides the branch.childleaf
2456        tree.remove(&childleaf_before);
2457
2458        // Ensure the removed key is gone and the other key remains and is now the childleaf.
2459        let other = if childleaf_before == key1 { key2 } else { key1 };
2460        assert_eq!(tree.get(&childleaf_before), None);
2461        assert_eq!(tree.get(&other), Some(&2u32));
2462        let after_childleaf = tree.root.as_ref().unwrap().childleaf_key();
2463        assert_eq!(after_childleaf, &other);
2464    }
2465
2466    #[test]
2467    fn remove_collapses_branch_to_single_child() {
2468        const KEY_SIZE: usize = 4;
2469        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2470
2471        let key1 = [0u8; KEY_SIZE];
2472        let key2 = [1u8; KEY_SIZE];
2473        tree.insert(&Entry::with_value(&key1, 1));
2474        tree.insert(&Entry::with_value(&key2, 2));
2475
2476        // Remove one key and ensure the root collapses to the remaining child.
2477        tree.remove(&key1);
2478        assert_eq!(tree.get(&key1), None);
2479        assert_eq!(tree.get(&key2), Some(&2u32));
2480        let root = tree.root.as_ref().expect("root exists");
2481        match root.body_ref() {
2482            BodyRef::Leaf(_) => {}
2483            BodyRef::Branch(_) => panic!("root should have collapsed to a leaf"),
2484        }
2485    }
2486
2487    #[test]
2488    fn branch_size() {
2489        assert_eq!(
2490            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 2], ()>>(
2491            ),
2492            64
2493        );
2494        assert_eq!(
2495            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 4], ()>>(
2496            ),
2497            48 + 16 * 2
2498        );
2499        assert_eq!(
2500            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 8], ()>>(
2501            ),
2502            48 + 16 * 4
2503        );
2504        assert_eq!(
2505            mem::size_of::<
2506                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 16], ()>,
2507            >(),
2508            48 + 16 * 8
2509        );
2510        assert_eq!(
2511            mem::size_of::<
2512                Branch<64, IdentitySchema, [Option<Head<32, IdentitySchema, ()>>; 32], ()>,
2513            >(),
2514            48 + 16 * 16
2515        );
2516        assert_eq!(
2517            mem::size_of::<
2518                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 64], ()>,
2519            >(),
2520            48 + 16 * 32
2521        );
2522        assert_eq!(
2523            mem::size_of::<
2524                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 128], ()>,
2525            >(),
2526            48 + 16 * 64
2527        );
2528        assert_eq!(
2529            mem::size_of::<
2530                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 256], ()>,
2531            >(),
2532            48 + 16 * 128
2533        );
2534    }
2535
2536    /// Checks what happens if we join two PATCHes that
2537    /// only contain a single element each, that differs in the last byte.
2538    #[test]
2539    fn tree_union_single() {
2540        const KEY_SIZE: usize = 8;
2541        let mut left = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
2542        let mut right = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
2543        let left_entry = Entry::new(&[0, 0, 0, 0, 0, 0, 0, 0]);
2544        let right_entry = Entry::new(&[0, 0, 0, 0, 0, 0, 0, 1]);
2545        left.insert(&left_entry);
2546        right.insert(&right_entry);
2547        left.union(right);
2548        assert_eq!(left.len(), 2);
2549    }
2550
2551    // Small unit tests that ensure BranchMut-based editing is used by
2552    // the higher-level set operations like intersect/difference. These are
2553    // ordinary unit tests (not proptest) and must appear outside the
2554    // `proptest!` macro below.
2555
2556    proptest! {
2557        #[test]
2558        fn tree_insert(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
2559            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
2560            for key in keys {
2561                let key: [u8; 64] = key.try_into().unwrap();
2562                let entry = Entry::new(&key);
2563                tree.insert(&entry);
2564            }
2565        }
2566
2567        #[test]
2568        fn tree_len(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
2569            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
2570            let mut set = HashSet::new();
2571            for key in keys {
2572                let key: [u8; 64] = key.try_into().unwrap();
2573                let entry = Entry::new(&key);
2574                tree.insert(&entry);
2575                set.insert(key);
2576            }
2577
2578            prop_assert_eq!(set.len() as u64, tree.len())
2579        }
2580
2581        #[test]
2582        fn tree_infixes(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
2583            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
2584            let mut set = HashSet::new();
2585            for key in keys {
2586                let key: [u8; 64] = key.try_into().unwrap();
2587                let entry = Entry::new(&key);
2588                tree.insert(&entry);
2589                set.insert(key);
2590            }
2591            let mut set_vec = Vec::from_iter(set.into_iter());
2592            let mut tree_vec = vec![];
2593            tree.infixes(&[0; 0], &mut |&x: &[u8; 64]| tree_vec.push(x));
2594
2595            set_vec.sort();
2596            tree_vec.sort();
2597
2598            prop_assert_eq!(set_vec, tree_vec);
2599        }
2600
2601        #[test]
2602        fn tree_iter(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
2603            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
2604            let mut set = HashSet::new();
2605            for key in keys {
2606                let key: [u8; 64] = key.try_into().unwrap();
2607                let entry = Entry::new(&key);
2608                tree.insert(&entry);
2609                set.insert(key);
2610            }
2611            let mut set_vec = Vec::from_iter(set.into_iter());
2612            let mut tree_vec = vec![];
2613            for key in &tree {
2614                tree_vec.push(*key);
2615            }
2616
2617            set_vec.sort();
2618            tree_vec.sort();
2619
2620            prop_assert_eq!(set_vec, tree_vec);
2621        }
2622
2623        #[test]
2624        fn tree_union(left in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 200),
2625                        right in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 200)) {
2626            let mut set = HashSet::new();
2627
2628            let mut left_tree = PATCH::<64, IdentitySchema, ()>::new();
2629            for entry in left {
2630                let mut key = [0; 64];
2631                key.iter_mut().set_from(entry.iter().cloned());
2632                let entry = Entry::new(&key);
2633                left_tree.insert(&entry);
2634                set.insert(key);
2635            }
2636
2637            let mut right_tree = PATCH::<64, IdentitySchema, ()>::new();
2638            for entry in right {
2639                let mut key = [0; 64];
2640                key.iter_mut().set_from(entry.iter().cloned());
2641                let entry = Entry::new(&key);
2642                right_tree.insert(&entry);
2643                set.insert(key);
2644            }
2645
2646            left_tree.union(right_tree);
2647
2648            let mut set_vec = Vec::from_iter(set.into_iter());
2649            let mut tree_vec = vec![];
2650            left_tree.infixes(&[0; 0], &mut |&x: &[u8;64]| tree_vec.push(x));
2651
2652            set_vec.sort();
2653            tree_vec.sort();
2654
2655            prop_assert_eq!(set_vec, tree_vec);
2656            }
2657
2658        #[test]
2659        fn tree_union_empty(left in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 2)) {
2660            let mut set = HashSet::new();
2661
2662            let mut left_tree = PATCH::<64, IdentitySchema, ()>::new();
2663            for entry in left {
2664                let mut key = [0; 64];
2665                key.iter_mut().set_from(entry.iter().cloned());
2666                let entry = Entry::new(&key);
2667                left_tree.insert(&entry);
2668                set.insert(key);
2669            }
2670
2671            let right_tree = PATCH::<64, IdentitySchema, ()>::new();
2672
2673            left_tree.union(right_tree);
2674
2675            let mut set_vec = Vec::from_iter(set.into_iter());
2676            let mut tree_vec = vec![];
2677            left_tree.infixes(&[0; 0], &mut |&x: &[u8;64]| tree_vec.push(x));
2678
2679            set_vec.sort();
2680            tree_vec.sort();
2681
2682            prop_assert_eq!(set_vec, tree_vec);
2683            }
2684
2685        // I got a feeling that we're not testing COW properly.
2686        // We should check if a tree remains the same after a clone of it
2687        // is modified by inserting new keys.
2688
2689    #[test]
2690    fn cow_on_insert(base_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024),
2691                         new_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024)) {
2692            // Note that we can't compare the trees directly, as that uses the hash,
2693            // which might not be affected by nodes in lower levels being changed accidentally.
2694            // Instead we need to iterate over the keys and check if they are the same.
2695
2696            let mut tree = PATCH::<8, IdentitySchema, ()>::new();
2697            for key in base_keys {
2698                let key: [u8; 8] = key[..].try_into().unwrap();
2699                let entry = Entry::new(&key);
2700                tree.insert(&entry);
2701            }
2702            let base_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
2703
2704            let mut tree_clone = tree.clone();
2705            for key in new_keys {
2706                let key: [u8; 8] = key[..].try_into().unwrap();
2707                let entry = Entry::new(&key);
2708                tree_clone.insert(&entry);
2709            }
2710
2711            let new_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
2712            prop_assert_eq!(base_tree_content, new_tree_content);
2713        }
2714
2715        #[test]
2716    fn cow_on_union(base_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024),
2717                         new_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024)) {
2718            // Note that we can't compare the trees directly, as that uses the hash,
2719            // which might not be affected by nodes in lower levels being changed accidentally.
2720            // Instead we need to iterate over the keys and check if they are the same.
2721
2722            let mut tree = PATCH::<8, IdentitySchema, ()>::new();
2723            for key in base_keys {
2724                let key: [u8; 8] = key[..].try_into().unwrap();
2725                let entry = Entry::new(&key);
2726                tree.insert(&entry);
2727            }
2728            let base_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
2729
2730            let mut tree_clone = tree.clone();
2731            let mut new_tree = PATCH::<8, IdentitySchema, ()>::new();
2732            for key in new_keys {
2733                let key: [u8; 8] = key[..].try_into().unwrap();
2734                let entry = Entry::new(&key);
2735                new_tree.insert(&entry);
2736            }
2737            tree_clone.union(new_tree);
2738
2739            let new_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
2740            prop_assert_eq!(base_tree_content, new_tree_content);
2741        }
2742    }
2743
2744    #[test]
2745    fn intersect_multiple_common_children_commits_branchmut() {
2746        const KEY_SIZE: usize = 4;
2747        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2748        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2749
2750        let a = [0u8, 0u8, 0u8, 1u8];
2751        let b = [0u8, 0u8, 0u8, 2u8];
2752        let c = [0u8, 0u8, 0u8, 3u8];
2753        let d = [2u8, 0u8, 0u8, 0u8];
2754        let e = [3u8, 0u8, 0u8, 0u8];
2755
2756        left.insert(&Entry::with_value(&a, 1));
2757        left.insert(&Entry::with_value(&b, 2));
2758        left.insert(&Entry::with_value(&c, 3));
2759        left.insert(&Entry::with_value(&d, 4));
2760
2761        right.insert(&Entry::with_value(&a, 10));
2762        right.insert(&Entry::with_value(&b, 11));
2763        right.insert(&Entry::with_value(&c, 12));
2764        right.insert(&Entry::with_value(&e, 13));
2765
2766        let res = left.intersect(&right);
2767        // A, B, C are common
2768        assert_eq!(res.len(), 3);
2769        assert!(res.get(&a).is_some());
2770        assert!(res.get(&b).is_some());
2771        assert!(res.get(&c).is_some());
2772    }
2773
2774    #[test]
2775    fn difference_multiple_children_commits_branchmut() {
2776        const KEY_SIZE: usize = 4;
2777        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2778        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2779
2780        let a = [0u8, 0u8, 0u8, 1u8];
2781        let b = [0u8, 0u8, 0u8, 2u8];
2782        let c = [0u8, 0u8, 0u8, 3u8];
2783        let d = [2u8, 0u8, 0u8, 0u8];
2784        let e = [3u8, 0u8, 0u8, 0u8];
2785
2786        left.insert(&Entry::with_value(&a, 1));
2787        left.insert(&Entry::with_value(&b, 2));
2788        left.insert(&Entry::with_value(&c, 3));
2789        left.insert(&Entry::with_value(&d, 4));
2790
2791        right.insert(&Entry::with_value(&a, 10));
2792        right.insert(&Entry::with_value(&b, 11));
2793        right.insert(&Entry::with_value(&c, 12));
2794        right.insert(&Entry::with_value(&e, 13));
2795
2796        let res = left.difference(&right);
2797        // left only has d
2798        assert_eq!(res.len(), 1);
2799        assert!(res.get(&d).is_some());
2800    }
2801
2802    #[test]
2803    fn difference_empty_left_is_empty() {
2804        const KEY_SIZE: usize = 4;
2805        let left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2806        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2807        let key = [1u8, 2u8, 3u8, 4u8];
2808        right.insert(&Entry::with_value(&key, 7));
2809
2810        let res = left.difference(&right);
2811        assert_eq!(res.len(), 0);
2812    }
2813
2814    #[test]
2815    fn difference_empty_right_returns_left() {
2816        const KEY_SIZE: usize = 4;
2817        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2818        let right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2819        let key = [1u8, 2u8, 3u8, 4u8];
2820        left.insert(&Entry::with_value(&key, 7));
2821
2822        let res = left.difference(&right);
2823        assert_eq!(res.len(), 1);
2824        assert!(res.get(&key).is_some());
2825    }
2826
2827    #[test]
2828    fn slot_edit_branchmut_insert_update() {
2829        // Small unit test demonstrating the Slot::edit -> BranchMut insert/update pattern.
2830        const KEY_SIZE: usize = 8;
2831        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
2832
2833        let entry1 = Entry::with_value(&[0u8; KEY_SIZE], 1u32);
2834        let entry2 = Entry::with_value(&[1u8; KEY_SIZE], 2u32);
2835        tree.insert(&entry1);
2836        tree.insert(&entry2);
2837        assert_eq!(tree.len(), 2);
2838
2839        // Edit the root slot in-place using the BranchMut editor.
2840        {
2841            let mut ed = crate::patch::branch::BranchMut::from_slot(&mut tree.root);
2842
2843            // Compute the insertion start depth first to avoid borrowing `ed` inside the closure.
2844            let start_depth = ed.end_depth as usize;
2845            let inserted = Entry::with_value(&[2u8; KEY_SIZE], 3u32)
2846                .leaf::<IdentitySchema>()
2847                .with_start(start_depth);
2848            let key = inserted.key();
2849
2850            ed.modify_child(key, |opt| match opt {
2851                Some(old) => Some(Head::insert_leaf(old, inserted, start_depth)),
2852                None => Some(inserted),
2853            });
2854            // BranchMut is dropped here and commits the updated branch pointer back into the head.
2855        }
2856
2857        assert_eq!(tree.len(), 3);
2858        assert_eq!(tree.get(&[2u8; KEY_SIZE]), Some(&3u32));
2859    }
2860}