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