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
22/// Re-export of [`Entry`](entry::Entry).
23use branch::*;
24pub use entry::{ArchiveEntry, Entry};
25use leaf::*;
26
27/// Re-export of all byte table utilities.
28pub use bytetable::*;
29use rand::thread_rng;
30use rand::RngCore;
31use std::cmp::{Ordering, Reverse};
32use std::convert::TryInto;
33use std::fmt;
34use std::fmt::Debug;
35use std::marker::PhantomData;
36use std::ptr::NonNull;
37use std::sync::{Arc, OnceLock};
38
39/// Marker trait for opaque owners of bytes referenced by archive-backed
40/// PATCH leaves. An owner exists solely to keep its allocation alive while a
41/// [`HeadTag::LocalLeaf`] points into it.
42pub trait ArchiveOwner: Send + Sync + 'static {}
43
44impl<T: Send + Sync + 'static + ?Sized> ArchiveOwner for T {}
45
46/// One node in the exact persistent set of retained archive allocations.
47///
48/// Owners are stored inline in their parent (or directly in [`OwnerCover`]);
49/// only branches allocate an [`Arc`]. This is a binary Patricia trie over
50/// owner allocation addresses. Masks strictly decrease on each root-to-leaf
51/// path, so the shape is canonical for an address set and its height is at
52/// most [`usize::BITS`]. Rebuilt paths share every untouched branch Arc with
53/// older PATCH snapshots.
54#[derive(Clone)]
55enum OwnerNode {
56    Owner(Arc<dyn ArchiveOwner>),
57    Branch(Arc<OwnerBranch>),
58}
59
60struct OwnerBranch {
61    mask: usize,
62    zero: OwnerNode,
63    one: OwnerNode,
64}
65
66/// Exact persistent set of archive allocations retained by one PATCH.
67///
68/// Membership is keyed by an allocation's data address. Each address remains
69/// unavailable for reuse while its owner leaf is present. `latest_address`
70/// keeps repeated archive ingestion O(1) without weakening exact membership
71/// for older owners or repeated diamond unions.
72#[derive(Clone)]
73struct OwnerCover {
74    latest_address: usize,
75    len: usize,
76    root: OwnerNode,
77}
78
79impl core::fmt::Debug for OwnerCover {
80    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81        f.debug_struct("OwnerCover")
82            .field("len", &self.len)
83            .finish()
84    }
85}
86
87impl OwnerNode {
88    #[inline]
89    fn takes_one(address: usize, mask: usize) -> bool {
90        address & mask != 0
91    }
92
93    #[inline]
94    fn critical_mask(left: usize, right: usize) -> usize {
95        let differing = left ^ right;
96        debug_assert_ne!(differing, 0);
97        1usize << (usize::BITS - 1 - differing.leading_zeros())
98    }
99
100    fn matching_owner(&self, address: usize) -> &Arc<dyn ArchiveOwner> {
101        let mut node = self;
102        loop {
103            match node {
104                Self::Owner(owner) => return owner,
105                Self::Branch(branch) => {
106                    node = if Self::takes_one(address, branch.mask) {
107                        &branch.one
108                    } else {
109                        &branch.zero
110                    };
111                }
112            }
113        }
114    }
115
116    #[cfg(any(debug_assertions, test))]
117    fn contains(&self, address: usize) -> bool {
118        OwnerCover::address(self.matching_owner(address)) == address
119    }
120
121    #[cfg(test)]
122    fn same_shape(&self, other: &Self) -> bool {
123        match (self, other) {
124            (Self::Owner(left), Self::Owner(right)) => {
125                OwnerCover::address(left) == OwnerCover::address(right)
126            }
127            (Self::Branch(left), Self::Branch(right)) => {
128                left.mask == right.mask
129                    && left.zero.same_shape(&right.zero)
130                    && left.one.same_shape(&right.one)
131            }
132            _ => false,
133        }
134    }
135
136    /// Persistently insert one owner, returning the unchanged root on a hit.
137    fn insert(&self, owner: &Arc<dyn ArchiveOwner>) -> (Self, bool) {
138        let address = OwnerCover::address(owner);
139        let matching = self.matching_owner(address);
140        let existing_address = OwnerCover::address(matching);
141        if existing_address == address {
142            debug_assert!(Arc::ptr_eq(matching, owner));
143            return (self.clone(), false);
144        }
145
146        let critical_mask = Self::critical_mask(address, existing_address);
147        (
148            Self::insert_at(
149                self,
150                Self::Owner(owner.clone()),
151                address,
152                existing_address,
153                critical_mask,
154            ),
155            true,
156        )
157    }
158
159    fn insert_at(
160        root: &Self,
161        inserted: Self,
162        inserted_address: usize,
163        existing_address: usize,
164        critical_mask: usize,
165    ) -> Self {
166        if let Self::Branch(branch) = root {
167            if branch.mask > critical_mask {
168                if Self::takes_one(inserted_address, branch.mask) {
169                    return Self::Branch(Arc::new(OwnerBranch {
170                        mask: branch.mask,
171                        zero: branch.zero.clone(),
172                        one: Self::insert_at(
173                            &branch.one,
174                            inserted,
175                            inserted_address,
176                            existing_address,
177                            critical_mask,
178                        ),
179                    }));
180                }
181                return Self::Branch(Arc::new(OwnerBranch {
182                    mask: branch.mask,
183                    zero: Self::insert_at(
184                        &branch.zero,
185                        inserted,
186                        inserted_address,
187                        existing_address,
188                        critical_mask,
189                    ),
190                    one: branch.one.clone(),
191                }));
192            }
193            debug_assert_ne!(branch.mask, critical_mask);
194        }
195
196        debug_assert_ne!(
197            Self::takes_one(inserted_address, critical_mask),
198            Self::takes_one(existing_address, critical_mask),
199        );
200        let (zero, one) = if Self::takes_one(inserted_address, critical_mask) {
201            (root.clone(), inserted)
202        } else {
203            (inserted, root.clone())
204        };
205        Self::Branch(Arc::new(OwnerBranch {
206            mask: critical_mask,
207            zero,
208            one,
209        }))
210    }
211
212    fn for_each_owner<F>(&self, f: &mut F)
213    where
214        F: FnMut(&Arc<dyn ArchiveOwner>),
215    {
216        match self {
217            Self::Owner(owner) => f(owner),
218            Self::Branch(branch) => {
219                branch.zero.for_each_owner(f);
220                branch.one.for_each_owner(f);
221            }
222        }
223    }
224}
225
226impl OwnerCover {
227    #[inline]
228    fn address(owner: &Arc<dyn ArchiveOwner>) -> usize {
229        Arc::as_ptr(owner) as *const () as usize
230    }
231
232    fn singleton(owner: &Arc<dyn ArchiveOwner>) -> Arc<Self> {
233        Arc::new(Self {
234            latest_address: Self::address(owner),
235            len: 1,
236            root: OwnerNode::Owner(owner.clone()),
237        })
238    }
239
240    fn retain(current: &mut Option<Arc<Self>>, owner: &Arc<dyn ArchiveOwner>) {
241        let address = Self::address(owner);
242        let Some(existing) = current.as_mut() else {
243            *current = Some(Self::singleton(owner));
244            return;
245        };
246        if existing.latest_address == address {
247            return;
248        }
249
250        // Finish the persistent path before publishing it. A caught allocation
251        // panic therefore leaves the installed lifetime receipt unchanged.
252        let (root, inserted) = existing.root.insert(owner);
253        let cover = Arc::make_mut(existing);
254        cover.root = root;
255        cover.len += usize::from(inserted);
256        cover.latest_address = address;
257    }
258
259    /// Transactionally replace `current` with its exact union with `other`.
260    fn merge_into(current: &mut Option<Arc<Self>>, other: &Option<Arc<Self>>) {
261        *current = Self::union(current.clone(), other);
262    }
263
264    fn union(left: Option<Arc<Self>>, right: &Option<Arc<Self>>) -> Option<Arc<Self>> {
265        let Some(right) = right.as_ref() else {
266            return left;
267        };
268        let Some(left) = left else {
269            return Some(right.clone());
270        };
271        if Arc::ptr_eq(&left, right) {
272            return Some(left);
273        }
274
275        // Insert the smaller exact set into the larger. The canonical Patricia
276        // shape makes the result independent of this directional choice.
277        let (mut result, additions) = if left.len >= right.len {
278            (left.clone(), right)
279        } else {
280            (right.clone(), &left)
281        };
282        additions.root.for_each_owner(&mut |owner| {
283            let (root, inserted) = result.root.insert(owner);
284            if inserted {
285                let cover = Arc::make_mut(&mut result);
286                cover.root = root;
287                cover.len += 1;
288            }
289        });
290        if result.latest_address != right.latest_address {
291            Arc::make_mut(&mut result).latest_address = right.latest_address;
292        }
293        Some(result)
294    }
295
296    /// Exact subset check for auditing unsafe cover replacement in debug
297    /// builds. Production callers rely on the construction proof documented
298    /// at [`PATCH::set_owner_guard`].
299    #[cfg(debug_assertions)]
300    fn covers(&self, covered: &Self) -> bool {
301        if self.len < covered.len {
302            return false;
303        }
304        let mut covers = true;
305        covered.root.for_each_owner(&mut |owner| {
306            covers &= self.root.contains(Self::address(owner));
307        });
308        covers
309    }
310}
311
312// Keep the intended structural cost visible. Owner leaves live inline; only
313// Patricia branches and the outer cover allocate.
314#[cfg(target_pointer_width = "64")]
315const _: () = {
316    assert!(std::mem::size_of::<OwnerNode>() == 2 * std::mem::size_of::<usize>());
317    assert!(std::mem::size_of::<OwnerBranch>() == 5 * std::mem::size_of::<usize>());
318    assert!(std::mem::size_of::<OwnerCover>() == 4 * std::mem::size_of::<usize>());
319};
320
321/// Opaque lifetime receipt for archive-backed PATCH leaves.
322///
323/// Aggregate structures can exactly deduplicate retained provenance, add one
324/// archive owner, and install a proved conservative superset. Trie Heads and
325/// concrete Patricia nodes remain private to PATCH.
326#[derive(Clone, Debug, Default)]
327pub(crate) struct PATCHOwnerGuard(Option<Arc<OwnerCover>>);
328
329impl PATCHOwnerGuard {
330    /// Retain the exact deduplicated union of owners in both receipts.
331    pub(crate) fn join(self, other: Self) -> Self {
332        Self(OwnerCover::union(self.0, &other.0))
333    }
334
335    /// Add one archive allocation before any LocalLeaf into it is installed.
336    pub(crate) fn retain_archive_owner(&mut self, owner: &Arc<dyn ArchiveOwner>) {
337        OwnerCover::retain(&mut self.0, owner);
338    }
339
340    #[cfg(debug_assertions)]
341    fn covers(&self, current: &Option<Arc<OwnerCover>>) -> bool {
342        let Some(current) = current else {
343            return true;
344        };
345        let Some(replacement) = self.0.as_ref() else {
346            return false;
347        };
348        Arc::ptr_eq(current, replacement) || replacement.covers(current)
349    }
350
351    #[cfg(test)]
352    pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
353        match (&self.0, &other.0) {
354            (None, None) => true,
355            (Some(left), Some(right)) => Arc::ptr_eq(left, right),
356            _ => false,
357        }
358    }
359
360    #[cfg(test)]
361    pub(crate) fn owner_count(&self) -> usize {
362        self.0.as_ref().map_or(0, |cover| cover.len)
363    }
364}
365
366#[cfg(not(target_pointer_width = "64"))]
367compile_error!("PATCH tagged pointers require 64-bit targets");
368
369struct HashKeys {
370    leaf: [u8; 16],
371    exported_fingerprint: [u8; 16],
372}
373
374static HASH_KEYS: OnceLock<HashKeys> = OnceLock::new();
375
376mod sealed {
377    pub trait Sealed {}
378}
379
380/// Hash-maintenance policy used by [`PATCH`].
381///
382/// Implementations are sealed because PATCH treats equal subtree summaries as
383/// equal key sets in `Eq`, union, intersection, and difference. An invalid
384/// implementation would therefore be a semantic data-loss bug rather than a
385/// merely weak cache hint.
386pub trait PatchHash: sealed::Sealed + Send + Sync + 'static {
387    /// Cached summary stored in every heap leaf and branch.
388    type Digest: Copy + core::fmt::Debug + Eq + Send + Sync + 'static;
389
390    /// Incremental state used while summarizing one branch's children.
391    type BranchState;
392
393    /// Whether child summaries form a commutative branch aggregate.
394    ///
395    /// Commutative policies can scan the physical cuckoo table directly;
396    /// ordered policies are fed children by ascending edge byte.
397    const COMMUTATIVE_BRANCH: bool;
398
399    /// Whether [`Self::edit_branch`] provides an exact updated digest.
400    /// False lets PATCH compile the edit call out and rebuild once on editor
401    /// drop; true keeps the default edit path identical to its direct
402    /// algebraic update.
403    const INCREMENTAL_BRANCH: bool;
404
405    /// Initialize any process-local state required by this policy.
406    fn init();
407
408    /// Summarize one complete key. Associated values never participate.
409    fn leaf(bytes: &[u8]) -> Self::Digest;
410
411    /// Begin summarizing a canonical branch.
412    ///
413    /// `representative` is any descendant key. `tree_to_key` identifies the
414    /// first `end_depth` bytes that form the branch's canonical compressed
415    /// prefix; bytes after that prefix must not affect the summary.
416    fn begin_branch(
417        representative: &[u8],
418        tree_to_key: &[usize],
419        end_depth: usize,
420        child_count: usize,
421        leaf_count: u64,
422    ) -> Self::BranchState;
423
424    /// Add one child in ascending edge-byte order.
425    fn push_child(state: &mut Self::BranchState, edge: u8, leaf_count: u64, digest: Self::Digest);
426
427    /// Finish one branch summary.
428    fn finish_branch(state: Self::BranchState) -> Self::Digest;
429
430    /// Update a branch summary after one child edit.
431    ///
432    /// PATCH calls this only when [`Self::INCREMENTAL_BRANCH`] is true, which
433    /// is a sealed-trait promise that this operation is exact.
434    fn edit_branch(
435        current: Self::Digest,
436        edge: u8,
437        old: Option<Self::Digest>,
438        new: Option<Self::Digest>,
439    ) -> Self::Digest;
440}
441
442/// PATCH's default process-private SipHash-leaf/XOR summary policy.
443///
444/// Its raw aggregates remain crate-private. [`TribleSetFingerprint`](
445/// crate::trible::TribleSetFingerprint) exposes only the separately keyed,
446/// nonlinear blinding of a root aggregate.
447#[derive(Clone, Copy, Debug, Default)]
448pub struct XorSip128;
449
450impl sealed::Sealed for XorSip128 {}
451
452impl PatchHash for XorSip128 {
453    type Digest = u128;
454    type BranchState = u128;
455    const COMMUTATIVE_BRANCH: bool = true;
456    const INCREMENTAL_BRANCH: bool = true;
457
458    #[inline]
459    fn init() {
460        init_hash_keys();
461    }
462
463    #[inline]
464    fn leaf(bytes: &[u8]) -> Self::Digest {
465        xor_hash_leaf_bytes(bytes)
466    }
467
468    #[inline]
469    fn begin_branch(
470        _representative: &[u8],
471        _tree_to_key: &[usize],
472        _end_depth: usize,
473        _child_count: usize,
474        _leaf_count: u64,
475    ) -> Self::BranchState {
476        0
477    }
478
479    #[inline]
480    fn push_child(
481        state: &mut Self::BranchState,
482        _edge: u8,
483        _leaf_count: u64,
484        digest: Self::Digest,
485    ) {
486        *state ^= digest;
487    }
488
489    #[inline]
490    fn finish_branch(state: Self::BranchState) -> Self::Digest {
491        state
492    }
493
494    #[inline]
495    fn edit_branch(
496        mut current: Self::Digest,
497        _edge: u8,
498        old: Option<Self::Digest>,
499        new: Option<Self::Digest>,
500    ) -> Self::Digest {
501        if let Some(old) = old {
502            current ^= old;
503        }
504        if let Some(new) = new {
505            current ^= new;
506        }
507        current
508    }
509}
510
511/// Canonical BLAKE3 Merkle summaries for durable or adversarial PATCH uses.
512///
513/// Unlike [`XorSip128`], this policy commits to the canonical Patricia-trie
514/// structure: leaf keys are domain-separated from branches, and every branch
515/// commits to its key width, compressed-path bytes, fanout, subtree leaf
516/// count, and each ascending `(edge, child leaf count, child digest)` tuple.
517/// PATCH's trie shape is a function of its key set, so insertion order and
518/// cuckoo-table placement do not affect the result.
519///
520/// BLAKE3's native chunk tree is intentionally not reused here. Its tree
521/// describes fixed-size chunks of one byte stream, whereas PATCH is a sparse
522/// radix tree whose fanout and compressed depths change under edits. Branches
523/// are therefore framed explicitly and hashed with the ordinary streaming
524/// API.
525#[derive(Clone, Copy, Debug, Default)]
526pub struct Blake3Merkle;
527
528impl sealed::Sealed for Blake3Merkle {}
529
530impl PatchHash for Blake3Merkle {
531    type Digest = [u8; 32];
532    type BranchState = blake3::Hasher;
533    const COMMUTATIVE_BRANCH: bool = false;
534    const INCREMENTAL_BRANCH: bool = false;
535
536    #[inline]
537    fn init() {
538        bytetable::init();
539    }
540
541    fn leaf(bytes: &[u8]) -> Self::Digest {
542        let mut state = blake3::Hasher::new();
543        state.update(b"triblespace.patch.leaf.v1\0");
544        state.update(&(bytes.len() as u64).to_le_bytes());
545        state.update(bytes);
546        *state.finalize().as_bytes()
547    }
548
549    fn begin_branch(
550        representative: &[u8],
551        tree_to_key: &[usize],
552        end_depth: usize,
553        child_count: usize,
554        leaf_count: u64,
555    ) -> Self::BranchState {
556        debug_assert_eq!(representative.len(), tree_to_key.len());
557        debug_assert!(end_depth <= representative.len());
558        let mut state = blake3::Hasher::new();
559        state.update(b"triblespace.patch.branch.v2\0");
560        state.update(&(representative.len() as u64).to_le_bytes());
561        state.update(&(end_depth as u64).to_le_bytes());
562        for &key_index in &tree_to_key[..end_depth] {
563            state.update(&[representative[key_index]]);
564        }
565        state.update(&(child_count as u64).to_le_bytes());
566        state.update(&leaf_count.to_le_bytes());
567        state
568    }
569
570    #[inline]
571    fn push_child(state: &mut Self::BranchState, edge: u8, leaf_count: u64, digest: Self::Digest) {
572        state.update(&[edge]);
573        state.update(&leaf_count.to_le_bytes());
574        state.update(&digest);
575    }
576
577    #[inline]
578    fn finish_branch(state: Self::BranchState) -> Self::Digest {
579        *state.finalize().as_bytes()
580    }
581
582    #[inline]
583    fn edit_branch(
584        _current: Self::Digest,
585        _edge: u8,
586        _old: Option<Self::Digest>,
587        _new: Option<Self::Digest>,
588    ) -> Self::Digest {
589        unreachable!("non-incremental PATCH hash policy was asked to edit a branch")
590    }
591}
592
593/// Fixed input-domain marker for the public
594/// [`TribleSetFingerprint`](crate::trible::TribleSetFingerprint)
595/// blinding PRF.
596///
597/// A distinct random key already separates this use from PATCH leaf hashing;
598/// the marker additionally prevents this output from being confused with a
599/// future use of the same key over an untyped 128-bit value.
600const EXPORTED_FINGERPRINT_DOMAIN: [u8; 16] = *b"TribleSet.fp.v1\0";
601
602/// Minimum `other.leaf_count` at which [`Head::par_union`] takes the
603/// scatter + bitset + rayon::scope-spawn path on the equal-depth-
604/// branch arm. Below this, the per-key `modify_child` loop wins
605/// because asymmetric merges only touch a handful of slots.
606#[cfg(feature = "parallel")]
607const PARALLEL_PATCH_UNION_THRESHOLD: usize = 4096;
608
609/// Parallel-aware PATCH union, with a shared work-stealing budget
610/// carried across the entire recursive descent.
611///
612/// Two-phase model per parallel call:
613///   1. Spawn phase (collect sequentially, dispatch per child):
614///      drain "both" pairs, for each: claim 1 unit from the
615///      shared budget — if successful, spawn the child union as
616///      a `rayon::scope` task; if budget is exhausted, run the
617///      child serially via `Head::union`.
618///   2. Install phase (purely serial): scatter-collected resolved
619///      heads + single-side pass-throughs land in the parent
620///      branch, then `recompute_aggregates` rebuilds the
621///      hash/leaf_count/segment_count/childleaf in one pass.
622///
623/// The budget is a single shared atomic — `num_threads²` total
624/// spawns across the entire descent, after which everything is
625/// sequential. This caps overhead without restricting the depth
626/// at which parallelism is reached: a heavy subtree near the
627/// root claims many units; a balanced descent spreads them.
628#[cfg(feature = "parallel")]
629mod parallel_union {
630    use core::sync::atomic::{AtomicUsize, Ordering};
631
632    /// Carries the shared spawn budget across recursive
633    /// `par_union_with_ctx` calls.
634    pub(crate) struct ParUnionCtx {
635        pub(crate) budget: AtomicUsize,
636    }
637
638    impl ParUnionCtx {
639        pub(crate) fn new() -> Self {
640            let n = rayon::current_num_threads();
641            Self {
642                budget: AtomicUsize::new(n.saturating_mul(n).max(2)),
643            }
644        }
645
646        /// Try to claim one spawn unit. Returns `true` if a unit was
647        /// claimed (caller should spawn), `false` if the budget was
648        /// already exhausted (caller should run serially).
649        ///
650        /// A naive `fetch_sub(1)` would wrap `0 → usize::MAX` on
651        /// over-subtract, briefly letting other threads see a huge
652        /// budget — so we use compare-exchange to refuse the claim
653        /// without ever observing the underflow.
654        pub(crate) fn try_claim(&self) -> bool {
655            let mut current = self.budget.load(Ordering::Relaxed);
656            loop {
657                if current == 0 {
658                    return false;
659                }
660                match self.budget.compare_exchange_weak(
661                    current,
662                    current - 1,
663                    Ordering::Relaxed,
664                    Ordering::Relaxed,
665                ) {
666                    Ok(_) => return true,
667                    Err(observed) => current = observed,
668                }
669            }
670        }
671    }
672
673    /// Raw-pointer wrapper for the scatter-write target. Each
674    /// spawned task writes to `resolved[k]` for its specific key
675    /// byte `k`; keys are pairwise distinct by construction (each
676    /// "both" bit in the partition uniquely identifies a slot), so
677    /// the writes are non-aliasing despite sharing a `*mut` across
678    /// threads.
679    ///
680    /// `write_at` exists as an inherent method (rather than callers
681    /// reading the `*mut` field directly) so that move closures
682    /// capture the whole wrapper — Rust 2021 precise-capture would
683    /// otherwise grab the raw pointer field, dropping the manual
684    /// `Send`/`Sync` impls and triggering a Send error.
685    pub(crate) struct ScatterPtr<T>(pub *mut T);
686
687    // Manual `Copy`/`Clone` impls so `T` doesn't get a spurious
688    // `T: Copy` / `T: Clone` bound from derive — the wrapper holds a
689    // raw pointer, which is always `Copy` regardless of `T`.
690    impl<T> Clone for ScatterPtr<T> {
691        fn clone(&self) -> Self {
692            *self
693        }
694    }
695    impl<T> Copy for ScatterPtr<T> {}
696
697    // SAFETY: tasks only transfer owned `T` values into pairwise-disjoint
698    // output slots. The wrapper never exposes a reference to a stored `T`, so
699    // moving those values between threads requires `T: Send`, not `T: Sync`.
700    unsafe impl<T: Send> Send for ScatterPtr<T> {}
701    unsafe impl<T: Send> Sync for ScatterPtr<T> {}
702
703    impl<T> ScatterPtr<T> {
704        /// SAFETY: `i` must be in-bounds of the underlying buffer,
705        /// and the caller must guarantee no other thread is writing
706        /// to slot `i` concurrently.
707        pub(crate) unsafe fn write_at(self, i: usize, v: T) {
708            self.0.add(i).write(v);
709        }
710    }
711}
712
713/// Return the immutable process-local PATCH hash-key bundle, initializing all
714/// randomness PATCH construction relies on exactly once.
715fn hash_keys() -> &'static HashKeys {
716    HASH_KEYS.get_or_init(|| {
717        bytetable::init();
718
719        let mut rng = thread_rng();
720        let mut leaf = [0u8; 16];
721        let mut exported_fingerprint = [0u8; 16];
722        rng.fill_bytes(&mut leaf);
723        // Make key separation exact rather than adding a second, avoidable
724        // 2^-128 assumption to the public-boundary argument.
725        loop {
726            rng.fill_bytes(&mut exported_fingerprint);
727            if exported_fingerprint != leaf {
728                break;
729            }
730        }
731        HashKeys {
732            leaf,
733            exported_fingerprint,
734        }
735    })
736}
737
738/// Initialize PATCH's process-local hash and byte-table randomness.
739///
740/// Hashing entry points also call [`hash_keys`] themselves, so safe `Entry`
741/// construction before the first [`PATCH`] cannot observe an uninitialized
742/// key.
743pub(crate) fn init_hash_keys() {
744    let _ = hash_keys();
745}
746
747/// Hash one PATCH leaf through the initialized process-local key accessor.
748#[inline]
749fn xor_hash_leaf_bytes(bytes: &[u8]) -> u128 {
750    use siphasher::sip128::SipHasher24;
751
752    SipHasher24::new_with_key(&hash_keys().leaf)
753        .hash(bytes)
754        .into()
755}
756
757/// Apply the public-fingerprint PRF under an explicit key.
758///
759/// Keeping this transformation separate makes the proof boundary visible:
760/// PATCH's internal aggregate is linear, while values crossing the public API
761/// pass through this nonlinear keyed function first.
762#[inline]
763fn blind_root_hash_with_key(root_hash: u128, key: &[u8; 16]) -> u128 {
764    use siphasher::sip128::SipHasher24;
765
766    let mut input = [0u8; 32];
767    input[..16].copy_from_slice(&EXPORTED_FINGERPRINT_DOMAIN);
768    input[16..].copy_from_slice(&root_hash.to_le_bytes());
769    SipHasher24::new_with_key(key).hash(&input).into()
770}
771
772/// Blind PATCH's internal root aggregate for public, process-local cache keys.
773///
774/// The raw root is an XOR of keyed leaf hashes and must not be exposed: chosen
775/// singleton outputs would reveal vectors from which a linear dependency can
776/// be constructed. This distinct-key, domain-separated PRF preserves equality
777/// within the process without exposing that algebra. `None` remains the unique
778/// empty-set representation.
779#[inline]
780pub(crate) fn blind_root_hash(root_hash: Option<u128>) -> Option<u128> {
781    let root_hash = root_hash?;
782    Some(blind_root_hash_with_key(
783        root_hash,
784        &hash_keys().exported_fingerprint,
785    ))
786}
787
788/// Hash one PATCH key with the process-local internal leaf key.
789///
790/// Bulk archive construction calls this once per source row and shares the
791/// result across all six index builds. Initializing here is important because
792/// that path hashes before it constructs its first [`PATCH`].
793#[cfg(any(test, feature = "parallel"))]
794#[inline]
795pub(crate) fn hash_key(bytes: &[u8]) -> u128 {
796    XorSip128::leaf(bytes)
797}
798
799/// Builds a per-byte segment map from the segment lengths.
800///
801/// The returned table maps each key byte to its segment index.
802pub const fn build_segmentation<const N: usize, const M: usize>(lens: [usize; M]) -> [usize; N] {
803    let mut res = [0; N];
804    let mut seg = 0;
805    let mut off = 0;
806    while seg < M {
807        let len = lens[seg];
808        let mut i = 0;
809        while i < len {
810            res[off + i] = seg;
811            i += 1;
812        }
813        off += len;
814        seg += 1;
815    }
816    res
817}
818
819/// Builds an identity permutation table of length `N`.
820pub const fn identity_map<const N: usize>() -> [usize; N] {
821    let mut res = [0; N];
822    let mut i = 0;
823    while i < N {
824        res[i] = i;
825        i += 1;
826    }
827    res
828}
829
830/// Builds a table translating indices from key order to tree order.
831///
832/// `lens` describes the segment lengths in key order and `perm` is the
833/// permutation of those segments in tree order.
834pub const fn build_key_to_tree<const N: usize, const M: usize>(
835    lens: [usize; M],
836    perm: [usize; M],
837) -> [usize; N] {
838    let mut key_starts = [0; M];
839    let mut off = 0;
840    let mut i = 0;
841    while i < M {
842        key_starts[i] = off;
843        off += lens[i];
844        i += 1;
845    }
846
847    let mut tree_starts = [0; M];
848    off = 0;
849    i = 0;
850    while i < M {
851        let seg = perm[i];
852        tree_starts[seg] = off;
853        off += lens[seg];
854        i += 1;
855    }
856
857    let mut res = [0; N];
858    let mut seg = 0;
859    while seg < M {
860        let len = lens[seg];
861        let ks = key_starts[seg];
862        let ts = tree_starts[seg];
863        let mut j = 0;
864        while j < len {
865            res[ks + j] = ts + j;
866            j += 1;
867        }
868        seg += 1;
869    }
870    res
871}
872
873/// Inverts a permutation table.
874pub const fn invert<const N: usize>(arr: [usize; N]) -> [usize; N] {
875    let mut res = [0; N];
876    let mut i = 0;
877    while i < N {
878        res[arr[i]] = i;
879        i += 1;
880    }
881    res
882}
883
884/// For each tree-depth `d`, the end (exclusive) of the segment that contains
885/// `d`, derived from a segmentation table (in key order) and a tree→key map.
886///
887/// Each logical segment is contiguous in tree order, so the boundary after a
888/// depth is simply the first deeper depth whose segment id differs (or
889/// `KEY_LEN`). Used by [`KeySchema::next_boundary`] / `SEGMENT_ENDS` to cap
890/// variable-width branch spans so they never cross a segment checkpoint.
891pub const fn build_segment_ends<const N: usize>(
892    segments: [usize; N],
893    tree_to_key: [usize; N],
894) -> [usize; N] {
895    let mut ends = [0usize; N];
896    let mut d = 0;
897    while d < N {
898        let seg = segments[tree_to_key[d]];
899        let mut e = d + 1;
900        while e < N && segments[tree_to_key[e]] == seg {
901            e += 1;
902        }
903        ends[d] = e;
904        d += 1;
905    }
906    ends
907}
908
909#[doc(hidden)]
910#[macro_export]
911macro_rules! key_segmentation {
912    (@count $($e:expr),* $(,)?) => {
913        <[()]>::len(&[$($crate::key_segmentation!(@sub $e)),*])
914    };
915    (@sub $e:expr) => { () };
916    ($(#[$meta:meta])* $name:ident, $len:expr, [$($seg_len:expr),+ $(,)?]) => {
917        $(#[$meta])*
918        #[derive(Copy, Clone, Debug)]
919        pub struct $name;
920        impl $name {
921            pub const SEG_LENS: [usize; $crate::key_segmentation!(@count $($seg_len),*)] = [$($seg_len),*];
922        }
923        impl $crate::patch::KeySegmentation<$len> for $name {
924            const SEGMENTS: [usize; $len] = $crate::patch::build_segmentation::<$len, {$crate::key_segmentation!(@count $($seg_len),*)}>(Self::SEG_LENS);
925        }
926    };
927}
928
929#[doc(hidden)]
930#[macro_export]
931macro_rules! key_schema {
932    (@count $($e:expr),* $(,)?) => {
933        <[()]>::len(&[$($crate::key_schema!(@sub $e)),*])
934    };
935    (@sub $e:expr) => { () };
936    ($(#[$meta:meta])* $name:ident, $seg:ty, $len:expr, [$($perm:expr),+ $(,)?]) => {
937        $(#[$meta])*
938        #[derive(Copy, Clone, Debug)]
939        pub struct $name;
940        impl $crate::patch::KeySchema<$len> for $name {
941            type Segmentation = $seg;
942            const SEGMENT_PERM: &'static [usize] = &[$($perm),*];
943            const KEY_TO_TREE: [usize; $len] = $crate::patch::build_key_to_tree::<$len, {$crate::key_schema!(@count $($perm),*)}>(<$seg>::SEG_LENS, [$($perm),*]);
944            const TREE_TO_KEY: [usize; $len] = $crate::patch::invert(Self::KEY_TO_TREE);
945        }
946    };
947}
948
949/// A trait is used to provide a re-ordered view of the keys stored in the PATCH.
950/// This allows for different PATCH instances share the same leaf nodes,
951/// independent of the key ordering used in the tree.
952pub trait KeySchema<const KEY_LEN: usize>: Copy + Clone + Debug {
953    /// The segmentation this ordering operates over.
954    type Segmentation: KeySegmentation<KEY_LEN>;
955    /// Order of segments from key layout to tree layout.
956    const SEGMENT_PERM: &'static [usize];
957    /// Maps each key index to its position in the tree view.
958    const KEY_TO_TREE: [usize; KEY_LEN];
959    /// Maps each tree index to its position in the key view.
960    const TREE_TO_KEY: [usize; KEY_LEN];
961
962    /// For each tree-depth, the exclusive end of the segment containing it.
963    ///
964    /// Purely additive (a provided default derived from `Segmentation` +
965    /// `TREE_TO_KEY`); it does not affect single-byte PATCH behaviour. A
966    /// variable-width trie would use it to start branch spans segment-wide and
967    /// guarantee a span never crosses a checkpoint. For EAV over a 64-byte
968    /// trible this yields ends `{16,32,64}`; for VEA `{32,48,64}`.
969    const SEGMENT_ENDS: [usize; KEY_LEN] = build_segment_ends::<KEY_LEN>(
970        <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS,
971        Self::TREE_TO_KEY,
972    );
973
974    /// The exclusive end of the segment containing tree-depth `tree_depth`.
975    ///
976    /// A variable-width branch starting at `span_start` may widen its span up
977    /// to `next_boundary(span_start)` but no further, so each branch stays
978    /// within a single segment.
979    fn next_boundary(tree_depth: usize) -> usize {
980        Self::SEGMENT_ENDS[tree_depth]
981    }
982
983    /// Reorders the key from the shared key ordering to the tree ordering.
984    fn tree_ordered(key: &[u8; KEY_LEN]) -> [u8; KEY_LEN] {
985        let mut new_key = [0; KEY_LEN];
986        let mut i = 0;
987        while i < KEY_LEN {
988            new_key[Self::KEY_TO_TREE[i]] = key[i];
989            i += 1;
990        }
991        new_key
992    }
993
994    /// Reorders the key from the tree ordering to the shared key ordering.
995    fn key_ordered(tree_key: &[u8; KEY_LEN]) -> [u8; KEY_LEN] {
996        let mut new_key = [0; KEY_LEN];
997        let mut i = 0;
998        while i < KEY_LEN {
999            new_key[Self::TREE_TO_KEY[i]] = tree_key[i];
1000            i += 1;
1001        }
1002        new_key
1003    }
1004
1005    /// Return the segment index for the byte at `at_depth` in tree ordering.
1006    ///
1007    /// Default implementation reads the static segmentation table and the
1008    /// tree->key mapping. Having this as a method makes call sites clearer and
1009    /// reduces the verbosity of expressions that access the segmentation table.
1010    fn segment_of_tree_depth(at_depth: usize) -> usize {
1011        <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[at_depth]]
1012    }
1013
1014    /// Return true if the tree-ordered bytes at `a` and `b` belong to the same
1015    /// logical segment.
1016    fn same_segment_tree(a: usize, b: usize) -> bool {
1017        <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[a]]
1018            == <Self::Segmentation as KeySegmentation<KEY_LEN>>::SEGMENTS[Self::TREE_TO_KEY[b]]
1019    }
1020}
1021
1022/// This trait is used to segment keys stored in the PATCH.
1023/// The segmentation is used to determine sub-fields of the key,
1024/// allowing for segment based operations, like counting the number
1025/// of elements in a segment with a given prefix without traversing the tree.
1026///
1027/// Note that the segmentation is defined on the shared key ordering,
1028/// and should thus be only implemented once, independent of additional key orderings.
1029///
1030/// See [TribleSegmentation](crate::trible::TribleSegmentation) for an example that segments keys into entity,
1031/// attribute, and value segments.
1032pub trait KeySegmentation<const KEY_LEN: usize>: Copy + Clone + Debug {
1033    /// Segment index for each position in the key.
1034    const SEGMENTS: [usize; KEY_LEN];
1035}
1036
1037/// A `KeySchema` that does not reorder the keys.
1038/// This is useful for keys that are already ordered in the desired way.
1039/// This is the default ordering.
1040#[derive(Copy, Clone, Debug)]
1041pub struct IdentitySchema {}
1042
1043/// A `KeySegmentation` that does not segment the keys.
1044/// This is useful for keys that do not have a segment structure.
1045/// This is the default segmentation.
1046#[derive(Copy, Clone, Debug)]
1047pub struct SingleSegmentation {}
1048impl<const KEY_LEN: usize> KeySchema<KEY_LEN> for IdentitySchema {
1049    type Segmentation = SingleSegmentation;
1050    const SEGMENT_PERM: &'static [usize] = &[0];
1051    const KEY_TO_TREE: [usize; KEY_LEN] = identity_map::<KEY_LEN>();
1052    const TREE_TO_KEY: [usize; KEY_LEN] = identity_map::<KEY_LEN>();
1053}
1054
1055impl<const KEY_LEN: usize> KeySegmentation<KEY_LEN> for SingleSegmentation {
1056    const SEGMENTS: [usize; KEY_LEN] = [0; KEY_LEN];
1057}
1058
1059#[allow(dead_code)]
1060#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
1061#[repr(u8)]
1062pub(crate) enum HeadTag {
1063    // Stored in the low 4 bits of `Head::tptr` (see Head::new).
1064    //
1065    // Branch values encode log2(branch_size) (i.e. `Branch2 == 1`, `Branch256
1066    // == 8`). `0` is reserved for leaf nodes, which lets us compute the branch
1067    // size as `1 << tag` without any offset. The derived `Ord` therefore
1068    // compares branch sizes — `tag_a > tag_b` ⟺ `size_a > size_b`, and the
1069    // 2× swap threshold reduces to a single tag-byte compare.
1070    //
1071    // `LocalLeaf` (9) is appended at the end so the Branch widths' `1 << tag`
1072    // arithmetic and the Leaf-vs-Branch threshold comparisons are unaffected.
1073    // It represents a leaf whose key bytes live in an archive's mmap'd buffer,
1074    // referenced via a thin pointer in the Head body slot rather than via a
1075    // heap-allocated `Leaf<KEY_LEN, V>`. Lifetime is guaranteed by the exact
1076    // owner set on the enclosing PATCH value.
1077    Leaf = 0,
1078    Branch2 = 1,
1079    Branch4 = 2,
1080    Branch8 = 3,
1081    Branch16 = 4,
1082    Branch32 = 5,
1083    Branch64 = 6,
1084    Branch128 = 7,
1085    Branch256 = 8,
1086    LocalLeaf = 9,
1087}
1088
1089impl HeadTag {
1090    #[inline]
1091    fn from_raw(raw: u8) -> Self {
1092        debug_assert!(raw <= HeadTag::LocalLeaf as u8);
1093        // SAFETY: `HeadTag` is `#[repr(u8)]` with a contiguous discriminant
1094        // range 0..=9. The tag bits are written by Head::new/set_body and
1095        // Branch::tag, which only emit valid discriminants.
1096        unsafe { std::mem::transmute(raw) }
1097    }
1098}
1099
1100pub(crate) enum BodyPtr<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> {
1101    Leaf(NonNull<Leaf<KEY_LEN, V, H>>),
1102    /// Thin pointer to a `[u8; KEY_LEN]` trible living in an archive's
1103    /// mmap'd buffer. Lifetime is implicit — guaranteed by the enclosing
1104    /// PATCH's owner set.
1105    LocalLeaf(NonNull<[u8; KEY_LEN]>),
1106    Branch(branch::BranchNN<KEY_LEN, O, V, H>),
1107}
1108
1109/// Immutable borrow view of a Head body.
1110/// Returned by `body_ref()` and tied to the lifetime of the `&Head`.
1111pub(crate) enum BodyRef<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> {
1112    Leaf(&'a Leaf<KEY_LEN, V, H>),
1113    /// Reference to a trible's bytes within an archive. The slice's
1114    /// lifetime is bound to `&'a Head` via the body pointer; the actual
1115    /// underlying allocation is kept alive by the enclosing PATCH.
1116    LocalLeaf(&'a [u8; KEY_LEN]),
1117    Branch(&'a Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V, H>>], V, H>),
1118}
1119
1120/// Mutation-capable borrow view of a Head body.
1121/// Returned by `body_mut()` and tied to the lifetime of the `&mut Head`.
1122///
1123/// Branches are copy-on-write and therefore unique before this view exposes
1124/// them mutably. Heap leaves, like archive-local leaves, may still be shared
1125/// by another PATCH snapshot, so both leaf variants are exposed read-only.
1126pub(crate) enum BodyMut<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> {
1127    Leaf(&'a Leaf<KEY_LEN, V, H>),
1128    /// `LocalLeaf` is read-only by construction (it points into immutable
1129    /// archive bytes), so the mutable view yields a shared reference.
1130    /// Structural operations may move the Head while its PATCH owner guard
1131    /// remains live.
1132    LocalLeaf(&'a [u8; KEY_LEN]),
1133    Branch(&'a mut Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V, H>>], V, H>),
1134}
1135
1136pub(crate) trait Body {
1137    fn tag(body: NonNull<Self>) -> HeadTag;
1138}
1139
1140#[repr(C)]
1141pub(crate) struct Head<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash = XorSip128> {
1142    tptr: std::ptr::NonNull<u8>,
1143    key_ordering: PhantomData<O>,
1144    key_segments: PhantomData<O::Segmentation>,
1145    value: PhantomData<V>,
1146    hash_policy: PhantomData<H>,
1147}
1148
1149// SAFETY: a Head owns a persistent, atomically reference-counted node. Cloned
1150// Heads may expose the same Leaf<V> on different threads, and the final owner
1151// may drop V on either thread, so both auto traits require V: Send + Sync.
1152// O and O::Segmentation are ignored deliberately: they are type-level schemas
1153// used only through associated constants and functions; no value or reference
1154// of either type is stored in, or accessed through, a Head.
1155unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V: Send + Sync, H: PatchHash> Send
1156    for Head<KEY_LEN, O, V, H>
1157{
1158}
1159
1160// SAFETY: the same shared-leaf and type-level-schema argument above applies.
1161unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V: Send + Sync, H: PatchHash> Sync
1162    for Head<KEY_LEN, O, V, H>
1163{
1164}
1165
1166impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Head<KEY_LEN, O, V, H> {
1167    // Tagged pointer layout (64-bit only):
1168    // - bits 0..=3:   HeadTag (requires 16-byte aligned bodies)
1169    // - bits 4..=55:  body pointer bits (52 bits)
1170    // - bits 56..=63: key byte for cuckoo table lookup
1171    const TAG_MASK: u64 = 0x0f;
1172    const BODY_MASK: u64 = 0x00_ff_ff_ff_ff_ff_ff_f0;
1173    const KEY_MASK: u64 = 0xff_00_00_00_00_00_00_00;
1174
1175    pub(crate) fn new<T: Body + ?Sized>(key: u8, body: NonNull<T>) -> Self {
1176        unsafe {
1177            let tptr =
1178                std::ptr::NonNull::new_unchecked((body.as_ptr() as *mut u8).map_addr(|addr| {
1179                    debug_assert_eq!(addr as u64 & Self::TAG_MASK, 0);
1180                    ((addr as u64 & Self::BODY_MASK)
1181                        | ((key as u64) << 56)
1182                        | (<T as Body>::tag(body) as u64)) as usize
1183                }));
1184            Self {
1185                tptr,
1186                key_ordering: PhantomData,
1187                key_segments: PhantomData,
1188                value: PhantomData,
1189                hash_policy: PhantomData,
1190            }
1191        }
1192    }
1193
1194    /// Constructs a `LocalLeaf` Head pointing directly at a `[u8; KEY_LEN]`
1195    /// trible inside an archive's mmap'd buffer. The pointer's address must
1196    /// be 16-byte aligned (so the low 4 bits are free for the `HeadTag`);
1197    /// for `SimpleArchive` buffers this holds whenever the base allocation
1198    /// is 16-byte aligned and tribles are 64 bytes wide (every offset is a
1199    /// multiple of 16).
1200    ///
1201    /// # Safety
1202    /// - `trible_ptr` must remain valid for at least as long as this Head
1203    ///   exists, which is the caller's responsibility to arrange — typically
1204    ///   by retaining its `Arc<dyn ArchiveOwner>` in the enclosing PATCH's
1205    ///   root owner set.
1206    /// - The pointed-to bytes must remain fully initialized and immutable for
1207    ///   that lifetime, including through concurrent aliases or interior
1208    ///   mutability. LocalLeaf routing and fingerprints read them through
1209    ///   shared references.
1210    /// - The pointer must be 16-byte aligned; this is debug-asserted.
1211    pub(crate) unsafe fn new_local_leaf(key: u8, trible_ptr: NonNull<[u8; KEY_LEN]>) -> Self {
1212        unsafe {
1213            let tptr = std::ptr::NonNull::new_unchecked((trible_ptr.as_ptr() as *mut u8).map_addr(
1214                |addr| {
1215                    debug_assert_eq!(
1216                        addr as u64 & Self::TAG_MASK,
1217                        0,
1218                        "LocalLeaf trible pointer must be 16-byte aligned"
1219                    );
1220                    ((addr as u64 & Self::BODY_MASK)
1221                        | ((key as u64) << 56)
1222                        | (HeadTag::LocalLeaf as u64)) as usize
1223                },
1224            ));
1225            Self {
1226                tptr,
1227                key_ordering: PhantomData,
1228                key_segments: PhantomData,
1229                value: PhantomData,
1230                hash_policy: PhantomData,
1231            }
1232        }
1233    }
1234
1235    #[inline]
1236    pub(crate) fn tag(&self) -> HeadTag {
1237        HeadTag::from_raw((self.tptr.as_ptr() as u64 & Self::TAG_MASK) as u8)
1238    }
1239
1240    #[inline]
1241    pub(crate) fn key(&self) -> u8 {
1242        (self.tptr.as_ptr() as u64 >> 56) as u8
1243    }
1244
1245    #[inline]
1246    pub(crate) fn with_key(mut self, key: u8) -> Self {
1247        self.tptr =
1248            std::ptr::NonNull::new(self.tptr.as_ptr().map_addr(|addr| {
1249                ((addr as u64 & !Self::KEY_MASK) | ((key as u64) << 56)) as usize
1250            }))
1251            .unwrap();
1252        self
1253    }
1254
1255    #[inline]
1256    pub(crate) fn set_body<T: Body + ?Sized>(&mut self, body: NonNull<T>) {
1257        unsafe {
1258            self.tptr = NonNull::new_unchecked((body.as_ptr() as *mut u8).map_addr(|addr| {
1259                debug_assert_eq!(addr as u64 & Self::TAG_MASK, 0);
1260                ((addr as u64 & Self::BODY_MASK)
1261                    | (self.tptr.as_ptr() as u64 & Self::KEY_MASK)
1262                    | (<T as Body>::tag(body) as u64)) as usize
1263            }))
1264        }
1265    }
1266
1267    pub(crate) fn with_start(self, new_start_depth: usize) -> Head<KEY_LEN, O, V, H> {
1268        let leaf_key = self.childleaf_key();
1269        let i = O::TREE_TO_KEY[new_start_depth];
1270        let key = leaf_key[i];
1271        self.with_key(key)
1272    }
1273
1274    // Removed childleaf_matches_key_from in favor of composing the existing
1275    // has_prefix primitives directly at call sites. Use
1276    // `self.has_prefix::<KEY_LEN>(at_depth, key)` or for partial checks
1277    // `self.childleaf().has_prefix::<O>(at_depth, &key[..limit])` instead.
1278
1279    pub(crate) fn body(&self) -> BodyPtr<KEY_LEN, O, V, H> {
1280        unsafe {
1281            let ptr = NonNull::new_unchecked(self.tptr.as_ptr().map_addr(|addr| {
1282                let masked = (addr as u64) & Self::BODY_MASK;
1283                masked as usize
1284            }));
1285            match self.tag() {
1286                HeadTag::Leaf => BodyPtr::Leaf(ptr.cast()),
1287                HeadTag::LocalLeaf => BodyPtr::LocalLeaf(ptr.cast()),
1288                branch_tag => {
1289                    let count = 1 << (branch_tag as usize);
1290                    BodyPtr::Branch(NonNull::new_unchecked(std::ptr::slice_from_raw_parts(
1291                        ptr.as_ptr(),
1292                        count,
1293                    )
1294                        as *mut Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V, H>>], V, H>))
1295                }
1296            }
1297        }
1298    }
1299
1300    pub(crate) fn body_mut(&mut self) -> BodyMut<'_, KEY_LEN, O, V, H> {
1301        unsafe {
1302            match self.body() {
1303                BodyPtr::Leaf(leaf) => BodyMut::Leaf(leaf.as_ref()),
1304                BodyPtr::LocalLeaf(ptr) => BodyMut::LocalLeaf(ptr.as_ref()),
1305                BodyPtr::Branch(mut branch) => {
1306                    // Ensure ownership: try copy-on-write and update local pointer if needed.
1307                    let mut branch_nn = branch;
1308                    if Branch::rc_cow(&mut branch_nn).is_some() {
1309                        self.set_body(branch_nn);
1310                        BodyMut::Branch(branch_nn.as_mut())
1311                    } else {
1312                        BodyMut::Branch(branch.as_mut())
1313                    }
1314                }
1315            }
1316        }
1317    }
1318
1319    /// Returns an immutable borrow of the body (Leaf, LocalLeaf, or Branch)
1320    /// tied to &self.
1321    pub(crate) fn body_ref(&self) -> BodyRef<'_, KEY_LEN, O, V, H> {
1322        match self.body() {
1323            BodyPtr::Leaf(nn) => BodyRef::Leaf(unsafe { nn.as_ref() }),
1324            BodyPtr::LocalLeaf(nn) => BodyRef::LocalLeaf(unsafe { nn.as_ref() }),
1325            BodyPtr::Branch(nn) => BodyRef::Branch(unsafe { nn.as_ref() }),
1326        }
1327    }
1328
1329    pub(crate) fn count(&self) -> u64 {
1330        match self.body_ref() {
1331            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => 1,
1332            BodyRef::Branch(branch) => branch.leaf_count,
1333        }
1334    }
1335
1336    #[inline]
1337    fn is_archive_singleton_pair(&self, other: &Self) -> bool {
1338        matches!(
1339            (self.tag(), other.tag()),
1340            (HeadTag::LocalLeaf, HeadTag::Leaf | HeadTag::LocalLeaf)
1341                | (HeadTag::Leaf, HeadTag::LocalLeaf)
1342        )
1343    }
1344
1345    /// Returns whether cardinality still permits equal fingerprints when an
1346    /// archive-backed leaf is involved. A `LocalLeaf` represents exactly one
1347    /// key, while a Branch's count is cached; all pairs without a `LocalLeaf`
1348    /// retain the existing fingerprint path unchanged.
1349    #[inline]
1350    fn local_leaf_cardinality_allows_equality(&self, other: &Self) -> bool {
1351        match (self.tag(), other.tag()) {
1352            (HeadTag::LocalLeaf, _) => other.count() == 1,
1353            (_, HeadTag::LocalLeaf) => self.count() == 1,
1354            _ => true,
1355        }
1356    }
1357
1358    pub(crate) fn count_segment(&self, at_depth: usize) -> u64 {
1359        match self.body_ref() {
1360            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => 1,
1361            BodyRef::Branch(branch) => branch.count_segment(at_depth),
1362        }
1363    }
1364
1365    pub(crate) fn hash(&self) -> H::Digest {
1366        match self.body_ref() {
1367            BodyRef::Leaf(leaf) => leaf.hash,
1368            BodyRef::LocalLeaf(bytes) => H::leaf(&bytes[..]),
1369            BodyRef::Branch(branch) => branch.hash,
1370        }
1371    }
1372
1373    pub(crate) fn end_depth(&self) -> usize {
1374        match self.body_ref() {
1375            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => KEY_LEN,
1376            BodyRef::Branch(branch) => branch.end_depth as usize,
1377        }
1378    }
1379
1380    /// Returns the raw key-bytes pointer of the representative child
1381    /// leaf for use in low-level operations (Branch construction,
1382    /// invariant checks). For heap `Leaf`, that's `&leaf.key`; for
1383    /// `LocalLeaf`, the archive-resident bytes pointer; for `Branch`,
1384    /// the branch's already-computed childleaf pointer.
1385    pub(crate) fn childleaf_ptr(&self) -> *const [u8; KEY_LEN] {
1386        match self.body_ref() {
1387            BodyRef::Leaf(leaf) => &leaf.key as *const [u8; KEY_LEN],
1388            BodyRef::LocalLeaf(bytes) => bytes as *const [u8; KEY_LEN],
1389            BodyRef::Branch(branch) => branch.childleaf_ptr(),
1390        }
1391    }
1392
1393    pub(crate) fn childleaf_key(&self) -> &[u8; KEY_LEN] {
1394        match self.body_ref() {
1395            BodyRef::Leaf(leaf) => &leaf.key,
1396            BodyRef::LocalLeaf(bytes) => bytes,
1397            BodyRef::Branch(branch) => branch.childleaf_key(),
1398        }
1399    }
1400
1401    // Slot wrapper defined at module level (moved to below the impl block)
1402
1403    /// Find the first depth in [start_depth, limit) where the tree-ordered
1404    /// bytes of `self` and `other` differ. The comparison limit is computed
1405    /// as min(self.end_depth(), other.end_depth(), KEY_LEN) which is the
1406    /// natural bound for comparing two heads. Returns `Some((depth, a, b))`
1407    /// where `a` and `b` are the differing bytes at that depth, or `None`
1408    /// if no divergence is found in the range.
1409    pub(crate) fn first_divergence(
1410        &self,
1411        other: &Self,
1412        start_depth: usize,
1413    ) -> Option<(usize, u8, u8)> {
1414        let limit = std::cmp::min(std::cmp::min(self.end_depth(), other.end_depth()), KEY_LEN);
1415        debug_assert!(limit <= KEY_LEN);
1416        let this_key = self.childleaf_key();
1417        let other_key = other.childleaf_key();
1418        let mut depth = start_depth;
1419        while depth < limit {
1420            let i = O::TREE_TO_KEY[depth];
1421            let a = this_key[i];
1422            let b = other_key[i];
1423            if a != b {
1424                return Some((depth, a, b));
1425            }
1426            depth += 1;
1427        }
1428        None
1429    }
1430
1431    // Mutable access to the child slots for this head. If the head is a
1432    // branch, returns a mutable slice referencing the underlying child table
1433    // (each element is Option<Head>). If the head is a leaf an empty slice
1434    // is returned.
1435    //
1436    // The caller receives a &mut slice tied to the borrow of `self` and may
1437    // reorder entries in-place (e.g., sort_unstable) and then take them using
1438    // `Option::take()` to extract Head values. The call uses `body_mut()` so
1439    // COW semantics are preserved and callers have exclusive access to the
1440    // branch storage while the mutable borrow lasts.
1441    // NOTE: mut_children removed — prefer matching on BodyRef returned by
1442    // `body_mut()` and operating directly on the `&mut Branch` reference.
1443
1444    /// Remove a matching leaf. A detached heap leaf is returned without being
1445    /// dropped; archive-local leaves are dropped immediately while the enclosing
1446    /// PATCH owner cover is still installed. Their backing owner is retired
1447    /// separately at the public mutation boundary if the root empties.
1448    #[must_use = "drop the retired heap leaf only after the replacement root is committed"]
1449    pub(crate) fn remove_leaf(
1450        slot: &mut Option<Self>,
1451        leaf_key: &[u8; KEY_LEN],
1452        start_depth: usize,
1453    ) -> Option<Self> {
1454        if let Some(this) = slot {
1455            let end_depth = std::cmp::min(this.end_depth(), KEY_LEN);
1456            // Check reachable equality by asking the head to test the prefix
1457            // up to its end_depth. Using the head/leaf primitive centralises the
1458            // unsafe deref into Branch::childleaf()/Leaf::has_prefix.
1459            if !this.has_prefix::<KEY_LEN>(start_depth, leaf_key) {
1460                return None;
1461            }
1462            match this.tag() {
1463                HeadTag::Leaf => {
1464                    // Keep the removed value alive until every ancestor has
1465                    // repaired its aggregates and collapsed any unary branch.
1466                    slot.take()
1467                }
1468                HeadTag::LocalLeaf => {
1469                    // A LocalLeaf owns no allocation itself. Remove its Head
1470                    // while the PATCH-level owner cover still guards the raw
1471                    // bytes; never let a naked LocalLeaf escape as retirement.
1472                    drop(slot.take());
1473                    None
1474                }
1475                _ => {
1476                    let mut retired_leaf = None;
1477                    let mut ed = crate::patch::branch::BranchMut::from_head(this);
1478                    let key = leaf_key[end_depth];
1479                    ed.modify_child(key, |mut opt| {
1480                        retired_leaf = Self::remove_leaf(&mut opt, leaf_key, end_depth);
1481                        opt
1482                    });
1483
1484                    // If the branch now contains a single remaining child we
1485                    // collapse the branch upward into that child. We must pull
1486                    // the remaining child out while `ed` is still borrowed,
1487                    // then drop `ed` before writing back into `slot` to avoid
1488                    // double mutable borrows of the slot.
1489                    let occupied_children = ed.child_table.iter().flatten().take(2).count();
1490                    if occupied_children == 0 {
1491                        drop(ed);
1492                        drop(slot.take());
1493                    } else if occupied_children == 1 {
1494                        let mut remaining: Option<Head<KEY_LEN, O, V, H>> = None;
1495                        for slot_child in &mut ed.child_table {
1496                            if let Some(child) = slot_child.take() {
1497                                remaining = Some(child.with_start(start_depth));
1498                                break;
1499                            }
1500                        }
1501                        drop(ed);
1502                        if let Some(child) = remaining {
1503                            slot.replace(child);
1504                        }
1505                    } else {
1506                        // Ensure the editor commits the final pointer into the
1507                        // head when the branch does not collapse.
1508                        drop(ed);
1509                    }
1510                    retired_leaf
1511                }
1512            }
1513        } else {
1514            None
1515        }
1516    }
1517
1518    // NOTE: slot-level wrappers removed; callers should take the slot and call
1519    // the owned helpers (insert_leaf / replace_leaf / union)
1520    // directly. This reduces the indirection and keeps ownership semantics
1521    // explicit at the call site.
1522
1523    // Owned variants of the slot-based helpers. These accept the existing
1524    // Head by value and return the new Head after performing the
1525    // modification. They are used with the split `insert_child` /
1526    // `update_child` APIs so we no longer need `Branch::upsert_child`.
1527    pub(crate) fn insert_leaf(mut this: Self, leaf: Self, start_depth: usize) -> Self {
1528        if let Some((depth, this_byte_key, leaf_byte_key)) =
1529            this.first_divergence(&leaf, start_depth)
1530        {
1531            let old_key = this.key();
1532            let new_body = crate::patch::branch::Branch::new(
1533                depth,
1534                this.with_key(this_byte_key),
1535                leaf.with_key(leaf_byte_key),
1536            );
1537            return Head::new(old_key, new_body);
1538        }
1539
1540        let end_depth = this.end_depth();
1541        if end_depth != KEY_LEN {
1542            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1543            let inserted = leaf.with_start(ed.end_depth as usize);
1544            let key = inserted.key();
1545            ed.modify_child(key, |opt| match opt {
1546                Some(old) => Some(Head::insert_leaf(old, inserted, end_depth)),
1547                None => Some(inserted),
1548            });
1549        }
1550        this
1551    }
1552}
1553
1554// Archive-aware insertion path, available only when V = ().
1555impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, H: PatchHash> Head<KEY_LEN, O, (), H> {
1556    /// Inserts a LocalLeaf whose hash was already computed by ArchiveEntry.
1557    /// The enclosing PATCH retains the leaf's owner independently of trie
1558    /// shape, so LocalLeaves can use the ordinary structural operations.
1559    pub(crate) fn insert_archive_leaf(
1560        mut this: Self,
1561        leaf: Self,
1562        leaf_hash: H::Digest,
1563        start_depth: usize,
1564    ) -> Self {
1565        if let Some((depth, this_byte_key, leaf_byte_key)) =
1566            this.first_divergence(&leaf, start_depth)
1567        {
1568            let old_key = this.key();
1569            let new_body = crate::patch::branch::Branch::new_with_rchild_hash(
1570                depth,
1571                this.with_key(this_byte_key),
1572                leaf.with_key(leaf_byte_key),
1573                leaf_hash,
1574            );
1575            return Head::new(old_key, new_body);
1576        }
1577
1578        let end_depth = this.end_depth();
1579        if end_depth != KEY_LEN {
1580            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1581            let inserted = leaf.with_start(ed.end_depth as usize);
1582            let key = inserted.key();
1583            ed.modify_child_with_inserted_hint(key, leaf_hash, |opt| match opt {
1584                None => Some(inserted),
1585                Some(old) => Some(Head::insert_archive_leaf(
1586                    old, inserted, leaf_hash, end_depth,
1587                )),
1588            });
1589        }
1590        this
1591    }
1592}
1593
1594// Resume generic-V `Head` impl for the remaining methods (replace_leaf,
1595// union, intersect, query operations, etc.) which don't care about V
1596// shape and so remain in the V-generic impl block.
1597impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Head<KEY_LEN, O, V, H> {
1598    /// Replace the matching leaf while deferring reclamation of the old leaf.
1599    ///
1600    /// The returned retirement slot must be dropped only after the caller has
1601    /// published the returned head. `V::drop` is arbitrary user code and may
1602    /// panic; running it from inside a [`BranchMut`] edit would expose a taken
1603    /// child slot and stale aggregates if the panic were caught.
1604    pub(crate) fn replace_leaf(
1605        mut this: Self,
1606        leaf: Self,
1607        start_depth: usize,
1608    ) -> (Self, Option<Self>) {
1609        if let Some((depth, this_byte_key, leaf_byte_key)) =
1610            this.first_divergence(&leaf, start_depth)
1611        {
1612            let old_key = this.key();
1613            let new_body = Branch::new(
1614                depth,
1615                this.with_key(this_byte_key),
1616                leaf.with_key(leaf_byte_key),
1617            );
1618
1619            return (Head::new(old_key, new_body), None);
1620        }
1621
1622        let end_depth = this.end_depth();
1623        if end_depth == KEY_LEN {
1624            let old_key = this.key();
1625            return (leaf.with_key(old_key), Some(this));
1626        } else {
1627            // Use the editor view for branch mutation instead of raw pointer ops.
1628            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1629            let inserted = leaf.with_start(ed.end_depth as usize);
1630            let key = inserted.key();
1631            let mut retired = None;
1632            ed.modify_child(key, |opt| match opt {
1633                Some(old) => {
1634                    let (replacement, old_leaf) = Head::replace_leaf(old, inserted, end_depth);
1635                    retired = old_leaf;
1636                    Some(replacement)
1637                }
1638                None => Some(inserted),
1639            });
1640            drop(ed);
1641            return (this, retired);
1642        }
1643    }
1644
1645    /// Sequential PATCH-trie union. Always serial; the parallel
1646    /// dispatch lives in [`Self::par_union`] which calls back into
1647    /// `union` once budget is exhausted.
1648    pub(crate) fn union(mut this: Self, mut other: Self, at_depth: usize) -> Self {
1649        // An archive-backed singleton has no cached fingerprint. Decide its
1650        // exact identity first; a distinct union then hashes each child once
1651        // and carries those hashes into the new Branch.
1652        if this.is_archive_singleton_pair(&other) {
1653            if let Some((depth, this_byte_key, other_byte_key)) =
1654                this.first_divergence(&other, at_depth)
1655            {
1656                let this_hash = this.hash();
1657                let other_hash = other.hash();
1658                let old_key = this.key();
1659                let new_body = Branch::new_with_child_hashes(
1660                    depth,
1661                    this.with_key(this_byte_key),
1662                    other.with_key(other_byte_key),
1663                    this_hash,
1664                    other_hash,
1665                );
1666                return Head::new(old_key, new_body);
1667            }
1668            return this;
1669        }
1670
1671        if this.local_leaf_cardinality_allows_equality(&other) && this.hash() == other.hash() {
1672            return this;
1673        }
1674
1675        if let Some((depth, this_byte_key, other_byte_key)) =
1676            this.first_divergence(&other, at_depth)
1677        {
1678            let old_key = this.key();
1679            let new_body = Branch::new(
1680                depth,
1681                this.with_key(this_byte_key),
1682                other.with_key(other_byte_key),
1683            );
1684
1685            return Head::new(old_key, new_body);
1686        }
1687
1688        let this_depth = this.end_depth();
1689        let other_depth = other.end_depth();
1690        if this_depth < other_depth {
1691            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1692            let inserted = other.with_start(ed.end_depth as usize);
1693            let key = inserted.key();
1694            ed.modify_child(key, |opt| match opt {
1695                Some(old) => Some(Head::union(old, inserted, this_depth)),
1696                None => Some(inserted),
1697            });
1698            drop(ed);
1699            return this;
1700        }
1701
1702        if other_depth < this_depth {
1703            let old_key = this.key();
1704            let this_head = this;
1705            let mut ed = crate::patch::branch::BranchMut::from_head(&mut other);
1706            let inserted = this_head.with_start(ed.end_depth as usize);
1707            let key = inserted.key();
1708            ed.modify_child(key, |opt| match opt {
1709                Some(old) => Some(Head::union(old, inserted, other_depth)),
1710                None => Some(inserted),
1711            });
1712            drop(ed);
1713            return other.with_key(old_key);
1714        }
1715
1716        // Equal depth, hashes differ → walk `other`'s children,
1717        // resolving collisions via recursive `Head::union` and the
1718        // `modify_child`'s per-call accounting.
1719        //
1720        // Union is commutative; mutating either side in place is
1721        // semantically equivalent. Swap when `other`'s child_table
1722        // is at least 2× larger than `this`'s — start with the
1723        // bigger capacity so cuckoo grows are mostly avoided during
1724        // insert. Branch tags encode `log2(child_table_size)`, so
1725        // the 2× ratio reduces to `other_tag > this_tag` (no body
1726        // deref needed; the tag bits live in the head's pointer).
1727        if other.tag() > this.tag() {
1728            std::mem::swap(&mut this, &mut other);
1729        }
1730        let BodyMut::Branch(other_branch_ref) = other.body_mut() else {
1731            unreachable!();
1732        };
1733        let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1734        for other_child in other_branch_ref
1735            .child_table
1736            .iter_mut()
1737            .filter_map(Option::take)
1738        {
1739            let inserted = other_child.with_start(ed.end_depth as usize);
1740            let key = inserted.key();
1741            ed.modify_child(key, |opt| match opt {
1742                Some(old) => Some(Head::union(old, inserted, this_depth)),
1743                None => Some(inserted),
1744            });
1745        }
1746        drop(ed);
1747        this
1748    }
1749
1750    /// Parallel-aware top-level union entry. Allocates a fresh
1751    /// [`parallel_union::ParUnionCtx`] with a budget of
1752    /// `num_threads²` shared spawns, then delegates to
1753    /// [`Self::par_union_with_ctx`]. The budget persists across the
1754    /// entire recursive descent — once exhausted, the rest is
1755    /// sequential.
1756    #[cfg(feature = "parallel")]
1757    pub(crate) fn par_union(this: Self, other: Self, at_depth: usize) -> Self
1758    where
1759        O: Send + Sync,
1760        V: Send + Sync,
1761    {
1762        let ctx = parallel_union::ParUnionCtx::new();
1763        Self::par_union_with_ctx(this, other, at_depth, &ctx)
1764    }
1765
1766    /// Recursive parallel-aware union: at the equal-depth-branch
1767    /// arm, drains the "both" pairs and, for each pair, either
1768    /// claims a budget unit and spawns a parallel task or falls
1769    /// back to serial `Self::union`. All other arms (hash-equal,
1770    /// divergence, asymmetric depth) delegate to `Self::union` —
1771    /// they don't generate fan-out work for the budget to spend.
1772    #[cfg(feature = "parallel")]
1773    pub(crate) fn par_union_with_ctx(
1774        mut this: Self,
1775        mut other: Self,
1776        at_depth: usize,
1777        ctx: &parallel_union::ParUnionCtx,
1778    ) -> Self
1779    where
1780        O: Send + Sync,
1781        V: Send + Sync,
1782    {
1783        // Singleton pairs have no fan-out work for Rayon.
1784        if this.is_archive_singleton_pair(&other) {
1785            return Self::union(this, other, at_depth);
1786        }
1787
1788        if this.local_leaf_cardinality_allows_equality(&other) && this.hash() == other.hash() {
1789            return this;
1790        }
1791
1792        if let Some((depth, this_byte_key, other_byte_key)) =
1793            this.first_divergence(&other, at_depth)
1794        {
1795            let old_key = this.key();
1796            let new_body = Branch::new(
1797                depth,
1798                this.with_key(this_byte_key),
1799                other.with_key(other_byte_key),
1800            );
1801            return Head::new(old_key, new_body);
1802        }
1803
1804        let this_depth = this.end_depth();
1805        let other_depth = other.end_depth();
1806        if this_depth != other_depth {
1807            // Asymmetric — no fan-out opportunity, serial path wins.
1808            return Self::union(this, other, at_depth);
1809        }
1810
1811        // Equal depth, hashes differ → branch merge. Swap when
1812        // `other`'s child_table is ≥2× `this`'s so the in-place
1813        // target starts with the bigger capacity (fewer cuckoo
1814        // grows when scattering children back via
1815        // `install_child_growing`). Branch tags encode
1816        // `log2(child_table_size)`, so the 2× ratio reduces to
1817        // `other_tag > this_tag` — single byte compare from the
1818        // head pointer, no body deref / CoW risk.
1819        if other.tag() > this.tag() {
1820            std::mem::swap(&mut this, &mut other);
1821        }
1822
1823        // Threshold check via `body_ref` (no CoW); fall back to
1824        // serial when the source side is too small to amortise the
1825        // scatter machinery.
1826        let small = match other.body_ref() {
1827            BodyRef::Branch(b) => (b.leaf_count as usize) < PARALLEL_PATCH_UNION_THRESHOLD,
1828            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => unreachable!(),
1829        };
1830        if small {
1831            return Self::union(this, other, at_depth);
1832        }
1833
1834        let BodyMut::Branch(other_branch_ref) = other.body_mut() else {
1835            unreachable!();
1836        };
1837
1838        {
1839            let mut ed = crate::patch::branch::BranchMut::from_head(&mut this);
1840            let end_depth = ed.end_depth as usize;
1841
1842            // Scatter both child tables into key-indexed 256-slot
1843            // arrays + present bitsets. The bitset partition tells us
1844            // which keys need a recursive union ("both") vs which are
1845            // simple pass-throughs ("only").
1846            let mut this_arr: [Option<Head<KEY_LEN, O, V, H>>; 256] = std::array::from_fn(|_| None);
1847            let mut other_arr: [Option<Head<KEY_LEN, O, V, H>>; 256] =
1848                std::array::from_fn(|_| None);
1849            let mut this_present = crate::patch::bytetable::ByteSet::new_empty();
1850            let mut other_present = crate::patch::bytetable::ByteSet::new_empty();
1851
1852            for slot in ed.child_table.iter_mut() {
1853                if let Some(head) = slot.take() {
1854                    let key = head.key();
1855                    this_present.insert(key);
1856                    this_arr[key as usize] = Some(head);
1857                }
1858            }
1859            for slot in other_branch_ref.child_table.iter_mut() {
1860                if let Some(head) = slot.take() {
1861                    let head = head.with_start(end_depth);
1862                    let key = head.key();
1863                    other_present.insert(key);
1864                    other_arr[key as usize] = Some(head);
1865                }
1866            }
1867
1868            let mut both = this_present.intersect(&other_present);
1869            let mut only = this_present.symmetric_difference(&other_present);
1870
1871            // Pre-allocated scatter-write target. Each spawned task
1872            // writes to `resolved[k]` for its specific key byte —
1873            // disjoint by construction. The raw pointer wrapper
1874            // (`ScatterPtr`) makes the cross-thread sharing explicit.
1875            let mut resolved: [Option<Head<KEY_LEN, O, V, H>>; 256] = std::array::from_fn(|_| None);
1876            let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
1877
1878            rayon::scope(|s| {
1879                // Drain `both` pairs serially in the parent; per
1880                // pair, either claim a spawn unit and dispatch as a
1881                // task, or run serially via `Head::union` here on
1882                // the parent thread. The atomic budget is shared
1883                // with all nested `par_union_with_ctx` calls.
1884                while let Some(k) = both.drain_next_ascending() {
1885                    let i = k as usize;
1886                    let t = this_arr[i].take().expect("both ⇒ this");
1887                    let o = other_arr[i].take().expect("both ⇒ other");
1888                    if ctx.try_claim() {
1889                        s.spawn(move |_| {
1890                            let head = Self::par_union_with_ctx(t, o, this_depth, ctx);
1891                            // SAFETY: each task has a distinct
1892                            // key `k`, so the writes to
1893                            // `resolved[i]` are non-aliasing.
1894                            unsafe {
1895                                resolved_ptr.write_at(i, Some(head));
1896                            }
1897                        });
1898                    } else {
1899                        // Budget exhausted — fall back to fully
1900                        // serial union on this pair, then scatter
1901                        // the result. SAFETY: same disjointness
1902                        // invariant; the parent thread races only
1903                        // with tasks targeting distinct keys.
1904                        let head = Self::union(t, o, this_depth);
1905                        unsafe {
1906                            resolved_ptr.write_at(i, Some(head));
1907                        }
1908                    }
1909                }
1910            });
1911            // After scope: all spawned tasks have completed; the
1912            // scatter writes to `resolved` are all sequenced-before
1913            // here by rayon's join semantics.
1914
1915            for slot in resolved.iter_mut() {
1916                if let Some(head) = slot.take() {
1917                    ed.install_child_growing(head);
1918                }
1919            }
1920            while let Some(k) = only.drain_next_ascending() {
1921                let i = k as usize;
1922                let head = this_arr[i]
1923                    .take()
1924                    .or_else(|| other_arr[i].take())
1925                    .expect("only ⇒ exactly one side");
1926                ed.install_child_growing(head);
1927            }
1928
1929            ed.recompute_aggregates();
1930        }
1931        this
1932    }
1933
1934    /// Parallel-aware top-level intersect entry. Allocates a fresh
1935    /// [`parallel_union::ParUnionCtx`] (shared budget across the
1936    /// descent) and delegates to [`Self::par_intersect_with_ctx`].
1937    /// Intersect builds a fresh tree, so there is no in-place
1938    /// target — the parallel work is purely "compute per-pair
1939    /// intersections in parallel, then collect into a new Branch."
1940    #[cfg(feature = "parallel")]
1941    pub(crate) fn par_intersect(&self, other: &Self, at_depth: usize) -> Option<Self>
1942    where
1943        O: Send + Sync,
1944        V: Send + Sync,
1945    {
1946        let ctx = parallel_union::ParUnionCtx::new();
1947        self.par_intersect_with_ctx(other, at_depth, &ctx)
1948    }
1949
1950    /// Recursive parallel-aware intersect. At the equal-depth-branch
1951    /// arm, scatter-spawns one task per matching `(self_child,
1952    /// other_child)` pair (under budget), then collects results
1953    /// into a fresh `Branch`. Hash-equal / divergence / asymmetric-
1954    /// depth arms delegate to serial [`Self::intersect`] — they
1955    /// don't generate fan-out work.
1956    #[cfg(feature = "parallel")]
1957    pub(crate) fn par_intersect_with_ctx(
1958        &self,
1959        other: &Self,
1960        at_depth: usize,
1961        ctx: &parallel_union::ParUnionCtx,
1962    ) -> Option<Self>
1963    where
1964        O: Send + Sync,
1965        V: Send + Sync,
1966    {
1967        if self.is_archive_singleton_pair(other) {
1968            return self.intersect(other, at_depth);
1969        }
1970        if self.local_leaf_cardinality_allows_equality(other) && self.hash() == other.hash() {
1971            return Some(self.clone());
1972        }
1973        if self.first_divergence(other, at_depth).is_some() {
1974            return None;
1975        }
1976        let self_depth = self.end_depth();
1977        let other_depth = other.end_depth();
1978        if self_depth != other_depth {
1979            return self.intersect(other, at_depth);
1980        }
1981
1982        let BodyRef::Branch(self_branch) = self.body_ref() else {
1983            unreachable!();
1984        };
1985        let BodyRef::Branch(other_branch) = other.body_ref() else {
1986            unreachable!();
1987        };
1988
1989        // Intersect work is bounded by the smaller side — pairs only
1990        // exist where keys appear in both branches.
1991        let min_leaves = self_branch.leaf_count.min(other_branch.leaf_count) as usize;
1992        if min_leaves < PARALLEL_PATCH_UNION_THRESHOLD {
1993            return self.intersect(other, at_depth);
1994        }
1995
1996        let mut resolved: [Option<Head<KEY_LEN, O, V, H>>; 256] = std::array::from_fn(|_| None);
1997        let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
1998
1999        // `in_place_scope` runs the outer closure on the calling
2000        // thread (no `Send` bound), which lets us hold `&Branch`
2001        // borrows across the spawn loop. `Branch` is `!Sync` due
2002        // to its raw `*const Leaf` pointer field, so a regular
2003        // `rayon::scope` would reject the captures.
2004        rayon::in_place_scope(|s| {
2005            for slot in self_branch.child_table.iter() {
2006                let Some(self_child) = slot.as_ref() else {
2007                    continue;
2008                };
2009                let key = self_child.key();
2010                let Some(other_child) = other_branch.child_table.table_get(key) else {
2011                    continue;
2012                };
2013
2014                if ctx.try_claim() {
2015                    s.spawn(move |_| {
2016                        let result =
2017                            self_child.par_intersect_with_ctx(other_child, self_depth, ctx);
2018                        // SAFETY: distinct keys → disjoint slots.
2019                        unsafe {
2020                            resolved_ptr.write_at(key as usize, result);
2021                        }
2022                    });
2023                } else {
2024                    let result = self_child.intersect(other_child, self_depth);
2025                    unsafe {
2026                        resolved_ptr.write_at(key as usize, result);
2027                    }
2028                }
2029            }
2030        });
2031
2032        // Collect non-None results into a fresh Branch. Stick with
2033        // per-key `modify_child` here — intersect's collection
2034        // phase typically has FEW children (heavy filtering kept
2035        // only the matching subset), so the per-call aggregate
2036        // updates beat the fixed `recompute_aggregates` cost. Bench
2037        // sanity-checked: install+recompute regressed intersect
2038        // +18% on the 4M/50%-overlap dataset.
2039        let mut iter = resolved.into_iter().flatten();
2040        let first = iter.next()?;
2041        let Some(second) = iter.next() else {
2042            return Some(first);
2043        };
2044        let new_branch = Branch::new(
2045            self_depth,
2046            first.with_start(self_depth),
2047            second.with_start(self_depth),
2048        );
2049        let mut head_for_branch = Head::new(0, new_branch);
2050        {
2051            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
2052            for child in iter {
2053                let inserted = child.with_start(self_depth);
2054                let k = inserted.key();
2055                ed.modify_child(k, |_opt| Some(inserted));
2056            }
2057        }
2058        Some(head_for_branch)
2059    }
2060
2061    /// Parallel-aware top-level difference entry. Allocates a fresh
2062    /// [`parallel_union::ParUnionCtx`] and delegates to
2063    /// [`Self::par_difference_with_ctx`].
2064    #[cfg(feature = "parallel")]
2065    pub(crate) fn par_difference(&self, other: &Self, at_depth: usize) -> Option<Self>
2066    where
2067        O: Send + Sync,
2068        V: Send + Sync,
2069    {
2070        let ctx = parallel_union::ParUnionCtx::new();
2071        self.par_difference_with_ctx(other, at_depth, &ctx)
2072    }
2073
2074    /// Recursive parallel-aware difference. Same scatter-and-spawn
2075    /// shape as `par_intersect_with_ctx`, plus the "no match in
2076    /// other" branch where we clone `self_child` unchanged into
2077    /// the resolved array (no recursive work).
2078    #[cfg(feature = "parallel")]
2079    pub(crate) fn par_difference_with_ctx(
2080        &self,
2081        other: &Self,
2082        at_depth: usize,
2083        ctx: &parallel_union::ParUnionCtx,
2084    ) -> Option<Self>
2085    where
2086        O: Send + Sync,
2087        V: Send + Sync,
2088    {
2089        if self.is_archive_singleton_pair(other) {
2090            return self.difference(other, at_depth);
2091        }
2092        if self.local_leaf_cardinality_allows_equality(other) && self.hash() == other.hash() {
2093            return None;
2094        }
2095        if self.first_divergence(other, at_depth).is_some() {
2096            return Some(self.clone());
2097        }
2098        let self_depth = self.end_depth();
2099        let other_depth = other.end_depth();
2100        if self_depth != other_depth {
2101            return self.difference(other, at_depth);
2102        }
2103
2104        let BodyRef::Branch(self_branch) = self.body_ref() else {
2105            unreachable!();
2106        };
2107        let BodyRef::Branch(other_branch) = other.body_ref() else {
2108            unreachable!();
2109        };
2110
2111        // Difference work is bounded by `self` (every key in self is
2112        // either kept or filtered against other).
2113        if (self_branch.leaf_count as usize) < PARALLEL_PATCH_UNION_THRESHOLD {
2114            return self.difference(other, at_depth);
2115        }
2116
2117        let mut resolved: [Option<Head<KEY_LEN, O, V, H>>; 256] = std::array::from_fn(|_| None);
2118        let resolved_ptr = parallel_union::ScatterPtr(resolved.as_mut_ptr());
2119
2120        // See `par_intersect_with_ctx` for why this is
2121        // `in_place_scope` rather than `scope`.
2122        rayon::in_place_scope(|s| {
2123            for slot in self_branch.child_table.iter() {
2124                let Some(self_child) = slot.as_ref() else {
2125                    continue;
2126                };
2127                let key = self_child.key();
2128
2129                match other_branch.child_table.table_get(key) {
2130                    Some(other_child) => {
2131                        if ctx.try_claim() {
2132                            s.spawn(move |_| {
2133                                let result = self_child.par_difference_with_ctx(
2134                                    other_child,
2135                                    self_depth,
2136                                    ctx,
2137                                );
2138                                unsafe {
2139                                    resolved_ptr.write_at(key as usize, result);
2140                                }
2141                            });
2142                        } else {
2143                            let result = self_child.difference(other_child, self_depth);
2144                            unsafe {
2145                                resolved_ptr.write_at(key as usize, result);
2146                            }
2147                        }
2148                    }
2149                    None => {
2150                        // No match in other ⇒ keep `self_child`
2151                        // unchanged. Clone is cheap (Arc-style rc
2152                        // bump on Branch, leaf is small).
2153                        let cloned = self_child.clone();
2154                        unsafe {
2155                            resolved_ptr.write_at(key as usize, Some(cloned));
2156                        }
2157                    }
2158                }
2159            }
2160        });
2161
2162        // Collect non-None results into a fresh Branch. Difference's
2163        // collection phase typically has MANY children (most keys
2164        // in `self` survive — only matching+empty subtrees get
2165        // filtered), so `install_child_growing` + one
2166        // `recompute_aggregates` pass wins handily over per-call
2167        // `modify_child`. Mirror of the union pattern; intersect
2168        // uses `modify_child` because its collection phase has
2169        // far fewer children (heavy filtering).
2170        let mut iter = resolved.into_iter().flatten();
2171        let first = iter.next()?;
2172        let Some(second) = iter.next() else {
2173            return Some(first);
2174        };
2175        let new_branch = Branch::new(
2176            self_depth,
2177            first.with_start(self_depth),
2178            second.with_start(self_depth),
2179        );
2180        let mut head_for_branch = Head::new(0, new_branch);
2181        {
2182            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
2183            for child in iter {
2184                ed.install_child_growing(child.with_start(self_depth));
2185            }
2186            ed.recompute_aggregates();
2187        }
2188        Some(head_for_branch)
2189    }
2190
2191    pub(crate) fn infixes<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
2192        &self,
2193        prefix: &[u8; PREFIX_LEN],
2194        at_depth: usize,
2195        f: &mut F,
2196    ) where
2197        F: FnMut(&[u8; INFIX_LEN]),
2198    {
2199        match self.body_ref() {
2200            BodyRef::Leaf(leaf) => leaf.infixes::<PREFIX_LEN, INFIX_LEN, O, F>(prefix, at_depth, f),
2201            BodyRef::LocalLeaf(bytes) => {
2202                leaf::key_ops::infixes::<KEY_LEN, PREFIX_LEN, INFIX_LEN, O, F>(
2203                    bytes, prefix, at_depth, f,
2204                )
2205            }
2206            BodyRef::Branch(branch) => {
2207                branch.infixes::<PREFIX_LEN, INFIX_LEN, F>(prefix, at_depth, f)
2208            }
2209        }
2210    }
2211
2212    pub(crate) fn infixes_range<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
2213        &self,
2214        prefix: &[u8; PREFIX_LEN],
2215        at_depth: usize,
2216        min_infix: &[u8; INFIX_LEN],
2217        max_infix: &[u8; INFIX_LEN],
2218        f: &mut F,
2219    ) where
2220        F: FnMut(&[u8; INFIX_LEN]),
2221    {
2222        match self.body_ref() {
2223            BodyRef::Leaf(leaf) => leaf.infixes_range::<PREFIX_LEN, INFIX_LEN, O, F>(
2224                prefix, at_depth, min_infix, max_infix, f,
2225            ),
2226            BodyRef::LocalLeaf(bytes) => {
2227                leaf::key_ops::infixes_range::<KEY_LEN, PREFIX_LEN, INFIX_LEN, O, F>(
2228                    bytes, prefix, at_depth, min_infix, max_infix, f,
2229                )
2230            }
2231            BodyRef::Branch(branch) => branch.infixes_range::<PREFIX_LEN, INFIX_LEN, F>(
2232                prefix, at_depth, min_infix, max_infix, f,
2233            ),
2234        }
2235    }
2236
2237    pub(crate) fn first_infix_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
2238        &self,
2239        prefix: &[u8; PREFIX_LEN],
2240        at_depth: usize,
2241        min_infix: &[u8; INFIX_LEN],
2242        max_infix: &[u8; INFIX_LEN],
2243    ) -> Option<[u8; INFIX_LEN]> {
2244        match self.body_ref() {
2245            BodyRef::Leaf(leaf) => leaf.first_infix_range::<PREFIX_LEN, INFIX_LEN, O>(
2246                prefix, at_depth, min_infix, max_infix,
2247            ),
2248            BodyRef::LocalLeaf(bytes) => {
2249                leaf::key_ops::first_infix_range::<KEY_LEN, PREFIX_LEN, INFIX_LEN, O>(
2250                    bytes, prefix, at_depth, min_infix, max_infix,
2251                )
2252            }
2253            BodyRef::Branch(branch) => branch
2254                .first_infix_range::<PREFIX_LEN, INFIX_LEN>(prefix, at_depth, min_infix, max_infix),
2255        }
2256    }
2257
2258    pub(crate) fn count_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
2259        &self,
2260        prefix: &[u8; PREFIX_LEN],
2261        at_depth: usize,
2262        min_infix: &[u8; INFIX_LEN],
2263        max_infix: &[u8; INFIX_LEN],
2264    ) -> u64 {
2265        match self.body_ref() {
2266            BodyRef::Leaf(leaf) => {
2267                leaf.count_range::<PREFIX_LEN, INFIX_LEN, O>(prefix, at_depth, min_infix, max_infix)
2268            }
2269            BodyRef::LocalLeaf(bytes) => {
2270                leaf::key_ops::count_range::<KEY_LEN, PREFIX_LEN, INFIX_LEN, O>(
2271                    bytes, prefix, at_depth, min_infix, max_infix,
2272                )
2273            }
2274            BodyRef::Branch(branch) => {
2275                branch.count_range::<PREFIX_LEN, INFIX_LEN>(prefix, at_depth, min_infix, max_infix)
2276            }
2277        }
2278    }
2279
2280    pub(crate) fn has_prefix<const PREFIX_LEN: usize>(
2281        &self,
2282        at_depth: usize,
2283        prefix: &[u8; PREFIX_LEN],
2284    ) -> bool {
2285        const {
2286            assert!(PREFIX_LEN <= KEY_LEN);
2287        }
2288        match self.body_ref() {
2289            BodyRef::Leaf(leaf) => leaf.has_prefix::<O>(at_depth, prefix),
2290            BodyRef::LocalLeaf(bytes) => {
2291                leaf::key_ops::has_prefix::<KEY_LEN, O>(bytes, at_depth, prefix)
2292            }
2293            BodyRef::Branch(branch) => branch.has_prefix::<PREFIX_LEN>(at_depth, prefix),
2294        }
2295    }
2296
2297    pub(crate) fn traversal_depth<const PREFIX_LEN: usize>(
2298        &self,
2299        at_depth: usize,
2300        prefix: &[u8; PREFIX_LEN],
2301    ) -> usize {
2302        const {
2303            assert!(PREFIX_LEN <= KEY_LEN);
2304        }
2305        match self.body_ref() {
2306            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => 1,
2307            BodyRef::Branch(branch) => branch.traversal_depth::<PREFIX_LEN>(at_depth, prefix),
2308        }
2309    }
2310
2311    pub(crate) fn get<'a>(&'a self, at_depth: usize, key: &[u8; KEY_LEN]) -> Option<&'a V>
2312    where
2313        O: 'a,
2314    {
2315        match self.body_ref() {
2316            BodyRef::Leaf(leaf) => leaf.get::<O>(at_depth, key),
2317            BodyRef::LocalLeaf(bytes) => {
2318                if !leaf::key_ops::matches::<KEY_LEN, O>(bytes, at_depth, key) {
2319                    return None;
2320                }
2321                // SAFETY: LocalLeaf is only constructed by the SimpleArchive
2322                // ingestion path (step 3), which constrains the PATCH to
2323                // `V = ()`. The `Option<&V>` here therefore points at a
2324                // zero-sized value; a static `()` provides the address.
2325                // For non-`()` V this branch is unreachable today, and
2326                // construction will refuse such PATCHes once step 3 lands.
2327                // The type-system invariant will eventually be enforced
2328                // via a `LocalLeafSupported: V` trait constraint at
2329                // `Head::new_local_leaf` callers.
2330                static UNIT: () = ();
2331                let unit_ref: &V = unsafe {
2332                    debug_assert_eq!(std::mem::size_of::<V>(), 0, "LocalLeaf requires V = ()");
2333                    &*(&UNIT as *const () as *const V)
2334                };
2335                Some(unit_ref)
2336            }
2337            BodyRef::Branch(branch) => branch.get(at_depth, key),
2338        }
2339    }
2340
2341    pub(crate) fn segmented_len<const PREFIX_LEN: usize>(
2342        &self,
2343        at_depth: usize,
2344        prefix: &[u8; PREFIX_LEN],
2345    ) -> u64 {
2346        match self.body_ref() {
2347            BodyRef::Leaf(leaf) => leaf.segmented_len::<O, PREFIX_LEN>(at_depth, prefix),
2348            BodyRef::LocalLeaf(bytes) => {
2349                leaf::key_ops::segmented_len::<KEY_LEN, PREFIX_LEN, O>(bytes, at_depth, prefix)
2350            }
2351            BodyRef::Branch(branch) => branch.segmented_len::<PREFIX_LEN>(at_depth, prefix),
2352        }
2353    }
2354
2355    /// Locate the shallowest subtree whose keys all share `prefix`.
2356    ///
2357    /// Unlike composing [`Self::segmented_len`] with [`Self::infixes`], this
2358    /// returns the already-located head so a caller can inspect its cached
2359    /// segment count and then enumerate that same subtree without descending
2360    /// the fixed prefix a second time.
2361    fn locate_prefix<const PREFIX_LEN: usize>(
2362        &self,
2363        at_depth: usize,
2364        prefix: &[u8; PREFIX_LEN],
2365    ) -> Option<&Self> {
2366        let node_end_depth = self.end_depth();
2367        let limit = std::cmp::min(PREFIX_LEN, node_end_depth);
2368        if !leaf::key_ops::has_prefix::<KEY_LEN, O>(
2369            self.childleaf_key(),
2370            at_depth,
2371            &prefix[..limit],
2372        ) {
2373            return None;
2374        }
2375        if PREFIX_LEN <= node_end_depth {
2376            return Some(self);
2377        }
2378        let BodyRef::Branch(branch) = self.body_ref() else {
2379            unreachable!("a leaf always covers the complete key");
2380        };
2381        branch
2382            .child_table
2383            .table_get(prefix[node_end_depth])
2384            .and_then(|child| child.locate_prefix(node_end_depth, prefix))
2385    }
2386
2387    /// Enumerate a whole infix segment after `prefix` has already been
2388    /// matched for every key below this head.
2389    fn infixes_from_matched_prefix<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
2390        &self,
2391        for_each: &mut F,
2392    ) where
2393        F: FnMut(&[u8; INFIX_LEN]),
2394    {
2395        if PREFIX_LEN + INFIX_LEN <= self.end_depth() {
2396            let infix: [u8; INFIX_LEN] =
2397                core::array::from_fn(|i| self.childleaf_key()[O::TREE_TO_KEY[PREFIX_LEN + i]]);
2398            for_each(&infix);
2399            return;
2400        }
2401
2402        let BodyRef::Branch(branch) = self.body_ref() else {
2403            unreachable!("a leaf always covers the complete key");
2404        };
2405        for child in branch.child_table.iter().flatten() {
2406            child.infixes_from_matched_prefix::<PREFIX_LEN, INFIX_LEN, F>(for_each);
2407        }
2408    }
2409
2410    /// Diagnostic: accumulate (branch nodes, total child-table slots,
2411    /// heap-`Leaf` nodes, `LocalLeaf` slots) over the subtree. Used to
2412    /// decompose a PATCH's *structural* byte size (vs resident RSS).
2413    /// `branches` × the policy-specific branch header + `slots` × 8 is the
2414    /// branch allocation total; heap leaves add one `Leaf` node each.
2415    pub(crate) fn node_stats(&self, acc: &mut (u64, u64, u64, u64)) {
2416        match self.body_ref() {
2417            BodyRef::Leaf(_) => acc.2 += 1,
2418            BodyRef::LocalLeaf(_) => acc.3 += 1,
2419            BodyRef::Branch(branch) => {
2420                acc.0 += 1;
2421                acc.1 += branch.child_table.len() as u64;
2422                for child in branch.child_table.iter().flatten() {
2423                    child.node_stats(acc);
2424                }
2425            }
2426        }
2427    }
2428
2429    /// Per-end-depth branch census: `hist[d] = (branch_count, filled_children)`
2430    /// for branches whose branching point is at byte-depth `d`. Reveals where
2431    /// the branches sit and their fanout — the input to the HOT/variable-width
2432    /// densification question.
2433    pub(crate) fn branch_hist(&self, hist: &mut [(u64, u64); 65]) {
2434        if let BodyRef::Branch(branch) = self.body_ref() {
2435            let d = self.end_depth().min(64);
2436            let fanout = branch.child_table.iter().flatten().count() as u64;
2437            hist[d].0 += 1;
2438            hist[d].1 += fanout;
2439            for child in branch.child_table.iter().flatten() {
2440                child.branch_hist(hist);
2441            }
2442        }
2443    }
2444
2445    /// Per-fanout branch census: `hist[f] = branch_count` for branches with
2446    /// exactly `f` filled children.
2447    pub(crate) fn branch_fanout_hist(&self, hist: &mut [u64; 257]) {
2448        if let BodyRef::Branch(branch) = self.body_ref() {
2449            let fanout = branch.child_table.iter().flatten().count();
2450            hist[fanout.min(256)] += 1;
2451            for child in branch.child_table.iter().flatten() {
2452                child.branch_fanout_hist(hist);
2453            }
2454        }
2455    }
2456
2457    // NOTE: slot-level union wrapper removed; callers should take the slot and
2458    // call the owned helper `union` directly.
2459
2460    pub(crate) fn intersect(&self, other: &Self, at_depth: usize) -> Option<Self> {
2461        if self.is_archive_singleton_pair(other) {
2462            return if self.first_divergence(other, at_depth).is_none() {
2463                Some(self.clone())
2464            } else {
2465                None
2466            };
2467        }
2468
2469        if self.local_leaf_cardinality_allows_equality(other) && self.hash() == other.hash() {
2470            return Some(self.clone());
2471        }
2472
2473        if self.first_divergence(other, at_depth).is_some() {
2474            return None;
2475        }
2476
2477        let self_depth = self.end_depth();
2478        let other_depth = other.end_depth();
2479        if self_depth < other_depth {
2480            // This means that there can be at most one child in self
2481            // that might intersect with other.
2482            let BodyRef::Branch(branch) = self.body_ref() else {
2483                unreachable!();
2484            };
2485            return branch
2486                .child_table
2487                .table_get(other.childleaf_key()[O::TREE_TO_KEY[self_depth]])
2488                .and_then(|self_child| other.intersect(self_child, self_depth));
2489        }
2490
2491        if other_depth < self_depth {
2492            // This means that there can be at most one child in other
2493            // that might intersect with self.
2494            // If the depth of other is less than the depth of self, then it can't be a leaf.
2495            let BodyRef::Branch(other_branch) = other.body_ref() else {
2496                unreachable!();
2497            };
2498            return other_branch
2499                .child_table
2500                .table_get(self.childleaf_key()[O::TREE_TO_KEY[other_depth]])
2501                .and_then(|other_child| self.intersect(other_child, other_depth));
2502        }
2503
2504        // If we reached this point then the depths are equal. The only way to have a leaf
2505        // is if the other is a leaf as well, which is already handled by the hash check if they are equal,
2506        // and by the key check if they are not equal.
2507        // If one of them is a leaf and the other is a branch, then they would also have different depths,
2508        // which is already handled by the above code.
2509        let BodyRef::Branch(self_branch) = self.body_ref() else {
2510            unreachable!();
2511        };
2512        let BodyRef::Branch(other_branch) = other.body_ref() else {
2513            unreachable!();
2514        };
2515
2516        let mut intersected_children = self_branch
2517            .child_table
2518            .iter()
2519            .filter_map(Option::as_ref)
2520            .filter_map(|self_child| {
2521                let other_child = other_branch.child_table.table_get(self_child.key())?;
2522                self_child.intersect(other_child, self_depth)
2523            });
2524        let first_child = intersected_children.next()?;
2525        let Some(second_child) = intersected_children.next() else {
2526            return Some(first_child);
2527        };
2528        let new_branch = Branch::new(
2529            self_depth,
2530            first_child.with_start(self_depth),
2531            second_child.with_start(self_depth),
2532        );
2533        // Use a BranchMut editor to perform all child insertions via the
2534        // safe editor API instead of manipulating the NonNull pointer
2535        // directly. The editor will perform COW and commit the final
2536        // pointer into the Head when it is dropped.
2537        let mut head_for_branch = Head::new(0, new_branch);
2538        {
2539            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
2540            for child in intersected_children {
2541                let inserted = child.with_start(self_depth);
2542                let k = inserted.key();
2543                ed.modify_child(k, |_opt| Some(inserted));
2544            }
2545            // ed dropped here commits the final branch pointer into head_for_branch
2546        }
2547        Some(head_for_branch)
2548    }
2549
2550    /// Returns the difference between self and other.
2551    /// This is the set of elements that are in self but not in other.
2552    /// If the difference is empty, None is returned.
2553    pub(crate) fn difference(&self, other: &Self, at_depth: usize) -> Option<Self> {
2554        if self.is_archive_singleton_pair(other) {
2555            return if self.first_divergence(other, at_depth).is_none() {
2556                None
2557            } else {
2558                Some(self.clone())
2559            };
2560        }
2561
2562        if self.local_leaf_cardinality_allows_equality(other) && self.hash() == other.hash() {
2563            return None;
2564        }
2565
2566        if self.first_divergence(other, at_depth).is_some() {
2567            return Some(self.clone());
2568        }
2569
2570        let self_depth = self.end_depth();
2571        let other_depth = other.end_depth();
2572        if self_depth < other_depth {
2573            // This means that there can be at most one child in self
2574            // that might intersect with other. It's the only child that may not be in the difference.
2575            // The other children are definitely in the difference, as they have no corresponding byte in other.
2576            // Thus the cheapest way to compute the difference is compute the difference of the only child
2577            // that might intersect with other, copy self with it's correctly filled byte table, then
2578            // remove the old child, and insert the new child.
2579            let mut new_branch = self.clone();
2580            let other_byte_key = other.childleaf_key()[O::TREE_TO_KEY[self_depth]];
2581            {
2582                let mut ed = crate::patch::branch::BranchMut::from_head(&mut new_branch);
2583                ed.modify_child(other_byte_key, |opt| {
2584                    opt.and_then(|child| child.difference(other, self_depth))
2585                });
2586
2587                // The asymmetric edit can delete the only matching child
2588                // subtree. Preserve the compressed-trie invariant instead of
2589                // returning a Branch with zero or one child.
2590                let child_count = ed
2591                    .child_table
2592                    .iter()
2593                    .filter(|child| child.is_some())
2594                    .take(2)
2595                    .count();
2596                if child_count <= 1 {
2597                    let mut remaining = None;
2598                    for slot in &mut ed.child_table {
2599                        if let Some(child) = slot.take() {
2600                            remaining = Some(child.with_start(at_depth));
2601                            break;
2602                        }
2603                    }
2604                    drop(ed);
2605                    return remaining;
2606                }
2607            }
2608            return Some(new_branch);
2609        }
2610
2611        if other_depth < self_depth {
2612            // This means that we need to check if there is a child in other
2613            // that matches the path at the current depth of self.
2614            // There is no such child, then then self must be in the difference.
2615            // If there is such a child, then we have to compute the difference
2616            // between self and that child.
2617            // We know that other must be a branch.
2618            let BodyRef::Branch(other_branch) = other.body_ref() else {
2619                unreachable!();
2620            };
2621            let self_byte_key = self.childleaf_key()[O::TREE_TO_KEY[other_depth]];
2622            if let Some(other_child) = other_branch.child_table.table_get(self_byte_key) {
2623                return self.difference(other_child, at_depth);
2624            } else {
2625                return Some(self.clone());
2626            }
2627        }
2628
2629        // If we reached this point then the depths are equal. The only way to have a leaf
2630        // is if the other is a leaf as well, which is already handled by the hash check if they are equal,
2631        // and by the key check if they are not equal.
2632        // If one of them is a leaf and the other is a branch, then they would also have different depths,
2633        // which is already handled by the above code.
2634        let BodyRef::Branch(self_branch) = self.body_ref() else {
2635            unreachable!();
2636        };
2637        let BodyRef::Branch(other_branch) = other.body_ref() else {
2638            unreachable!();
2639        };
2640
2641        let mut differenced_children = self_branch
2642            .child_table
2643            .iter()
2644            .filter_map(Option::as_ref)
2645            .filter_map(|self_child| {
2646                if let Some(other_child) = other_branch.child_table.table_get(self_child.key()) {
2647                    self_child.difference(other_child, self_depth)
2648                } else {
2649                    Some(self_child.clone())
2650                }
2651            });
2652
2653        let first_child = differenced_children.next()?;
2654        let second_child = match differenced_children.next() {
2655            Some(sc) => sc,
2656            None => return Some(first_child),
2657        };
2658
2659        let new_branch = Branch::new(
2660            self_depth,
2661            first_child.with_start(self_depth),
2662            second_child.with_start(self_depth),
2663        );
2664        let mut head_for_branch = Head::new(0, new_branch);
2665        {
2666            let mut ed = crate::patch::branch::BranchMut::from_head(&mut head_for_branch);
2667            for child in differenced_children {
2668                let inserted = child.with_start(self_depth);
2669                let k = inserted.key();
2670                ed.modify_child(k, |_opt| Some(inserted));
2671            }
2672            // ed dropped here commits the final branch pointer into head_for_branch
2673        }
2674        // The key will be set later, because we don't know it yet.
2675        // The difference might remove multiple levels of branches,
2676        // so we can't just take the key from self or other.
2677        Some(head_for_branch)
2678    }
2679
2680    /// Set inclusion between the keys under this head and under `other`:
2681    /// `Equal` for the same keys, `Less` for a strict subset, `Greater` for a
2682    /// strict superset, `None` when neither contains the other.
2683    ///
2684    /// The same walk as [`Self::difference`], constructing nothing: a shared
2685    /// subtree is settled by its hash, and a key one side lacks decides the
2686    /// direction the moment it is met.
2687    pub(crate) fn inclusion(&self, other: &Self, at_depth: usize) -> Option<Ordering> {
2688        if self.is_archive_singleton_pair(other) {
2689            return self
2690                .first_divergence(other, at_depth)
2691                .is_none()
2692                .then_some(Ordering::Equal);
2693        }
2694
2695        if self.local_leaf_cardinality_allows_equality(other) && self.hash() == other.hash() {
2696            return Some(Ordering::Equal);
2697        }
2698
2699        if self.first_divergence(other, at_depth).is_some() {
2700            // Two non-empty sets on divergent prefixes share no key.
2701            return None;
2702        }
2703
2704        let self_depth = self.end_depth();
2705        let other_depth = other.end_depth();
2706        if self_depth < other_depth {
2707            // Self branches at a byte every key of other shares, so other
2708            // lies under one child of self, if anywhere, and self has more.
2709            let BodyRef::Branch(self_branch) = self.body_ref() else {
2710                unreachable!();
2711            };
2712            let other_byte_key = other.childleaf_key()[O::TREE_TO_KEY[self_depth]];
2713            return match self_branch.child_table.table_get(other_byte_key) {
2714                Some(self_child) => match self_child.inclusion(other, at_depth) {
2715                    Some(Ordering::Equal | Ordering::Greater) => Some(Ordering::Greater),
2716                    _ => None,
2717                },
2718                None => None,
2719            };
2720        }
2721
2722        if other_depth < self_depth {
2723            let BodyRef::Branch(other_branch) = other.body_ref() else {
2724                unreachable!();
2725            };
2726            let self_byte_key = self.childleaf_key()[O::TREE_TO_KEY[other_depth]];
2727            return match other_branch.child_table.table_get(self_byte_key) {
2728                Some(other_child) => match self.inclusion(other_child, at_depth) {
2729                    Some(Ordering::Equal | Ordering::Less) => Some(Ordering::Less),
2730                    _ => None,
2731                },
2732                None => None,
2733            };
2734        }
2735
2736        // Equal depths: both are branches, because a leaf pair is settled
2737        // above by the hash when equal and by the divergence when not. The
2738        // order is the meet over the children at each byte: a child only
2739        // self has says Greater, one only other has says Less, and a shared
2740        // byte says what its subtrees say.
2741        let BodyRef::Branch(self_branch) = self.body_ref() else {
2742            unreachable!();
2743        };
2744        let BodyRef::Branch(other_branch) = other.body_ref() else {
2745            unreachable!();
2746        };
2747        let mut order = Some(Ordering::Equal);
2748        for self_child in self_branch.child_table.iter().filter_map(Option::as_ref) {
2749            let child_order = match other_branch.child_table.table_get(self_child.key()) {
2750                Some(other_child) => self_child.inclusion(other_child, self_depth),
2751                None => Some(Ordering::Greater),
2752            };
2753            order = meet(order, child_order)?;
2754        }
2755        for other_child in other_branch.child_table.iter().filter_map(Option::as_ref) {
2756            if self_branch.child_table.table_get(other_child.key()).is_none() {
2757                order = meet(order, Some(Ordering::Less))?;
2758            }
2759        }
2760        order
2761    }
2762}
2763
2764/// Combine the inclusion of two disjoint parts: equal parts do not move it,
2765/// two parts leaning the same way keep leaning, and two parts leaning
2766/// opposite ways make the wholes incomparable.
2767fn meet(left: Option<Ordering>, right: Option<Ordering>) -> Option<Option<Ordering>> {
2768    match (left?, right?) {
2769        (Ordering::Equal, order) | (order, Ordering::Equal) => Some(Some(order)),
2770        (Ordering::Less, Ordering::Less) => Some(Some(Ordering::Less)),
2771        (Ordering::Greater, Ordering::Greater) => Some(Some(Ordering::Greater)),
2772        _ => None,
2773    }
2774}
2775
2776unsafe impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> ByteEntry
2777    for Head<KEY_LEN, O, V, H>
2778{
2779    fn key(&self) -> u8 {
2780        self.key()
2781    }
2782}
2783
2784impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> fmt::Debug
2785    for Head<KEY_LEN, O, V, H>
2786{
2787    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2788        self.tag().fmt(f)
2789    }
2790}
2791
2792impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Clone
2793    for Head<KEY_LEN, O, V, H>
2794{
2795    fn clone(&self) -> Self {
2796        unsafe {
2797            match self.body() {
2798                BodyPtr::Leaf(leaf) => Self::new(self.key(), Leaf::rc_inc(leaf)),
2799                BodyPtr::LocalLeaf(ptr) => {
2800                    // LocalLeaf has no refcount. Its enclosing PATCH snapshots
2801                    // clone the root owner set alongside the tagged pointer.
2802                    Self::new_local_leaf(self.key(), ptr)
2803                }
2804                BodyPtr::Branch(branch) => Self::new(self.key(), Branch::rc_inc(branch)),
2805            }
2806        }
2807    }
2808}
2809
2810// The Slot wrapper was removed in favor of using BranchMut::from_slot(&mut
2811// Option<Head<...>>) directly. This keeps the API surface smaller and
2812// avoids an extra helper type that simply forwarded to BranchMut.
2813
2814impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Drop for Head<KEY_LEN, O, V, H> {
2815    fn drop(&mut self) {
2816        unsafe {
2817            match self.body() {
2818                BodyPtr::Leaf(leaf) => Leaf::rc_dec(leaf),
2819                BodyPtr::LocalLeaf(_) => {
2820                    // No-op: LocalLeaf bytes are retained by the enclosing
2821                    // PATCH's root owner set, not refcounted per leaf.
2822                }
2823                BodyPtr::Branch(branch) => Branch::rc_dec(branch),
2824            }
2825        }
2826    }
2827}
2828
2829/// A PATCH is a persistent data structure that stores a set of keys.
2830/// Each key can be reordered and segmented, based on the provided key ordering and segmentation.
2831///
2832/// The patch supports efficient set operations, like union, intersection, and difference,
2833/// because it efficiently maintains a hash for all keys that are part of a sub-tree.
2834///
2835/// The tree itself is a path- and node-compressed a 256-ary trie.
2836/// Each nodes stores its children in a byte oriented cuckoo hash table,
2837/// allowing for O(1) access to children, while keeping the memory overhead low.
2838/// Table sizes are powers of two, starting at 2.
2839///
2840/// Having a single node type for all branching factors simplifies the implementation,
2841/// compared to other adaptive trie implementations, like ARTs or Judy Arrays
2842///
2843/// The PATCH allows for cheap copy-on-write operations, with `clone` being O(1).
2844/// Its persistent snapshots can share leaves, so a PATCH is `Send + Sync` only
2845/// when its associated value is also both `Send` and `Sync`.
2846///
2847/// A value that is neither thread-safe cannot make a PATCH thread-safe:
2848///
2849/// ```compile_fail
2850/// use std::rc::Rc;
2851/// use triblespace_core::patch::{IdentitySchema, PATCH};
2852///
2853/// fn assert_send_sync<T: Send + Sync>() {}
2854/// assert_send_sync::<PATCH<1, IdentitySchema, Rc<()>>>();
2855/// ```
2856///
2857/// `Cell<u64>` is `Send` but not `Sync`. Rejecting this case is important:
2858/// moving one PATCH snapshot can leave another snapshot reading the same leaf
2859/// on its original thread.
2860///
2861/// ```compile_fail
2862/// use std::cell::Cell;
2863/// use triblespace_core::patch::{IdentitySchema, PATCH};
2864///
2865/// fn assert_send<T: Send>() {}
2866/// assert_send::<PATCH<1, IdentitySchema, Cell<u64>>>();
2867/// ```
2868#[derive(Debug)]
2869pub struct PATCH<const KEY_LEN: usize, O = IdentitySchema, V = (), H = XorSip128>
2870where
2871    O: KeySchema<KEY_LEN>,
2872    H: PatchHash,
2873{
2874    // Field order is deliberate: Heads drop before the owner cover.
2875    root: Option<Head<KEY_LEN, O, V, H>>,
2876    /// Deduplicated conservative lifetime cover for every LocalLeaf anywhere
2877    /// below `root`. Set operations may retain provenance no longer reachable
2878    /// from the result, but never duplicate an owner or omit a reachable one.
2879    /// This thin Arc adds eight bytes per PATCH while removing sixteen bytes
2880    /// from every Branch.
2881    owners: Option<Arc<OwnerCover>>,
2882}
2883
2884/// A prefix-located PATCH infix traversal whose exact cardinality has already
2885/// been proved to fit a caller-supplied bound.
2886///
2887/// The view borrows the located trie head, so [`Self::for_each`] starts at that
2888/// same subtree and never repeats the fixed-prefix descent.
2889#[must_use = "call for_each to enumerate the bounded infixes"]
2890pub struct PATCHBoundedInfixes<
2891    'a,
2892    const KEY_LEN: usize,
2893    const PREFIX_LEN: usize,
2894    const INFIX_LEN: usize,
2895    O: KeySchema<KEY_LEN>,
2896    V,
2897    H: PatchHash = XorSip128,
2898> {
2899    located: Option<&'a Head<KEY_LEN, O, V, H>>,
2900    count: u64,
2901}
2902
2903/// Opaque borrow of one logical node in a canonical BLAKE3 PATCH trie.
2904///
2905/// The view exposes reconciliation data, never PATCH's tagged pointers,
2906/// branches, or physical cuckoo-table layout. It is available only for
2907/// [`IdentitySchema`], so [`Self::prefix`] and [`Self::representative`] are
2908/// canonical raw-key bytes rather than a schema-specific tree permutation.
2909/// Values do not participate in PATCH identity and are intentionally absent.
2910pub struct PATCHMerkleNode<'a, const KEY_LEN: usize, V> {
2911    head: &'a Head<KEY_LEN, IdentitySchema, V, Blake3Merkle>,
2912}
2913
2914impl<const KEY_LEN: usize, V> Copy for PATCHMerkleNode<'_, KEY_LEN, V> {}
2915
2916impl<const KEY_LEN: usize, V> Clone for PATCHMerkleNode<'_, KEY_LEN, V> {
2917    fn clone(&self) -> Self {
2918        *self
2919    }
2920}
2921
2922impl<'a, const KEY_LEN: usize, V> PATCHMerkleNode<'a, KEY_LEN, V> {
2923    fn new(head: &'a Head<KEY_LEN, IdentitySchema, V, Blake3Merkle>) -> Self {
2924        Self { head }
2925    }
2926
2927    /// Canonical digest of this logical subtree.
2928    pub fn digest(&self) -> [u8; 32] {
2929        self.head.hash()
2930    }
2931
2932    /// Exact number of leaves below this node.
2933    ///
2934    /// Branch digests commit to this count. A leaf digest canonically denotes
2935    /// one complete key, so its count is necessarily one.
2936    pub fn leaf_count(&self) -> u64 {
2937        self.head.count()
2938    }
2939
2940    /// First raw-key depth not shared by every key below this node.
2941    ///
2942    /// Leaves return `KEY_LEN`. For branches, the byte at `end_depth` selects
2943    /// one of [`Self::children`].
2944    pub fn end_depth(&self) -> usize {
2945        self.head.end_depth()
2946    }
2947
2948    /// Lexicographically first complete raw key below this node.
2949    ///
2950    /// PATCH's internal representative pointer is merely a routing witness
2951    /// and may depend on construction history. This accessor instead follows
2952    /// the smallest logical edge at each branch, making the public result
2953    /// canonical without exposing or changing that hot-path field.
2954    pub fn representative(&self) -> &'a [u8; KEY_LEN] {
2955        let mut node = self.head;
2956        loop {
2957            match node.body_ref() {
2958                BodyRef::Leaf(leaf) => return &leaf.key,
2959                BodyRef::LocalLeaf(key) => return key,
2960                BodyRef::Branch(branch) => {
2961                    node = branch
2962                        .child_table
2963                        .iter()
2964                        .flatten()
2965                        .min_by_key(|child| child.key())
2966                        .expect("a PATCH branch has at least two children");
2967                }
2968            }
2969        }
2970    }
2971
2972    /// Canonical raw-key prefix naming this logical node.
2973    ///
2974    /// A lookup prefix may end inside a compressed path. In that case the
2975    /// returned node's canonical prefix is longer than the requested prefix.
2976    pub fn prefix(&self) -> &'a [u8] {
2977        &self.representative()[..self.end_depth()]
2978    }
2979
2980    /// Whether this node is a single complete key.
2981    pub fn is_leaf(&self) -> bool {
2982        self.end_depth() == KEY_LEN
2983    }
2984
2985    /// Iterate over logical children in ascending edge-byte order.
2986    pub fn children(&self) -> PATCHMerkleChildren<'a, KEY_LEN, V> {
2987        PATCHMerkleChildren::new(*self)
2988    }
2989
2990    /// Iterate over at most `limit` keys in this subtree, strictly after
2991    /// `after`, in canonical raw-key order.
2992    ///
2993    /// The cursor is a complete key, not an implementation node token. It
2994    /// need not exist in the PATCH. Keys are copied out so neither associated
2995    /// values nor archive-backed leaf lifetimes escape this borrow. A zero
2996    /// limit is explicitly empty and performs no traversal.
2997    pub fn items_after(
2998        &self,
2999        after: Option<&[u8; KEY_LEN]>,
3000        limit: usize,
3001    ) -> PATCHMerkleItems<'a, KEY_LEN, V> {
3002        PATCHMerkleItems::new(*self, after.copied(), limit)
3003    }
3004
3005    fn may_contain_after(&self, after: &[u8; KEY_LEN]) -> bool {
3006        let end_depth = self.end_depth();
3007        self.representative()[..end_depth] >= after[..end_depth]
3008    }
3009}
3010
3011impl<const KEY_LEN: usize, V> core::fmt::Debug for PATCHMerkleNode<'_, KEY_LEN, V> {
3012    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3013        f.debug_struct("PATCHMerkleNode")
3014            .field("prefix", &self.prefix())
3015            .field("digest", &self.digest())
3016            .field("leaf_count", &self.leaf_count())
3017            .field("end_depth", &self.end_depth())
3018            .field("representative", self.representative())
3019            .finish()
3020    }
3021}
3022
3023/// Ascending logical children of a [`PATCHMerkleNode`].
3024///
3025/// The iterator contains at most 256 edges regardless of the physical branch
3026/// allocation. Its fields are private so the cuckoo representation remains an
3027/// implementation detail.
3028pub struct PATCHMerkleChildren<'a, const KEY_LEN: usize, V> {
3029    node: Option<PATCHMerkleNode<'a, KEY_LEN, V>>,
3030    edges: ByteSet,
3031}
3032
3033impl<'a, const KEY_LEN: usize, V> PATCHMerkleChildren<'a, KEY_LEN, V> {
3034    fn new(node: PATCHMerkleNode<'a, KEY_LEN, V>) -> Self {
3035        let mut edges = ByteSet::new_empty();
3036        if let BodyRef::Branch(branch) = node.head.body_ref() {
3037            for child in branch.child_table.iter().flatten() {
3038                edges.insert(child.key());
3039            }
3040        }
3041        Self {
3042            node: (!node.is_leaf()).then_some(node),
3043            edges,
3044        }
3045    }
3046}
3047
3048impl<'a, const KEY_LEN: usize, V> Iterator for PATCHMerkleChildren<'a, KEY_LEN, V> {
3049    type Item = (u8, PATCHMerkleNode<'a, KEY_LEN, V>);
3050
3051    fn next(&mut self) -> Option<Self::Item> {
3052        let edge = self.edges.drain_next_ascending()?;
3053        let node = self.node.expect("a child edge requires a branch node");
3054        let BodyRef::Branch(branch) = node.head.body_ref() else {
3055            unreachable!("a leaf cannot carry child edges");
3056        };
3057        let child = branch
3058            .child_table
3059            .table_get(edge)
3060            .expect("an enumerated PATCH child remains present");
3061        Some((edge, PATCHMerkleNode::new(child)))
3062    }
3063
3064    fn size_hint(&self) -> (usize, Option<usize>) {
3065        let remaining = self.edges.popcount() as usize;
3066        (remaining, Some(remaining))
3067    }
3068}
3069
3070impl<const KEY_LEN: usize, V> ExactSizeIterator for PATCHMerkleChildren<'_, KEY_LEN, V> {}
3071impl<const KEY_LEN: usize, V> std::iter::FusedIterator for PATCHMerkleChildren<'_, KEY_LEN, V> {}
3072
3073/// Bounded canonical key page below one [`PATCHMerkleNode`].
3074///
3075/// Earlier subtrees are rejected from their compressed raw-key prefix rather
3076/// than scanned leaf-by-leaf. The traversal stack grows only with trie depth;
3077/// each frame contains a fixed 256-bit edge set.
3078pub struct PATCHMerkleItems<'a, const KEY_LEN: usize, V> {
3079    pending: Option<PATCHMerkleNode<'a, KEY_LEN, V>>,
3080    stack: Vec<PATCHMerkleChildren<'a, KEY_LEN, V>>,
3081    after: Option<[u8; KEY_LEN]>,
3082    remaining: usize,
3083}
3084
3085impl<'a, const KEY_LEN: usize, V> PATCHMerkleItems<'a, KEY_LEN, V> {
3086    fn new(
3087        node: PATCHMerkleNode<'a, KEY_LEN, V>,
3088        after: Option<[u8; KEY_LEN]>,
3089        limit: usize,
3090    ) -> Self {
3091        Self {
3092            pending: (limit != 0).then_some(node),
3093            stack: Vec::new(),
3094            after,
3095            remaining: limit,
3096        }
3097    }
3098
3099    fn next_node(&mut self) -> Option<PATCHMerkleNode<'a, KEY_LEN, V>> {
3100        if let Some(node) = self.pending.take() {
3101            return Some(node);
3102        }
3103        loop {
3104            let children = self.stack.last_mut()?;
3105            if let Some((_, node)) = children.next() {
3106                return Some(node);
3107            }
3108            self.stack.pop();
3109        }
3110    }
3111}
3112
3113impl<'a, const KEY_LEN: usize, V> Iterator for PATCHMerkleItems<'a, KEY_LEN, V> {
3114    type Item = [u8; KEY_LEN];
3115
3116    fn next(&mut self) -> Option<Self::Item> {
3117        while self.remaining != 0 {
3118            let node = self.next_node()?;
3119            if self
3120                .after
3121                .as_ref()
3122                .is_some_and(|after| !node.may_contain_after(after))
3123            {
3124                continue;
3125            }
3126            if node.is_leaf() {
3127                let key = *node.representative();
3128                if self.after.as_ref().is_some_and(|after| key <= *after) {
3129                    continue;
3130                }
3131                self.remaining -= 1;
3132                return Some(key);
3133            }
3134            self.stack.push(node.children());
3135        }
3136        None
3137    }
3138
3139    fn size_hint(&self) -> (usize, Option<usize>) {
3140        (0, Some(self.remaining))
3141    }
3142}
3143
3144impl<const KEY_LEN: usize, V> std::iter::FusedIterator for PATCHMerkleItems<'_, KEY_LEN, V> {}
3145
3146impl<
3147        'a,
3148        const KEY_LEN: usize,
3149        const PREFIX_LEN: usize,
3150        const INFIX_LEN: usize,
3151        O: KeySchema<KEY_LEN>,
3152        V,
3153        H: PatchHash,
3154    > PATCHBoundedInfixes<'a, KEY_LEN, PREFIX_LEN, INFIX_LEN, O, V, H>
3155{
3156    /// Exact number of distinct infixes this view will emit.
3157    pub fn len(&self) -> u64 {
3158        self.count
3159    }
3160
3161    /// Whether this bounded traversal has no matching infixes.
3162    pub fn is_empty(&self) -> bool {
3163        self.count == 0
3164    }
3165
3166    /// Enumerate the already-located subtree in the same callback order as
3167    /// [`PATCH::infixes`].
3168    pub fn for_each<F>(self, mut for_each: F)
3169    where
3170        F: FnMut(&[u8; INFIX_LEN]),
3171    {
3172        if let Some(located) = self.located {
3173            located.infixes_from_matched_prefix::<PREFIX_LEN, INFIX_LEN, F>(&mut for_each);
3174        }
3175    }
3176}
3177
3178impl<const KEY_LEN: usize, O, V, H> Clone for PATCH<KEY_LEN, O, V, H>
3179where
3180    O: KeySchema<KEY_LEN>,
3181    H: PatchHash,
3182{
3183    fn clone(&self) -> Self {
3184        Self {
3185            root: self.root.clone(),
3186            owners: self.owners.clone(),
3187        }
3188    }
3189}
3190
3191impl<const KEY_LEN: usize, O, V, H> Default for PATCH<KEY_LEN, O, V, H>
3192where
3193    O: KeySchema<KEY_LEN>,
3194    H: PatchHash,
3195{
3196    fn default() -> Self {
3197        Self::new()
3198    }
3199}
3200
3201impl<const KEY_LEN: usize, O, V, H> PATCH<KEY_LEN, O, V, H>
3202where
3203    O: KeySchema<KEY_LEN>,
3204    H: PatchHash,
3205{
3206    /// Creates a new empty PATCH.
3207    pub fn new() -> Self {
3208        H::init();
3209        PATCH {
3210            root: None,
3211            owners: None,
3212        }
3213    }
3214
3215    /// Inserts a shared key into the PATCH.
3216    ///
3217    /// Takes an [Entry] object that can be created from a key,
3218    /// and inserted into multiple PATCH instances.
3219    ///
3220    /// If the key is already present, this is a no-op.
3221    pub fn insert(&mut self, entry: &Entry<KEY_LEN, V, H>) {
3222        if self.root.is_some() {
3223            let this = self.root.take().expect("root should not be empty");
3224            let new_head = Head::insert_leaf(this, entry.leaf(), 0);
3225            self.root.replace(new_head);
3226        } else {
3227            self.root.replace(entry.leaf());
3228        }
3229        self.debug_check_owner_invariant();
3230    }
3231
3232    /// Inserts a key into the PATCH, replacing the value if it already exists.
3233    ///
3234    /// If the replaced value's destructor panics, the replacement is already
3235    /// fully committed when the panic is raised.
3236    pub fn replace(&mut self, entry: &Entry<KEY_LEN, V, H>) {
3237        let retired_leaf = if self.root.is_some() {
3238            let this = self.root.take().expect("root should not be empty");
3239            let (new_head, retired_leaf) = Head::replace_leaf(this, entry.leaf(), 0);
3240            self.root.replace(new_head);
3241            retired_leaf
3242        } else {
3243            self.root.replace(entry.leaf());
3244            None
3245        };
3246        self.debug_check_owner_invariant();
3247
3248        // Deliberately last: replacement may release the final shared
3249        // reference to user-owned `V`, whose destructor may panic.
3250        drop(retired_leaf);
3251    }
3252
3253    /// Removes a key from the PATCH.
3254    ///
3255    /// `key` is expressed in this PATCH's tree ordering. A key in the shared
3256    /// key ordering must first be converted with [`KeySchema::tree_ordered`].
3257    ///
3258    /// If the key is not present, this is a no-op.
3259    /// If a removed value or final archive owner's destructor panics, the
3260    /// removal is already fully committed when the panic is raised.
3261    pub fn remove(&mut self, key: &[u8; KEY_LEN]) {
3262        let retired_leaf = Head::remove_leaf(&mut self.root, key, 0);
3263        let retired_owners = if self.root.is_none() {
3264            self.owners.take()
3265        } else {
3266            None
3267        };
3268        self.debug_check_owner_invariant();
3269
3270        // Deliberately last: owner and value reclamation may execute arbitrary
3271        // user Drop implementations, so every observable PATCH field and
3272        // structural invariant must already describe the committed result.
3273        drop(retired_owners);
3274        drop(retired_leaf);
3275    }
3276
3277    /// Returns the number of keys in the PATCH.
3278    pub fn len(&self) -> u64 {
3279        if let Some(root) = &self.root {
3280            root.count()
3281        } else {
3282            0
3283        }
3284    }
3285
3286    /// Diagnostic structural census: returns
3287    /// `(branch_nodes, child_table_slots, heap_leaf_nodes, local_leaf_slots)`.
3288    /// Structural branch bytes ≈ `branches * Self::branch_header_bytes() + slots * 8`;
3289    /// heap leaves add a `Leaf` node each (the key is shared across the six
3290    /// orderings, so count it once per trible, not once per ordering).
3291    pub fn node_stats(&self) -> (u64, u64, u64, u64) {
3292        let mut acc = (0u64, 0u64, 0u64, 0u64);
3293        if let Some(root) = &self.root {
3294            root.node_stats(&mut acc);
3295        }
3296        acc
3297    }
3298
3299    #[cfg(debug_assertions)]
3300    fn debug_check_owner_invariant(&self) {
3301        debug_assert!(
3302            self.root.as_ref().map(|root| root.tag()) != Some(HeadTag::LocalLeaf)
3303                || self.owners.is_some(),
3304            "a root LocalLeaf must retain its archive owner",
3305        );
3306    }
3307
3308    #[cfg(not(debug_assertions))]
3309    #[inline]
3310    fn debug_check_owner_invariant(&self) {}
3311
3312    /// Returns the total capacity of all branch child tables.
3313    ///
3314    /// This counts allocated table slots (`child_table.len()`), not filled
3315    /// children.
3316    pub fn total_table_slots(&self) -> u64 {
3317        self.node_stats().1
3318    }
3319
3320    /// Fixed branch header bytes, excluding the trailing child table.
3321    pub fn branch_header_bytes() -> usize {
3322        std::mem::size_of::<Branch<KEY_LEN, O, [Option<Head<KEY_LEN, O, V, H>>; 0], V, H>>()
3323    }
3324
3325    /// Per-end-depth `(branch_count, filled_children)` histogram (65 buckets,
3326    /// byte-depths 0..=64), for analysing trie shape — where branches sit and
3327    /// their fanout distribution.
3328    pub fn branch_histogram(&self) -> [(u64, u64); 65] {
3329        let mut hist = [(0u64, 0u64); 65];
3330        if let Some(root) = &self.root {
3331            root.branch_hist(&mut hist);
3332        }
3333        hist
3334    }
3335
3336    /// Per-fanout branch census: returns `hist[f] = branch_count` for each
3337    /// exact fanout `0..=256`.
3338    pub fn branch_fanout_histogram(&self) -> [u64; 257] {
3339        let mut hist = [0u64; 257];
3340        if let Some(root) = &self.root {
3341            root.branch_fanout_hist(&mut hist);
3342        }
3343        hist
3344    }
3345
3346    /// Test-only root ownership receipt and LocalLeaf count.
3347    #[cfg(test)]
3348    pub(crate) fn archive_owner_guard_stats(&self) -> (bool, u64) {
3349        (self.owners.is_some(), self.node_stats().3)
3350    }
3351
3352    /// Returns true if the PATCH contains no keys.
3353    pub fn is_empty(&self) -> bool {
3354        self.len() == 0
3355    }
3356
3357    /// Return PATCH's internal root summary.
3358    ///
3359    /// The default policy's value is crate-private deliberately. Public cache
3360    /// keys must pass through [`blind_root_hash`] so callers cannot observe
3361    /// chosen leaf-hash vectors and exploit its XOR maintenance law.
3362    pub(crate) fn root_hash(&self) -> Option<H::Digest> {
3363        self.root.as_ref().map(|root| root.hash())
3364    }
3365
3366    /// Whether two snapshots still share the same persistent root allocation.
3367    ///
3368    /// This is a lineage-local invalidation primitive, not semantic equality
3369    /// and not a portable version. Clones share the root; every key or attached
3370    /// value mutation copy-on-writes it, even when the key-only fingerprint is
3371    /// unchanged by replacing a value.
3372    pub(crate) fn shares_root(&self, other: &Self) -> bool {
3373        match (&self.root, &other.root) {
3374            (None, None) => true,
3375            (Some(left), Some(right)) => left.tptr == right.tptr,
3376            _ => false,
3377        }
3378    }
3379
3380    /// Whether the complete subtree under `prefix` is structurally shared.
3381    ///
3382    /// The prefix is in tree order and may end inside a compressed path or a
3383    /// segment. Two absent prefixes are shared; present prefixes require the
3384    /// same node body and kind, not equal counts or key-set fingerprints. An
3385    /// unrelated insertion may re-key that body's incoming edge without
3386    /// changing its contents, so the edge byte is not part of this comparison.
3387    ///
3388    /// Like [`Self::shares_root`], this is conservative, lineage-local
3389    /// invalidation evidence, not semantic equality or a portable version.
3390    /// Key changes and attached-value replacements through PATCH are observed;
3391    /// interior mutations of an attached value are outside this contract.
3392    pub(crate) fn shares_prefix<const PREFIX_LEN: usize>(
3393        &self,
3394        other: &Self,
3395        prefix: &[u8; PREFIX_LEN],
3396    ) -> bool {
3397        const {
3398            assert!(PREFIX_LEN <= KEY_LEN);
3399        }
3400        let left = self
3401            .root
3402            .as_ref()
3403            .and_then(|root| root.locate_prefix(0, prefix));
3404        let right = other
3405            .root
3406            .as_ref()
3407            .and_then(|root| root.locate_prefix(0, prefix));
3408        match (left, right) {
3409            (None, None) => true,
3410            (Some(left), Some(right)) => {
3411                let mask = !(Head::<KEY_LEN, O, V, H>::KEY_MASK as usize);
3412                (left.tptr.as_ptr().addr() & mask) == (right.tptr.as_ptr().addr() & mask)
3413            }
3414            _ => false,
3415        }
3416    }
3417
3418    /// Clone the opaque archive-owner receipt without exposing the root Head.
3419    pub(crate) fn owner_guard(&self) -> PATCHOwnerGuard {
3420        PATCHOwnerGuard(self.owners.clone())
3421    }
3422
3423    /// Whether this PATCH and another PATCH share one owner-cover Arc.
3424    pub(crate) fn shares_owner_guard<OO, VV, HH>(&self, other: &PATCH<KEY_LEN, OO, VV, HH>) -> bool
3425    where
3426        OO: KeySchema<KEY_LEN>,
3427        HH: PatchHash,
3428    {
3429        match (&self.owners, &other.owners) {
3430            (None, None) => true,
3431            (Some(left), Some(right)) => Arc::ptr_eq(left, right),
3432            _ => false,
3433        }
3434    }
3435
3436    /// Whether `owner` is the most recently adopted member of this cover.
3437    pub(crate) fn owner_guard_latest_is(&self, owner: &Arc<dyn ArchiveOwner>) -> bool {
3438        self.owners
3439            .as_ref()
3440            .is_some_and(|cover| cover.latest_address == OwnerCover::address(owner))
3441    }
3442
3443    /// Install an owner cover proved to be a conservative superset of this
3444    /// PATCH's current receipt. Empty PATCHes may retain a receipt so all
3445    /// indexes of an aggregate can share one Arc.
3446    ///
3447    /// # Safety
3448    ///
3449    /// `guard` must retain every archive allocation retained by the current
3450    /// owner cover. Violating this can leave a LocalLeaf dangling.
3451    pub(crate) unsafe fn set_owner_guard(&mut self, guard: &PATCHOwnerGuard) {
3452        #[cfg(debug_assertions)]
3453        debug_assert!(
3454            guard.covers(&self.owners),
3455            "a PATCH owner guard may only be replaced by an owner-cover superset",
3456        );
3457        let already_installed = match (&self.owners, &guard.0) {
3458            (None, None) => true,
3459            (Some(current), Some(replacement)) => Arc::ptr_eq(current, replacement),
3460            _ => false,
3461        };
3462        if !already_installed {
3463            self.owners = guard.0.clone();
3464        }
3465        self.debug_check_owner_invariant();
3466    }
3467
3468    /// Returns the value associated with `key` if present.
3469    pub fn get(&self, key: &[u8; KEY_LEN]) -> Option<&V> {
3470        self.root.as_ref().and_then(|root| root.get(0, key))
3471    }
3472
3473    /// Allows iteratig over all infixes of a given length with a given prefix.
3474    /// Each infix is passed to the provided closure.
3475    ///
3476    /// The entire operation is performed over the tree view ordering of the keys.
3477    ///
3478    /// The length of the prefix and the infix is provided as type parameters,
3479    /// but will usually inferred from the arguments.
3480    ///
3481    /// The sum of `PREFIX_LEN` and `INFIX_LEN` must be less than or equal to `KEY_LEN`
3482    /// or a compile-time assertion will fail.
3483    ///
3484    /// Because all infixes are iterated in one go, less bookkeeping is required,
3485    /// than when using an Iterator, allowing for better performance.
3486    pub fn infixes<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
3487        &self,
3488        prefix: &[u8; PREFIX_LEN],
3489        mut for_each: F,
3490    ) where
3491        F: FnMut(&[u8; INFIX_LEN]),
3492    {
3493        const {
3494            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
3495        }
3496        assert!(
3497            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
3498                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
3499                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
3500            "INFIX_LEN must cover a whole segment"
3501        );
3502        if let Some(root) = &self.root {
3503            root.infixes(prefix, 0, &mut for_each);
3504        }
3505    }
3506
3507    /// Locate all distinct infixes for `prefix` only when their exact count is
3508    /// at most `limit`.
3509    ///
3510    /// `Some(view)` is an all-or-nothing proof that [`PATCHBoundedInfixes::len`]
3511    /// infixes fit the bound; [`PATCHBoundedInfixes::for_each`] then enumerates
3512    /// every one from the already-located subtree. `None` means the cached
3513    /// segment count exceeded `limit`. A missing prefix is a successful empty
3514    /// view.
3515    ///
3516    /// Locating the view costs `O(prefix depth)`. Visiting it costs
3517    /// `O(count)`, where `count <= limit`, so paged callers retain a hard
3518    /// geometric work bound while reserving output storage from the exact
3519    /// count before enumeration.
3520    pub fn bounded_infixes<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
3521        &self,
3522        prefix: &[u8; PREFIX_LEN],
3523        limit: u64,
3524    ) -> Option<PATCHBoundedInfixes<'_, KEY_LEN, PREFIX_LEN, INFIX_LEN, O, V, H>> {
3525        const {
3526            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
3527        }
3528        assert!(
3529            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
3530                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
3531                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
3532            "INFIX_LEN must cover a whole segment"
3533        );
3534        const {
3535            if PREFIX_LEN > 0 && PREFIX_LEN < KEY_LEN {
3536                assert!(
3537                    <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
3538                        [O::TREE_TO_KEY[PREFIX_LEN - 1]]
3539                        != <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
3540                            [O::TREE_TO_KEY[PREFIX_LEN]],
3541                    "PREFIX_LEN must align to segment boundary",
3542                );
3543            }
3544        }
3545
3546        let Some(root) = &self.root else {
3547            return Some(PATCHBoundedInfixes {
3548                located: None,
3549                count: 0,
3550            });
3551        };
3552        let Some(located) = root.locate_prefix(0, prefix) else {
3553            return Some(PATCHBoundedInfixes {
3554                located: None,
3555                count: 0,
3556            });
3557        };
3558        let count = located.count_segment(PREFIX_LEN);
3559        if count > limit {
3560            return None;
3561        }
3562        Some(PATCHBoundedInfixes {
3563            located: Some(located),
3564            count,
3565        })
3566    }
3567
3568    /// Like [`infixes`](Self::infixes) but only yields infixes in the
3569    /// byte range `[min_infix, max_infix]` (inclusive).
3570    ///
3571    /// The trie is pruned at each depth: branches whose byte key falls
3572    /// outside the range at the current infix position are skipped
3573    /// entirely, avoiding traversal of irrelevant subtrees.
3574    pub fn infixes_range<const PREFIX_LEN: usize, const INFIX_LEN: usize, F>(
3575        &self,
3576        prefix: &[u8; PREFIX_LEN],
3577        min_infix: &[u8; INFIX_LEN],
3578        max_infix: &[u8; INFIX_LEN],
3579        mut for_each: F,
3580    ) where
3581        F: FnMut(&[u8; INFIX_LEN]),
3582    {
3583        const {
3584            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
3585        }
3586        assert!(
3587            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
3588                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
3589                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
3590            "INFIX_LEN must cover a whole segment"
3591        );
3592        if let Some(root) = &self.root {
3593            root.infixes_range(prefix, 0, min_infix, max_infix, &mut for_each);
3594        }
3595    }
3596
3597    /// Return the lexicographically first distinct infix in the inclusive
3598    /// range `[min_infix, max_infix]` for `prefix`.
3599    ///
3600    /// This performs ordered lower-bound descent through the PATCH trie. It
3601    /// does not depend on the physical cuckoo-table order and does not
3602    /// materialize or sort the matching infixes.
3603    pub fn first_infix_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
3604        &self,
3605        prefix: &[u8; PREFIX_LEN],
3606        min_infix: &[u8; INFIX_LEN],
3607        max_infix: &[u8; INFIX_LEN],
3608    ) -> Option<[u8; INFIX_LEN]> {
3609        const {
3610            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
3611        }
3612        assert!(
3613            O::same_segment_tree(PREFIX_LEN, PREFIX_LEN + INFIX_LEN - 1)
3614                && (PREFIX_LEN + INFIX_LEN == KEY_LEN
3615                    || !O::same_segment_tree(PREFIX_LEN + INFIX_LEN - 1, PREFIX_LEN + INFIX_LEN)),
3616            "INFIX_LEN must cover a whole segment"
3617        );
3618        if min_infix > max_infix {
3619            return None;
3620        }
3621        self.root
3622            .as_ref()
3623            .and_then(|root| root.first_infix_range(prefix, 0, min_infix, max_infix))
3624    }
3625
3626    /// Return the first distinct infix strictly after `after`, bounded above
3627    /// by `max_infix` (inclusive).
3628    ///
3629    /// The successor is computed in lexicographic byte order and then passed
3630    /// to [`Self::first_infix_range`]. `None` is returned when `after` is the
3631    /// all-`0xff` value or when no later infix exists.
3632    pub fn next_infix_after<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
3633        &self,
3634        prefix: &[u8; PREFIX_LEN],
3635        after: &[u8; INFIX_LEN],
3636        max_infix: &[u8; INFIX_LEN],
3637    ) -> Option<[u8; INFIX_LEN]> {
3638        let mut lower = *after;
3639        let mut cursor = INFIX_LEN;
3640        loop {
3641            if cursor == 0 {
3642                return None;
3643            }
3644            cursor -= 1;
3645            if lower[cursor] != u8::MAX {
3646                lower[cursor] += 1;
3647                for byte in &mut lower[cursor + 1..] {
3648                    *byte = u8::MIN;
3649                }
3650                break;
3651            }
3652        }
3653        self.first_infix_range(prefix, &lower, max_infix)
3654    }
3655
3656    /// Count entries whose infix falls within [min_infix, max_infix].
3657    ///
3658    /// Uses cached `leaf_count` on branches to skip entire subtrees that
3659    /// are fully inside the range, making the count O(boundary_nodes)
3660    /// rather than O(matching_leaves).
3661    pub fn count_range<const PREFIX_LEN: usize, const INFIX_LEN: usize>(
3662        &self,
3663        prefix: &[u8; PREFIX_LEN],
3664        min_infix: &[u8; INFIX_LEN],
3665        max_infix: &[u8; INFIX_LEN],
3666    ) -> u64 {
3667        const {
3668            assert!(PREFIX_LEN + INFIX_LEN <= KEY_LEN);
3669        }
3670        match &self.root {
3671            Some(root) => root.count_range(prefix, 0, min_infix, max_infix),
3672            None => 0,
3673        }
3674    }
3675
3676    /// Returns true if the PATCH has a key with the given prefix.
3677    ///
3678    /// `PREFIX_LEN` must be less than or equal to `KEY_LEN` or a compile-time
3679    /// assertion will fail.
3680    pub fn has_prefix<const PREFIX_LEN: usize>(&self, prefix: &[u8; PREFIX_LEN]) -> bool {
3681        const {
3682            assert!(PREFIX_LEN <= KEY_LEN);
3683        }
3684        if let Some(root) = &self.root {
3685            root.has_prefix(0, prefix)
3686        } else {
3687            PREFIX_LEN == 0
3688        }
3689    }
3690
3691    /// Returns the number of PATCH nodes inspected by a prefix lookup.
3692    ///
3693    /// This is a diagnostic companion to [`PATCH::has_prefix`]. A miss counts
3694    /// the node where the mismatch or missing child is discovered; an empty
3695    /// PATCH reports zero.
3696    pub fn traversal_depth<const PREFIX_LEN: usize>(&self, prefix: &[u8; PREFIX_LEN]) -> usize {
3697        const {
3698            assert!(PREFIX_LEN <= KEY_LEN);
3699        }
3700        self.root
3701            .as_ref()
3702            .map(|root| root.traversal_depth(0, prefix))
3703            .unwrap_or(0)
3704    }
3705
3706    /// Returns the number of unique segments in keys with the given prefix.
3707    pub fn segmented_len<const PREFIX_LEN: usize>(&self, prefix: &[u8; PREFIX_LEN]) -> u64 {
3708        const {
3709            assert!(PREFIX_LEN <= KEY_LEN);
3710            if PREFIX_LEN > 0 && PREFIX_LEN < KEY_LEN {
3711                assert!(
3712                    <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
3713                        [O::TREE_TO_KEY[PREFIX_LEN - 1]]
3714                        != <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
3715                            [O::TREE_TO_KEY[PREFIX_LEN]],
3716                    "PREFIX_LEN must align to segment boundary",
3717                );
3718            }
3719        }
3720        if let Some(root) = &self.root {
3721            root.segmented_len(0, prefix)
3722        } else {
3723            0
3724        }
3725    }
3726
3727    /// Iterates over all keys in the PATCH.
3728    /// The keys are returned in key ordering but random order.
3729    pub fn iter<'a>(&'a self) -> PATCHIterator<'a, KEY_LEN, O, V, H> {
3730        PATCHIterator::new(self)
3731    }
3732
3733    /// Iterates over all keys in the PATCH in key order.
3734    ///
3735    /// The traversal visits every key in lexicographic key order, without
3736    /// accepting a prefix filter. For prefix-aware iteration, see
3737    /// [`PATCH::iter_prefix_count`].
3738    pub fn iter_ordered<'a>(&'a self) -> PATCHOrderedIterator<'a, KEY_LEN, O, V, H> {
3739        PATCHOrderedIterator::new(self)
3740    }
3741
3742    /// Iterate over all prefixes of the given length in the PATCH.
3743    /// The prefixes are naturally returned in tree ordering and tree order.
3744    /// A count of the number of elements for the given prefix is also returned.
3745    pub fn iter_prefix_count<'a, const PREFIX_LEN: usize>(
3746        &'a self,
3747    ) -> PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H> {
3748        PATCHPrefixIterator::new(self)
3749    }
3750
3751    /// View every distinct tree-ordered prefix as one member of a set.
3752    ///
3753    /// `PREFIX_LEN` must end at a declared segment boundary. Bytes in later
3754    /// segments are deliberately projected away: adding or removing another
3755    /// suffix under an existing prefix does not change this view's membership.
3756    pub fn prefix_set<const PREFIX_LEN: usize>(
3757        &self,
3758    ) -> PATCHPrefixSet<'_, KEY_LEN, PREFIX_LEN, O, V, H> {
3759        PATCHPrefixSet::new(self)
3760    }
3761
3762    /// Unions this PATCH with another PATCH.
3763    ///
3764    /// The other PATCH is consumed, and this PATCH is updated in place.
3765    /// If both PATCHes contain the same key, one associated value survives,
3766    /// but this operation does not specify which operand supplies it. Values
3767    /// do not participate in PATCH key-set identity, and the merge may swap
3768    /// operands internally.
3769    pub fn union(&mut self, mut other: Self)
3770    where
3771        O: Send + Sync,
3772        V: Send + Sync,
3773    {
3774        if let Some(other_root) = other.root.take() {
3775            if self.root.is_some() {
3776                // Install the complete lifetime union before either Head can
3777                // detach or move LocalLeaves. `other` keeps its own cover
3778                // until the trie merge completes, including on unwind.
3779                OwnerCover::merge_into(&mut self.owners, &other.owners);
3780                let this = self.root.take().expect("root should not be empty");
3781                #[cfg(feature = "parallel")]
3782                let merged = Head::par_union(this, other_root, 0);
3783                #[cfg(not(feature = "parallel"))]
3784                let merged = Head::union(this, other_root, 0);
3785                self.root.replace(merged);
3786            } else {
3787                self.root.replace(other_root);
3788                self.owners = other.owners.take();
3789            }
3790        }
3791        self.debug_check_owner_invariant();
3792    }
3793
3794    /// Intersects this PATCH with another PATCH.
3795    ///
3796    /// Returns a new PATCH that contains only the keys that are present in both PATCHes.
3797    pub fn intersect(&self, other: &Self) -> Self
3798    where
3799        O: Send + Sync,
3800        V: Send + Sync,
3801    {
3802        let guard = self.owner_guard().join(other.owner_guard());
3803        // SAFETY: the exact union retains every owner held by either source.
3804        unsafe { self.intersect_with_guard(other, &guard) }
3805    }
3806
3807    /// Intersect under an owner receipt already joined by an aggregate.
3808    ///
3809    /// # Safety
3810    ///
3811    /// `guard` must retain every archive allocation retained by either input.
3812    /// Intersection may reuse a LocalLeaf from either trie.
3813    pub(crate) unsafe fn intersect_with_guard(&self, other: &Self, guard: &PATCHOwnerGuard) -> Self
3814    where
3815        O: Send + Sync,
3816        V: Send + Sync,
3817    {
3818        #[cfg(debug_assertions)]
3819        debug_assert!(
3820            guard.covers(&self.owners) && guard.covers(&other.owners),
3821            "an intersection guard must cover both source PATCHes",
3822        );
3823        let root = match (&self.root, &other.root) {
3824            (Some(root), Some(other_root)) => {
3825                #[cfg(feature = "parallel")]
3826                let result = root.par_intersect(other_root, 0);
3827                #[cfg(not(feature = "parallel"))]
3828                let result = root.intersect(other_root, 0);
3829                result.map(|root| root.with_start(0))
3830            }
3831            _ => None,
3832        };
3833        let owners = root.as_ref().and(guard.0.clone());
3834        let result = Self { root, owners };
3835        result.debug_check_owner_invariant();
3836        result
3837    }
3838
3839    /// Returns the difference between this PATCH and another PATCH.
3840    ///
3841    /// Returns a new PATCH that contains only the keys that are present in this PATCH,
3842    /// but not in the other PATCH.
3843    pub fn difference(&self, other: &Self) -> Self
3844    where
3845        O: Send + Sync,
3846        V: Send + Sync,
3847    {
3848        let guard = self.owner_guard();
3849        // SAFETY: difference can only reuse LocalLeaves from its left source.
3850        unsafe { self.difference_with_guard(other, &guard) }
3851    }
3852
3853
3854    /// Subtract under a left-owner receipt already combined by an aggregate.
3855    ///
3856    /// # Safety
3857    ///
3858    /// `guard` must retain every archive allocation retained by `self`.
3859    /// Difference never introduces a LocalLeaf from `other`.
3860    pub(crate) unsafe fn difference_with_guard(&self, other: &Self, guard: &PATCHOwnerGuard) -> Self
3861    where
3862        O: Send + Sync,
3863        V: Send + Sync,
3864    {
3865        #[cfg(debug_assertions)]
3866        debug_assert!(
3867            guard.covers(&self.owners),
3868            "a difference guard must cover its left source PATCH",
3869        );
3870        let root = match (&self.root, &other.root) {
3871            (Some(root), Some(other_root)) => {
3872                #[cfg(feature = "parallel")]
3873                let result = root.par_difference(other_root, 0);
3874                #[cfg(not(feature = "parallel"))]
3875                let result = root.difference(other_root, 0);
3876                result
3877            }
3878            (Some(root), None) => Some(root.clone()),
3879            (None, _) => None,
3880        };
3881        let owners = root.as_ref().and(guard.0.clone());
3882        let result = Self { root, owners };
3883        result.debug_check_owner_invariant();
3884        result
3885    }
3886
3887    /// Calculates the average fill level for branch nodes grouped by their
3888    /// branching factor. The returned array contains eight entries for branch
3889    /// sizes `2`, `4`, `8`, `16`, `32`, `64`, `128` and `256` in that order.
3890    //#[cfg(debug_assertions)]
3891    pub fn debug_branch_fill(&self) -> [f32; 8] {
3892        let mut counts = [0u64; 8];
3893        let mut used = [0u64; 8];
3894
3895        if let Some(root) = &self.root {
3896            let mut stack = Vec::new();
3897            stack.push(root);
3898
3899            while let Some(head) = stack.pop() {
3900                match head.body_ref() {
3901                    BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => {}
3902                    BodyRef::Branch(b) => {
3903                        let size = b.child_table.len();
3904                        let idx = size.trailing_zeros() as usize - 1;
3905                        counts[idx] += 1;
3906                        used[idx] += b.child_table.iter().filter(|c| c.is_some()).count() as u64;
3907                        for child in b.child_table.iter().filter_map(|c| c.as_ref()) {
3908                            stack.push(child);
3909                        }
3910                    }
3911                }
3912            }
3913        }
3914
3915        let mut avg = [0f32; 8];
3916        for i in 0..8 {
3917            if counts[i] > 0 {
3918                let size = 1u64 << (i + 1);
3919                avg[i] = used[i] as f32 / (counts[i] as f32 * size as f32);
3920            }
3921        }
3922        avg
3923    }
3924}
3925
3926impl<const KEY_LEN: usize, O, V> PATCH<KEY_LEN, O, V, Blake3Merkle>
3927where
3928    O: KeySchema<KEY_LEN>,
3929{
3930    /// Return the canonical BLAKE3 Merkle root for this key set.
3931    ///
3932    /// `None` is the unique empty-set representation. The digest is stable
3933    /// across processes and construction histories; callers that need to
3934    /// scope anti-entropy to a team should key or domain-separate this root at
3935    /// that protocol boundary rather than changing PATCH's canonical identity.
3936    pub fn merkle_root(&self) -> Option<[u8; 32]> {
3937        self.root_hash()
3938    }
3939}
3940
3941impl<const KEY_LEN: usize, V> PATCH<KEY_LEN, IdentitySchema, V, Blake3Merkle> {
3942    /// Locate the shallowest logical Merkle node whose compressed path covers
3943    /// `prefix`.
3944    ///
3945    /// Lookup walks raw key bytes from the root; PATCH maintains no
3946    /// digest-to-node side map. If `prefix` ends inside a compressed path, the
3947    /// returned node's [`PATCHMerkleNode::prefix`] extends beyond the request
3948    /// to that node's canonical `end_depth`. A prefix longer than `KEY_LEN`, a
3949    /// mismatching compressed path, or a missing child returns `None`.
3950    pub fn merkle_node(&self, prefix: &[u8]) -> Option<PATCHMerkleNode<'_, KEY_LEN, V>> {
3951        if prefix.len() > KEY_LEN {
3952            return None;
3953        }
3954
3955        let mut node = self.root.as_ref()?;
3956        let mut at_depth = 0;
3957        loop {
3958            let end_depth = node.end_depth();
3959            let limit = prefix.len().min(end_depth);
3960            if node.childleaf_key()[at_depth..limit] != prefix[at_depth..limit] {
3961                return None;
3962            }
3963            if prefix.len() <= end_depth {
3964                return Some(PATCHMerkleNode::new(node));
3965            }
3966
3967            let BodyRef::Branch(branch) = node.body_ref() else {
3968                unreachable!("a leaf covers every raw-key byte");
3969            };
3970            node = branch.child_table.table_get(prefix[end_depth])?;
3971            at_depth = end_depth;
3972        }
3973    }
3974}
3975
3976impl<const KEY_LEN: usize> PATCH<KEY_LEN, IdentitySchema, (), Blake3Merkle> {
3977    /// Build an immutable key-only PATCH bottom-up.
3978    ///
3979    /// Input order and duplicates are ignored. Already sorted, unique input
3980    /// takes a linear fast path; all other input is sorted and deduplicated
3981    /// before construction. Every retained key becomes one owned leaf, and
3982    /// every final Merkle node is hashed exactly once during construction
3983    /// while recursion carries child digests upward. Debug builds additionally
3984    /// recompute branch digests as an invariant audit.
3985    ///
3986    /// This is the construction path for canonical inventory snapshots. Use
3987    /// [`Self::insert`] instead when preserving an existing PATCH and editing
3988    /// only a small number of keys is more important than whole-set build
3989    /// throughput.
3990    pub fn from_keys(keys: impl IntoIterator<Item = [u8; KEY_LEN]>) -> Self {
3991        Self::from_owned_keys(keys.into_iter().collect())
3992    }
3993}
3994
3995impl<const KEY_LEN: usize, H: PatchHash> PATCH<KEY_LEN, IdentitySchema, (), H> {
3996    fn from_owned_keys(mut keys: Vec<[u8; KEY_LEN]>) -> Self {
3997        H::init();
3998        if !keys.windows(2).all(|pair| pair[0] < pair[1]) {
3999            #[cfg(feature = "parallel")]
4000            {
4001                use rayon::prelude::*;
4002                keys.par_sort_unstable();
4003            }
4004            #[cfg(not(feature = "parallel"))]
4005            keys.sort_unstable();
4006            keys.dedup();
4007        }
4008
4009        let root = (!keys.is_empty()).then(|| Self::build_owned_sorted_head(&keys, 0).0);
4010        let result = Self { root, owners: None };
4011        result.debug_check_owner_invariant();
4012        result
4013    }
4014
4015    /// Build one logical node from a nonempty sorted, duplicate-free key run.
4016    /// The returned digest is carried by the returned Head and is returned
4017    /// separately so its parent never has to re-read or recompute it.
4018    fn build_owned_sorted_head(
4019        keys: &[[u8; KEY_LEN]],
4020        depth: usize,
4021    ) -> (Head<KEY_LEN, IdentitySchema, (), H>, H::Digest) {
4022        debug_assert!(!keys.is_empty());
4023        if keys.len() == 1 {
4024            // SAFETY: Leaf::new returns one initialized, 16-byte-aligned,
4025            // refcount-one allocation. This Head becomes its sole owner.
4026            let leaf = unsafe { Leaf::<KEY_LEN, (), H>::new(&keys[0], ()) };
4027            let digest = unsafe { leaf.as_ref().hash };
4028            return (Head::new(0, leaf), digest);
4029        }
4030
4031        // Lexicographic ordering means the first and last keys determine the
4032        // common prefix of the entire run.
4033        let first = &keys[0];
4034        let last = &keys[keys.len() - 1];
4035        let mut end_depth = depth;
4036        while end_depth < KEY_LEN && first[end_depth] == last[end_depth] {
4037            end_depth += 1;
4038        }
4039        debug_assert!(
4040            end_depth < KEY_LEN,
4041            "deduplicated keys must diverge before their end"
4042        );
4043
4044        let mut groups = Vec::with_capacity(256.min(keys.len()));
4045        let mut start = 0;
4046        while start < keys.len() {
4047            let edge = keys[start][end_depth];
4048            let width = keys[start..].partition_point(|key| key[end_depth] == edge);
4049            let end = start + width;
4050            groups.push((edge, &keys[start..end]));
4051            start = end;
4052        }
4053        debug_assert!(groups.len() >= 2);
4054        let initial_slots = if groups.len() == 2 {
4055            2
4056        } else {
4057            groups.len().next_power_of_two()
4058        };
4059
4060        #[cfg(feature = "parallel")]
4061        let children = if keys.len() >= Self::PARALLEL_PARTITION_THRESHOLD {
4062            use rayon::prelude::*;
4063            groups
4064                .into_par_iter()
4065                .map(|(edge, child_keys)| {
4066                    let (head, digest) = Self::build_owned_sorted_head(child_keys, end_depth + 1);
4067                    (edge, head, digest)
4068                })
4069                .collect()
4070        } else {
4071            groups
4072                .into_iter()
4073                .map(|(edge, child_keys)| {
4074                    let (head, digest) = Self::build_owned_sorted_head(child_keys, end_depth + 1);
4075                    (edge, head, digest)
4076                })
4077                .collect()
4078        };
4079        #[cfg(not(feature = "parallel"))]
4080        let children = groups
4081            .into_iter()
4082            .map(|(edge, child_keys)| {
4083                let (head, digest) = Self::build_owned_sorted_head(child_keys, end_depth + 1);
4084                (edge, head, digest)
4085            })
4086            .collect();
4087
4088        Self::assemble_partition_branch(end_depth, initial_slots, children)
4089    }
4090}
4091
4092/// Archive-backed insertion path, available only for `V = ()` because
4093/// [`ArchiveEntry`] does not carry a value. Newly inserted archive keys remain
4094/// LocalLeaves while the PATCH's deduplicated root cover retains their
4095/// allocations.
4096impl<const KEY_LEN: usize, O, H> PATCH<KEY_LEN, O, (), H>
4097where
4098    O: KeySchema<KEY_LEN>,
4099    H: PatchHash,
4100{
4101    /// Inserts an archive-backed key and retains its allocation before the
4102    /// LocalLeaf becomes reachable from the root.
4103    pub fn insert_archive(&mut self, entry: &ArchiveEntry<'_, KEY_LEN, H>) {
4104        let (leaf_head, leaf_owner, leaf_hash) = entry.leaf::<O>();
4105        OwnerCover::retain(&mut self.owners, leaf_owner);
4106        if let Some(this) = self.root.take() {
4107            let new_head = Head::insert_archive_leaf(this, leaf_head, leaf_hash, 0);
4108            self.root.replace(new_head);
4109        } else {
4110            self.root.replace(leaf_head);
4111        }
4112        self.debug_check_owner_invariant();
4113    }
4114
4115    /// Builds a canonical PATCH directly from an unordered row permutation by
4116    /// partitioning that one buffer in place at each trie depth.
4117    ///
4118    /// Archive construction fuses ordering and trie construction: no sorted
4119    /// pointer array or per-row leaf descriptor is retained. `hashes[row]` is
4120    /// the one transient key hash shared by every TribleSet index build.
4121    ///
4122    /// # Safety
4123    ///
4124    /// - `rows` must contain every valid index into `keys` and `hashes` exactly
4125    ///   once.
4126    /// - Every key pointer must be 16-byte aligned, immutable, and kept alive
4127    ///   by `owner`.
4128    /// - `keys` must contain no duplicates.
4129    /// - `hashes[row]` must be the PATCH key hash of `keys[row]`.
4130    #[cfg(test)]
4131    pub(crate) unsafe fn from_archive_partition(
4132        keys: &[[u8; KEY_LEN]],
4133        hashes: &[H::Digest],
4134        rows: &mut [u32],
4135        owner: &std::sync::Arc<dyn ArchiveOwner>,
4136    ) -> Self {
4137        unsafe {
4138            Self::from_archive_partition_with_guard(
4139                keys,
4140                hashes,
4141                rows,
4142                owner,
4143                &PATCHOwnerGuard::default(),
4144            )
4145        }
4146    }
4147
4148    /// Build an archive partition under a receipt already shared by an
4149    /// aggregate. Retaining `owner` is idempotent when it is already the
4150    /// receipt's latest member, preserving the shared cover Arc.
4151    #[cfg(any(test, feature = "parallel"))]
4152    pub(crate) unsafe fn from_archive_partition_with_guard(
4153        keys: &[[u8; KEY_LEN]],
4154        hashes: &[H::Digest],
4155        rows: &mut [u32],
4156        owner: &std::sync::Arc<dyn ArchiveOwner>,
4157        guard: &PATCHOwnerGuard,
4158    ) -> Self {
4159        // Branch child tables use randomness initialized alongside the
4160        // hash-key bundle. A pre-hashed caller may reach this constructor
4161        // before PATCH::new.
4162        H::init();
4163        assert_eq!(keys.len(), hashes.len());
4164        assert_eq!(keys.len(), rows.len());
4165        assert!(
4166            u32::try_from(rows.len()).is_ok(),
4167            "archive row ordinals must fit the partition metadata",
4168        );
4169        if rows.is_empty() {
4170            return Self::new();
4171        }
4172        let mut guard = guard.clone();
4173        guard.retain_archive_owner(owner);
4174        let owners = guard.0;
4175        if rows.len() == 1 {
4176            let row = rows[0] as usize;
4177            let ptr = NonNull::from(&keys[row]);
4178            // SAFETY: the caller proves alignment and `owners` retains the
4179            // archive allocation for the returned PATCH's lifetime.
4180            let root = unsafe { Head::new_local_leaf(0, ptr) };
4181            let result = Self {
4182                root: Some(root),
4183                owners,
4184            };
4185            result.debug_check_owner_invariant();
4186            return result;
4187        }
4188
4189        let (root, _) = unsafe { Self::build_archive_partition_head(keys, hashes, rows, 0) };
4190        let result = Self {
4191            root: Some(root.with_start(0)),
4192            owners,
4193        };
4194        result.debug_check_owner_invariant();
4195        result
4196    }
4197
4198    /// Row count at or above which one trie node builds its children on
4199    /// separate workers instead of recursing into them in order.
4200    ///
4201    /// The MSD partition already hands each child a disjoint, contiguous
4202    /// interval of the one permutation buffer, so the fan-out costs no copy
4203    /// and no synchronisation — only the task overhead this threshold pays
4204    /// for. Below it a node is cheaper to walk than to schedule.
4205    #[cfg(feature = "parallel")]
4206    pub(crate) const PARALLEL_PARTITION_THRESHOLD: usize = 1 << 12;
4207
4208    /// Rows one worker is given before a partition pass is worth splitting.
4209    ///
4210    /// A counting pass is a sequential read and a scatter is a random write,
4211    /// so a worker needs enough rows to amortise the histogram reduction and
4212    /// the second buffer. Below two workers' worth, the in-place American-flag
4213    /// pass is both cheaper and allocation-free.
4214    #[cfg(feature = "parallel")]
4215    pub(crate) const PARTITION_ROWS_PER_WORKER: usize = 1 << 13;
4216
4217    /// How many workers an out-of-place partition of `rows` should use, and
4218    /// therefore whether it beats the in-place pass at all.
4219    #[cfg(feature = "parallel")]
4220    pub(crate) fn partition_workers(rows: usize) -> usize {
4221        (rows / Self::PARTITION_ROWS_PER_WORKER)
4222            .min(rayon::current_num_threads().max(1))
4223            .max(1)
4224    }
4225
4226    /// Representative-LCP plus in-place MSD-radix worker for
4227    /// [`Self::from_archive_partition`].
4228    ///
4229    /// Trie construction is ownership-neutral. One deduplicated conservative
4230    /// owner cover on the returned PATCH guards every LocalLeaf regardless of
4231    /// later reshaping.
4232    ///
4233    /// With the `parallel` feature a node meets one of three regimes, by
4234    /// size: wide enough for [`Self::partition_workers`] to want more than one
4235    /// worker, it is split by the out-of-place counting pass and its children
4236    /// are built concurrently; merely at or above
4237    /// [`Self::PARALLEL_PARTITION_THRESHOLD`], it keeps the in-place pass and
4238    /// only its children go concurrent; below that it is walked in order.
4239    ///
4240    /// All three build the same trie. Children own disjoint intervals of the
4241    /// permutation and disjoint subtrees of the result, the child heads are
4242    /// reassembled in ascending key order either way, and the node hash is a
4243    /// canonical summary over edge-sorted children — so neither the order
4244    /// children are built in nor the order rows sit in within a bucket can
4245    /// reach the answer.
4246    #[cfg(any(test, feature = "parallel"))]
4247    unsafe fn build_archive_partition_head(
4248        keys: &[[u8; KEY_LEN]],
4249        hashes: &[H::Digest],
4250        rows: &mut [u32],
4251        depth: usize,
4252    ) -> (Head<KEY_LEN, O, (), H>, H::Digest) {
4253        debug_assert!(!rows.is_empty());
4254        if rows.len() == 1 {
4255            let row = rows[0] as usize;
4256            let ptr = NonNull::from(&keys[row]);
4257            // SAFETY: the outer constructor installs its owner cover before
4258            // returning this LocalLeaf to safe code.
4259            let head = unsafe { Head::new_local_leaf(0, ptr) };
4260            return (head, hashes[row]);
4261        }
4262
4263        // A node big enough to be worth the extra buffer counts and scatters
4264        // its children across workers instead of walking them in place; a
4265        // node merely big enough to be worth a task keeps the in-place pass
4266        // and only recurses concurrently.
4267        #[cfg(feature = "parallel")]
4268        if Self::partition_workers(rows.len()) > 1 {
4269            let (plan, mut permuted) = Self::partition_archive_rows_parallel(keys, rows, depth);
4270            // SAFETY: `permuted` is the same multiset of row ordinals as
4271            // `rows`, grouped by the same key byte.
4272            return unsafe {
4273                Self::build_archive_partition_children(keys, hashes, &mut permuted, &plan)
4274            };
4275        }
4276
4277        let plan = Self::partition_archive_rows(keys, rows, depth);
4278        let end_depth = plan.end_depth;
4279
4280        #[cfg(feature = "parallel")]
4281        if rows.len() >= Self::PARALLEL_PARTITION_THRESHOLD {
4282            // SAFETY: same contract, on the in-place permutation.
4283            return unsafe { Self::build_archive_partition_children(keys, hashes, rows, &plan) };
4284        }
4285
4286        let first_bucket = plan.buckets[0];
4287        let second_bucket = plan.buckets[1];
4288        let first_end = plan.ends[first_bucket as usize] as usize;
4289        let (first_head, first_hash) = unsafe {
4290            Self::build_archive_partition_head(keys, hashes, &mut rows[..first_end], end_depth + 1)
4291        };
4292        let second_end = plan.ends[second_bucket as usize] as usize;
4293        let (second_head, second_hash) = unsafe {
4294            Self::build_archive_partition_head(
4295                keys,
4296                hashes,
4297                &mut rows[first_end..second_end],
4298                end_depth + 1,
4299            )
4300        };
4301        let first_count = first_head.count();
4302        let second_count = second_head.count();
4303
4304        let body = if plan.initial_slots == 2 {
4305            Branch::new_with_child_hashes(
4306                end_depth,
4307                first_head.with_key(first_bucket),
4308                second_head.with_key(second_bucket),
4309                first_hash,
4310                second_hash,
4311            )
4312        } else {
4313            Branch::new_with_child_hashes_capacity(
4314                end_depth,
4315                first_head.with_key(first_bucket),
4316                second_head.with_key(second_bucket),
4317                first_hash,
4318                second_hash,
4319                plan.initial_slots,
4320            )
4321        };
4322        let mut root = Head::new(0, body);
4323        let representative = &keys[rows[0] as usize];
4324        let mut hash_state = H::begin_branch(
4325            representative,
4326            &O::TREE_TO_KEY,
4327            end_depth,
4328            plan.fanout,
4329            rows.len() as u64,
4330        );
4331        H::push_child(&mut hash_state, first_bucket, first_count, first_hash);
4332        H::push_child(&mut hash_state, second_bucket, second_count, second_hash);
4333        if plan.fanout == 2 {
4334            debug_assert_eq!(second_end, rows.len());
4335            return (root, H::finish_branch(hash_state));
4336        }
4337
4338        let mut editor = BranchMut::from_head(&mut root);
4339        let mut range_start = second_end;
4340        for &byte in &plan.buckets[2..plan.fanout] {
4341            let range_end = plan.ends[byte as usize] as usize;
4342            let (child, child_hash) = unsafe {
4343                Self::build_archive_partition_head(
4344                    keys,
4345                    hashes,
4346                    &mut rows[range_start..range_end],
4347                    end_depth + 1,
4348                )
4349            };
4350            let child_count = child.count();
4351            H::push_child(&mut hash_state, byte, child_count, child_hash);
4352            editor.install_child_growing(child.with_key(byte));
4353            range_start = range_end;
4354        }
4355        debug_assert_eq!(range_start, rows.len());
4356
4357        // Rebuild structural aggregates once and install the exact canonical
4358        // summary carried by recursion, avoiding another hash read from direct
4359        // LocalLeaves.
4360        let hash = H::finish_branch(hash_state);
4361        editor.finish_bulk_aggregates(hash);
4362        drop(editor);
4363        (root, hash)
4364    }
4365
4366    /// Build every child of one already-partitioned node concurrently.
4367    ///
4368    /// The partition hands each child a disjoint, contiguous interval of the
4369    /// permutation, so `split_at_mut` is the whole proof that the concurrent
4370    /// recursion cannot alias: disjoint rows, disjoint subtrees, and a node
4371    /// hash summarized over children in canonical edge order.
4372    ///
4373    /// # Safety
4374    ///
4375    /// The caller's `keys`/`hashes` contract must hold, and `rows` must be
4376    /// grouped by `plan` as [`Self::partition_archive_rows`] leaves it.
4377    #[cfg(feature = "parallel")]
4378    unsafe fn build_archive_partition_children(
4379        keys: &[[u8; KEY_LEN]],
4380        hashes: &[H::Digest],
4381        rows: &mut [u32],
4382        plan: &ArchivePartitionPlan,
4383    ) -> (Head<KEY_LEN, O, (), H>, H::Digest) {
4384        use rayon::prelude::*;
4385
4386        let end_depth = plan.end_depth;
4387        let mut remaining: &mut [u32] = rows;
4388        let mut intervals: Vec<(u8, &mut [u32])> = Vec::with_capacity(plan.fanout);
4389        let mut previous_end = 0usize;
4390        for &byte in &plan.buckets[..plan.fanout] {
4391            let end = plan.ends[byte as usize] as usize;
4392            let (child, rest) = remaining.split_at_mut(end - previous_end);
4393            intervals.push((byte, child));
4394            remaining = rest;
4395            previous_end = end;
4396        }
4397        debug_assert!(remaining.is_empty());
4398
4399        let children: Vec<(u8, Head<KEY_LEN, O, (), H>, H::Digest)> = intervals
4400            .into_par_iter()
4401            .map(|(byte, child_rows)| {
4402                // SAFETY: the caller's contract holds for every subinterval,
4403                // and the intervals are pairwise disjoint.
4404                let (head, hash) = unsafe {
4405                    Self::build_archive_partition_head(keys, hashes, child_rows, end_depth + 1)
4406                };
4407                (byte, head, hash)
4408            })
4409            .collect();
4410
4411        Self::assemble_partition_branch(end_depth, plan.initial_slots, children)
4412    }
4413
4414    /// Out-of-place counting-sort twin of [`Self::partition_archive_rows`].
4415    ///
4416    /// The in-place American-flag pass is a chain of dependent swaps and can
4417    /// only ever run on one worker, which is exactly what caps a whole-archive
4418    /// build: six root passes over every row, each a serial storm of cache
4419    /// misses. Counting into per-worker histograms and scattering into a
4420    /// second buffer costs one extra `u32` per row and runs on every worker.
4421    ///
4422    /// The result groups the same rows under the same key bytes. It does not
4423    /// preserve their relative order within a bucket, and does not need to:
4424    /// keys are distinct, so the trie a bucket produces is a function of its
4425    /// key set alone, and children are installed in ascending byte order
4426    /// either way.
4427    #[cfg(feature = "parallel")]
4428    fn partition_archive_rows_parallel(
4429        keys: &[[u8; KEY_LEN]],
4430        rows: &[u32],
4431        depth: usize,
4432    ) -> (ArchivePartitionPlan, Vec<u32>) {
4433        use rayon::prelude::*;
4434
4435        let workers = Self::partition_workers(rows.len());
4436        let stride = rows.len().div_ceil(workers).max(1);
4437
4438        // Every worker narrows the representative's prefix over its own run;
4439        // the shortest agreement wins, which is the same minimum the ordered
4440        // scan converges to.
4441        let representative = &keys[rows[0] as usize];
4442        let end_depth = rows[1..]
4443            .par_chunks(stride)
4444            .map(|chunk| {
4445                let mut shortest = KEY_LEN;
4446                for &row in chunk {
4447                    let key = &keys[row as usize];
4448                    let mut candidate_depth = depth;
4449                    while candidate_depth < shortest {
4450                        let key_index = O::TREE_TO_KEY[candidate_depth];
4451                        if representative[key_index] != key[key_index] {
4452                            shortest = candidate_depth;
4453                            break;
4454                        }
4455                        candidate_depth += 1;
4456                    }
4457                    if shortest == depth {
4458                        break;
4459                    }
4460                }
4461                shortest
4462            })
4463            .min()
4464            .unwrap_or(KEY_LEN);
4465        assert!(
4466            end_depth < KEY_LEN,
4467            "duplicate archive keys cannot form a finite trie",
4468        );
4469
4470        let key_index = O::TREE_TO_KEY[end_depth];
4471        let histograms: Vec<[u32; 256]> = rows
4472            .par_chunks(stride)
4473            .map(|chunk| {
4474                let mut counts = [0u32; 256];
4475                for &row in chunk {
4476                    counts[keys[row as usize][key_index] as usize] += 1;
4477                }
4478                counts
4479            })
4480            .collect();
4481
4482        let mut totals = [0u32; 256];
4483        for counts in &histograms {
4484            for (total, count) in totals.iter_mut().zip(counts.iter()) {
4485                *total += count;
4486            }
4487        }
4488
4489        let mut buckets = [0u8; 256];
4490        let mut fanout = 0usize;
4491        let mut ends = [0u32; 256];
4492        let mut bases = [0u32; 256];
4493        let mut offset = 0u32;
4494        for (byte, &total) in totals.iter().enumerate() {
4495            if total == 0 {
4496                continue;
4497            }
4498            buckets[fanout] = byte as u8;
4499            fanout += 1;
4500            bases[byte] = offset;
4501            offset += total;
4502            ends[byte] = offset;
4503        }
4504        debug_assert_eq!(offset as usize, rows.len());
4505        debug_assert!((2..=256).contains(&fanout));
4506        let initial_slots = if fanout == 2 {
4507            2
4508        } else {
4509            fanout.next_power_of_two()
4510        };
4511
4512        // Each worker's rows for a bucket land after every earlier worker's,
4513        // so the per-worker cursors carve the bucket into disjoint windows.
4514        let mut cursors: Vec<[u32; 256]> = vec![[0u32; 256]; histograms.len()];
4515        let mut running = bases;
4516        for (cursor, counts) in cursors.iter_mut().zip(histograms.iter()) {
4517            for &byte in &buckets[..fanout] {
4518                let byte = byte as usize;
4519                cursor[byte] = running[byte];
4520                running[byte] += counts[byte];
4521            }
4522        }
4523
4524        let mut permuted: Vec<u32> = Vec::with_capacity(rows.len());
4525        let scatter = parallel_union::ScatterPtr(permuted.as_mut_ptr());
4526        rows.par_chunks(stride)
4527            .zip(cursors.into_par_iter())
4528            .for_each(|(chunk, mut cursor)| {
4529                for &row in chunk {
4530                    let byte = keys[row as usize][key_index] as usize;
4531                    let slot = cursor[byte] as usize;
4532                    // SAFETY: slot is inside the buffer and inside this
4533                    // worker's window of this bucket, so no other worker
4534                    // writes it.
4535                    unsafe { scatter.write_at(slot, row) };
4536                    cursor[byte] += 1;
4537                }
4538            });
4539        // SAFETY: the cursors partition `0..rows.len()`, so every slot was
4540        // written exactly once above.
4541        unsafe { permuted.set_len(rows.len()) };
4542
4543        (
4544            ArchivePartitionPlan {
4545                end_depth,
4546                ends,
4547                buckets,
4548                fanout,
4549                initial_slots,
4550            },
4551            permuted,
4552        )
4553    }
4554
4555    /// Install already-built children, in ascending key order, under one
4556    /// branch at `end_depth`.
4557    ///
4558    /// Children arrive as values, so whether they came from archive
4559    /// partitioning, a sorted owned-key build, or parallel recursion is
4560    /// invisible here. The final digest is computed before allocation and
4561    /// installed directly, so no temporary two-child BLAKE node is hashed.
4562    fn assemble_partition_branch(
4563        end_depth: usize,
4564        initial_slots: usize,
4565        children: Vec<(u8, Head<KEY_LEN, O, (), H>, H::Digest)>,
4566    ) -> (Head<KEY_LEN, O, (), H>, H::Digest) {
4567        debug_assert!(children.len() >= 2);
4568        debug_assert!(children.windows(2).all(|pair| pair[0].0 < pair[1].0));
4569        let child_count = children.len();
4570        let leaf_count = children.iter().map(|(_, child, _)| child.count()).sum();
4571        let mut hash_state = H::begin_branch(
4572            children[0].1.childleaf_key(),
4573            &O::TREE_TO_KEY,
4574            end_depth,
4575            child_count,
4576            leaf_count,
4577        );
4578        for &(edge, ref child, digest) in &children {
4579            H::push_child(&mut hash_state, edge, child.count(), digest);
4580        }
4581        let hash = H::finish_branch(hash_state);
4582
4583        let mut drain = children.into_iter();
4584        let (first_bucket, first_head, _) = drain.next().expect("two children");
4585        let (second_bucket, second_head, _) = drain.next().expect("two children");
4586        let body = if initial_slots == 2 {
4587            Branch::new_with_known_hash(
4588                end_depth,
4589                first_head.with_key(first_bucket),
4590                second_head.with_key(second_bucket),
4591                hash,
4592            )
4593        } else {
4594            Branch::new_with_known_hash_capacity(
4595                end_depth,
4596                first_head.with_key(first_bucket),
4597                second_head.with_key(second_bucket),
4598                hash,
4599                initial_slots,
4600            )
4601        };
4602        let mut root = Head::new(0, body);
4603        let mut extra = drain.peekable();
4604        if extra.peek().is_none() {
4605            return (root, hash);
4606        }
4607        let mut editor = BranchMut::from_head(&mut root);
4608        for (byte, child, _) in extra {
4609            editor.install_child_growing(child.with_key(byte));
4610        }
4611        editor.finish_bulk_aggregates(hash);
4612        drop(editor);
4613        (root, hash)
4614    }
4615
4616    /// One trie node's split: where its children diverge, which key bytes are
4617    /// occupied, and where each child's rows now sit inside `rows`.
4618    ///
4619    /// The rows are permuted in place by an American-flag pass, so on return
4620    /// bucket `buckets[i]` owns `rows[ends[buckets[i-1]]..ends[buckets[i]]]`.
4621    #[cfg(any(test, feature = "parallel"))]
4622    fn partition_archive_rows(
4623        keys: &[[u8; KEY_LEN]],
4624        rows: &mut [u32],
4625        depth: usize,
4626    ) -> ArchivePartitionPlan {
4627        // Tighten the representative's common prefix row-by-row. Once the
4628        // candidate reaches the incoming depth, no later row can shorten it.
4629        let representative = &keys[rows[0] as usize];
4630        let mut end_depth = KEY_LEN;
4631        for &row in &rows[1..] {
4632            let key = &keys[row as usize];
4633            let mut candidate_depth = depth;
4634            while candidate_depth < end_depth {
4635                let key_index = O::TREE_TO_KEY[candidate_depth];
4636                if representative[key_index] != key[key_index] {
4637                    end_depth = candidate_depth;
4638                    break;
4639                }
4640                candidate_depth += 1;
4641            }
4642            if end_depth == depth {
4643                break;
4644            }
4645        }
4646        assert!(
4647            end_depth < KEY_LEN,
4648            "duplicate archive keys cannot form a finite trie",
4649        );
4650
4651        let key_index = O::TREE_TO_KEY[end_depth];
4652        let mut ends = [0u32; 256];
4653        let mut occupied = ByteSet::new_empty();
4654        for &row in rows.iter() {
4655            let byte = keys[row as usize][key_index];
4656            let count = &mut ends[byte as usize];
4657            if *count == 0 {
4658                occupied.insert(byte);
4659            }
4660            *count += 1;
4661        }
4662
4663        let mut buckets = [0u8; 256];
4664        let mut fanout = 0usize;
4665        let mut listing = occupied;
4666        while let Some(byte) = listing.drain_next_ascending() {
4667            buckets[fanout] = byte;
4668            fanout += 1;
4669        }
4670        debug_assert!((2..=256).contains(&fanout));
4671        let initial_slots = if fanout == 2 {
4672            2
4673        } else {
4674            fanout.next_power_of_two()
4675        };
4676
4677        // Convert counts into cumulative exclusive ends. `next` tracks the
4678        // first unfilled position in each occupied interval.
4679        let mut next = [0u32; 256];
4680        let mut offset = 0u32;
4681        for &byte in &buckets[..fanout] {
4682            let count = ends[byte as usize];
4683            next[byte as usize] = offset;
4684            offset += count;
4685            ends[byte as usize] = offset;
4686        }
4687        debug_assert_eq!(offset as usize, rows.len());
4688
4689        // American-flag partition. Every swap permanently fills one
4690        // destination position, so this is linear and needs no second buffer.
4691        for &byte in &buckets[..fanout] {
4692            let bucket = byte as usize;
4693            while next[bucket] < ends[bucket] {
4694                let position = next[bucket] as usize;
4695                let row = rows[position] as usize;
4696                let destination = keys[row][key_index] as usize;
4697                if destination == bucket {
4698                    next[bucket] += 1;
4699                } else {
4700                    let destination_slot = next[destination] as usize;
4701                    debug_assert!(destination_slot < ends[destination] as usize);
4702                    rows.swap(position, destination_slot);
4703                    next[destination] += 1;
4704                }
4705            }
4706        }
4707
4708        ArchivePartitionPlan {
4709            end_depth,
4710            ends,
4711            buckets,
4712            fanout,
4713            initial_slots,
4714        }
4715    }
4716}
4717
4718/// Where one trie node's children start and end inside the shared permutation.
4719#[cfg(any(test, feature = "parallel"))]
4720struct ArchivePartitionPlan {
4721    /// Tree depth at which this node's children diverge.
4722    end_depth: usize,
4723    /// Exclusive end offset of each occupied bucket, indexed by key byte.
4724    ends: [u32; 256],
4725    /// The occupied key bytes, ascending, in `buckets[..fanout]`.
4726    buckets: [u8; 256],
4727    fanout: usize,
4728    /// Child-table capacity the branch is born with.
4729    initial_slots: usize,
4730}
4731
4732/// A PATCH is a set with payload: equality (and the root hash) cover the keys
4733/// only, never the values; a type whose identity includes the values must
4734/// compare them itself.
4735impl<const KEY_LEN: usize, O, V, H> PartialEq for PATCH<KEY_LEN, O, V, H>
4736where
4737    O: KeySchema<KEY_LEN>,
4738    H: PatchHash,
4739{
4740    fn eq(&self, other: &Self) -> bool {
4741        self.root.as_ref().map(|root| root.hash()) == other.root.as_ref().map(|root| root.hash())
4742    }
4743}
4744
4745/// Set inclusion over keys: `a <= b` says every key of `a` is in `b`, and
4746/// `partial_cmp` is `None` when neither contains the other.
4747///
4748/// An early-exit walk over both tries with the shape of
4749/// [`PATCH::difference`] that builds nothing: a shared subtree is settled by
4750/// its hash, and a key one side lacks decides the direction the moment it is
4751/// met. Prefer `a <= b` to `a.difference(&b).is_empty()`, which materializes
4752/// the keys it then discards.
4753impl<const KEY_LEN: usize, O, V, H> PartialOrd for PATCH<KEY_LEN, O, V, H>
4754where
4755    O: KeySchema<KEY_LEN>,
4756    H: PatchHash,
4757{
4758    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
4759        match (&self.root, &other.root) {
4760            (None, None) => Some(Ordering::Equal),
4761            (None, Some(_)) => Some(Ordering::Less),
4762            (Some(_), None) => Some(Ordering::Greater),
4763            (Some(root), Some(other_root)) => root.inclusion(other_root, 0),
4764        }
4765    }
4766}
4767
4768impl<const KEY_LEN: usize, O, V, H> Eq for PATCH<KEY_LEN, O, V, H>
4769where
4770    O: KeySchema<KEY_LEN>,
4771    H: PatchHash,
4772{
4773}
4774
4775impl<'a, const KEY_LEN: usize, O, V, H> IntoIterator for &'a PATCH<KEY_LEN, O, V, H>
4776where
4777    O: KeySchema<KEY_LEN>,
4778    H: PatchHash,
4779{
4780    type Item = &'a [u8; KEY_LEN];
4781    type IntoIter = PATCHIterator<'a, KEY_LEN, O, V, H>;
4782
4783    fn into_iter(self) -> Self::IntoIter {
4784        PATCHIterator::new(self)
4785    }
4786}
4787
4788/// An iterator over all keys in a PATCH.
4789/// The keys are returned in key ordering but in random order.
4790pub struct PATCHIterator<
4791    'a,
4792    const KEY_LEN: usize,
4793    O: KeySchema<KEY_LEN>,
4794    V,
4795    H: PatchHash = XorSip128,
4796> {
4797    // Root-to-leaf branch depths strictly increase within 0..KEY_LEN, so
4798    // seeding from the real root branch keeps the live stack within KEY_LEN.
4799    stack: ArrayVec<std::slice::Iter<'a, Option<Head<KEY_LEN, O, V, H>>>, KEY_LEN>,
4800    // A singleton root has no branch frame, including when KEY_LEN is zero.
4801    pending_leaf: Option<&'a [u8; KEY_LEN]>,
4802    remaining: usize,
4803}
4804
4805impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
4806    PATCHIterator<'a, KEY_LEN, O, V, H>
4807{
4808    /// Creates an iterator over all keys in `patch`.
4809    pub fn new(patch: &'a PATCH<KEY_LEN, O, V, H>) -> Self {
4810        let mut r = PATCHIterator {
4811            stack: ArrayVec::new(),
4812            pending_leaf: None,
4813            remaining: patch.len().min(usize::MAX as u64) as usize,
4814        };
4815        if let Some(root) = &patch.root {
4816            match root.body_ref() {
4817                BodyRef::Leaf(leaf) => r.pending_leaf = Some(&leaf.key),
4818                BodyRef::LocalLeaf(key) => r.pending_leaf = Some(key),
4819                BodyRef::Branch(branch) => r.stack.push(branch.child_table.iter()),
4820            }
4821        }
4822        r
4823    }
4824}
4825
4826impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Iterator
4827    for PATCHIterator<'a, KEY_LEN, O, V, H>
4828{
4829    type Item = &'a [u8; KEY_LEN];
4830
4831    fn next(&mut self) -> Option<Self::Item> {
4832        if let Some(key) = self.pending_leaf.take() {
4833            self.remaining = self.remaining.saturating_sub(1);
4834            return Some(key);
4835        }
4836        let mut iter = self.stack.last_mut()?;
4837        loop {
4838            if let Some(child) = iter.next() {
4839                if let Some(child) = child {
4840                    match child.body_ref() {
4841                        BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => {
4842                            self.remaining = self.remaining.saturating_sub(1);
4843                            // Use the safe accessor on the child reference to obtain the leaf key bytes.
4844                            return Some(child.childleaf_key());
4845                        }
4846                        BodyRef::Branch(branch) => {
4847                            self.stack.push(branch.child_table.iter());
4848                            iter = self.stack.last_mut()?;
4849                        }
4850                    }
4851                }
4852            } else {
4853                self.stack.pop();
4854                iter = self.stack.last_mut()?;
4855            }
4856        }
4857    }
4858
4859    fn size_hint(&self) -> (usize, Option<usize>) {
4860        (self.remaining, Some(self.remaining))
4861    }
4862}
4863
4864impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> ExactSizeIterator
4865    for PATCHIterator<'a, KEY_LEN, O, V, H>
4866{
4867}
4868
4869impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> std::iter::FusedIterator
4870    for PATCHIterator<'a, KEY_LEN, O, V, H>
4871{
4872}
4873
4874/// An iterator over every key in a PATCH, returned in key order.
4875///
4876/// Keys are yielded in lexicographic key order regardless of their physical
4877/// layout in the underlying tree. This iterator walks the full tree and does
4878/// not accept a prefix filter. For prefix-aware iteration, use
4879/// [`PATCHPrefixIterator`], constructed via [`PATCH::iter_prefix_count`].
4880pub struct PATCHOrderedIterator<
4881    'a,
4882    const KEY_LEN: usize,
4883    O: KeySchema<KEY_LEN>,
4884    V,
4885    H: PatchHash = XorSip128,
4886> {
4887    stack: Vec<ArrayVec<&'a Head<KEY_LEN, O, V, H>, 256>>,
4888    remaining: usize,
4889}
4890
4891impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
4892    PATCHOrderedIterator<'a, KEY_LEN, O, V, H>
4893{
4894    pub fn new(patch: &'a PATCH<KEY_LEN, O, V, H>) -> Self {
4895        let mut r = PATCHOrderedIterator {
4896            stack: Vec::with_capacity(KEY_LEN),
4897            remaining: patch.len().min(usize::MAX as u64) as usize,
4898        };
4899        if let Some(root) = &patch.root {
4900            r.stack.push(ArrayVec::new());
4901            match root.body_ref() {
4902                BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => {
4903                    r.stack[0].push(root);
4904                }
4905                BodyRef::Branch(branch) => {
4906                    let first_level = &mut r.stack[0];
4907                    first_level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
4908                    first_level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
4909                }
4910            }
4911        }
4912        r
4913    }
4914}
4915
4916// --- Owned consuming iterators ---
4917/// Iterator that owns a PATCH and yields keys in key-order. The owner set is
4918/// retained until every queued LocalLeaf has been copied out.
4919pub struct PATCHIntoIterator<
4920    const KEY_LEN: usize,
4921    O: KeySchema<KEY_LEN>,
4922    V,
4923    H: PatchHash = XorSip128,
4924> {
4925    // Field order is deliberate: queued Heads drop before the owner cover.
4926    queue: Vec<Head<KEY_LEN, O, V, H>>,
4927    remaining: usize,
4928    _owners: Option<Arc<OwnerCover>>,
4929}
4930
4931impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
4932    PATCHIntoIterator<KEY_LEN, O, V, H>
4933{
4934}
4935
4936impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Iterator
4937    for PATCHIntoIterator<KEY_LEN, O, V, H>
4938{
4939    type Item = [u8; KEY_LEN];
4940
4941    fn next(&mut self) -> Option<Self::Item> {
4942        let q = &mut self.queue;
4943        while let Some(mut head) = q.pop() {
4944            // Match on the mutable body directly. For leaves we can return the
4945            // stored key (the array is Copy), for branches we take children out
4946            // of the table and push them onto the stack so they are visited
4947            // depth-first.
4948            match head.body_mut() {
4949                BodyMut::Leaf(leaf) => {
4950                    self.remaining = self.remaining.saturating_sub(1);
4951                    return Some(leaf.key);
4952                }
4953                BodyMut::LocalLeaf(bytes) => {
4954                    self.remaining = self.remaining.saturating_sub(1);
4955                    return Some(*bytes);
4956                }
4957                BodyMut::Branch(branch) => {
4958                    for slot in branch.child_table.iter_mut().rev() {
4959                        if let Some(c) = slot.take() {
4960                            q.push(c);
4961                        }
4962                    }
4963                }
4964            }
4965        }
4966        None
4967    }
4968}
4969
4970/// Iterator that owns a PATCH and yields keys in key order.
4971pub struct PATCHIntoOrderedIterator<
4972    const KEY_LEN: usize,
4973    O: KeySchema<KEY_LEN>,
4974    V,
4975    H: PatchHash = XorSip128,
4976> {
4977    // Field order is deliberate: queued Heads drop before the owner cover.
4978    queue: Vec<Head<KEY_LEN, O, V, H>>,
4979    remaining: usize,
4980    _owners: Option<Arc<OwnerCover>>,
4981}
4982
4983impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Iterator
4984    for PATCHIntoOrderedIterator<KEY_LEN, O, V, H>
4985{
4986    type Item = [u8; KEY_LEN];
4987
4988    fn next(&mut self) -> Option<Self::Item> {
4989        let q = &mut self.queue;
4990        while let Some(mut head) = q.pop() {
4991            // Match the mutable body directly — we own `head` so calling
4992            // `body_mut()` is safe and allows returning the copied leaf key
4993            // or mutating the branch child table in-place.
4994            match head.body_mut() {
4995                BodyMut::Leaf(leaf) => {
4996                    self.remaining = self.remaining.saturating_sub(1);
4997                    return Some(leaf.key);
4998                }
4999                BodyMut::LocalLeaf(bytes) => {
5000                    self.remaining = self.remaining.saturating_sub(1);
5001                    return Some(*bytes);
5002                }
5003                BodyMut::Branch(branch) => {
5004                    let slice: &mut [Option<Head<KEY_LEN, O, V, H>>] = &mut branch.child_table;
5005                    // Sort children by their byte-key, placing empty slots (None)
5006                    // after all occupied slots. Using `sort_unstable_by_key` with
5007                    // a simple key projection is clearer than a custom
5008                    // comparator; it also avoids allocating temporaries. The
5009                    // old comparator manually handled None/Some cases — we
5010                    // express that intent directly by sorting on the tuple
5011                    // (is_none, key_opt).
5012                    slice
5013                        .sort_unstable_by_key(|opt| (opt.is_none(), opt.as_ref().map(|h| h.key())));
5014                    for slot in slice.iter_mut().rev() {
5015                        if let Some(c) = slot.take() {
5016                            q.push(c);
5017                        }
5018                    }
5019                }
5020            }
5021        }
5022        None
5023    }
5024}
5025
5026impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> IntoIterator
5027    for PATCH<KEY_LEN, O, V, H>
5028{
5029    type Item = [u8; KEY_LEN];
5030    type IntoIter = PATCHIntoIterator<KEY_LEN, O, V, H>;
5031
5032    fn into_iter(self) -> Self::IntoIter {
5033        let remaining = self.len().min(usize::MAX as u64) as usize;
5034        let PATCH { root, owners } = self;
5035        let mut q = Vec::new();
5036        if let Some(root) = root {
5037            q.push(root);
5038        }
5039        PATCHIntoIterator {
5040            queue: q,
5041            remaining,
5042            _owners: owners,
5043        }
5044    }
5045}
5046
5047impl<const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> PATCH<KEY_LEN, O, V, H> {
5048    /// Consume and return an iterator that yields keys in key order.
5049    pub fn into_iter_ordered(self) -> PATCHIntoOrderedIterator<KEY_LEN, O, V, H> {
5050        let remaining = self.len().min(usize::MAX as u64) as usize;
5051        let PATCH { root, owners } = self;
5052        let mut q = Vec::new();
5053        if let Some(root) = root {
5054            q.push(root);
5055        }
5056        PATCHIntoOrderedIterator {
5057            queue: q,
5058            remaining,
5059            _owners: owners,
5060        }
5061    }
5062
5063    /// Consume this PATCH and enumerate each distinct tree-ordered prefix once.
5064    ///
5065    /// Unlike mapping the full consuming iterator and deduplicating it, this
5066    /// traversal stops at `PREFIX_LEN`: suffix subtrees are dropped without
5067    /// visiting their leaves. `PREFIX_LEN` must end at a segment boundary.
5068    pub fn into_prefixes<const PREFIX_LEN: usize>(
5069        self,
5070    ) -> PATCHIntoPrefixSetIterator<KEY_LEN, PREFIX_LEN, O, V, H> {
5071        const {
5072            assert!(PREFIX_LEN > 0, "a prefix set needs at least one byte");
5073            assert!(PREFIX_LEN <= KEY_LEN);
5074            if PREFIX_LEN < KEY_LEN {
5075                assert!(
5076                    <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
5077                        [O::TREE_TO_KEY[PREFIX_LEN - 1]]
5078                        != <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
5079                            [O::TREE_TO_KEY[PREFIX_LEN]],
5080                    "PREFIX_LEN must align to a segment boundary",
5081                );
5082            }
5083        }
5084
5085        let PATCH { root, owners } = self;
5086        let mut queue = Vec::new();
5087        if let Some(root) = root {
5088            queue.push(root);
5089        }
5090        PATCHIntoPrefixSetIterator {
5091            queue,
5092            _owners: owners,
5093        }
5094    }
5095}
5096
5097/// Consuming iterator over the distinct prefixes at one PATCH segment boundary.
5098///
5099/// The iterator owns an immutable PATCH snapshot and drops every suffix subtree
5100/// as soon as its one projected member has been emitted. This is useful when an
5101/// iterator must outlive the snapshot value from which it was constructed.
5102pub struct PATCHIntoPrefixSetIterator<
5103    const KEY_LEN: usize,
5104    const PREFIX_LEN: usize,
5105    O: KeySchema<KEY_LEN>,
5106    V,
5107    H: PatchHash = XorSip128,
5108> {
5109    // Field order is deliberate: queued Heads drop before the owner cover.
5110    queue: Vec<Head<KEY_LEN, O, V, H>>,
5111    _owners: Option<Arc<OwnerCover>>,
5112}
5113
5114impl<const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Iterator
5115    for PATCHIntoPrefixSetIterator<KEY_LEN, PREFIX_LEN, O, V, H>
5116{
5117    type Item = [u8; PREFIX_LEN];
5118
5119    fn next(&mut self) -> Option<Self::Item> {
5120        while let Some(head) = self.queue.pop() {
5121            if head.end_depth() >= PREFIX_LEN {
5122                let key = O::tree_ordered(head.childleaf_key());
5123                return Some(key[..PREFIX_LEN].try_into().unwrap());
5124            }
5125
5126            let BodyRef::Branch(branch) = head.body_ref() else {
5127                unreachable!("a leaf cannot end before a valid prefix boundary");
5128            };
5129            // Clone one-word persistent Heads from the immutable branch. Using
5130            // `body_mut` here would copy-on-write every shared branch merely
5131            // because the iterator owns a clone of the PATCH root.
5132            let mut children = ArrayVec::<&Head<KEY_LEN, O, V, H>, 256>::new();
5133            children.extend(branch.child_table.iter().filter_map(Option::as_ref));
5134            children.sort_unstable_by_key(|child| child.key());
5135            for child in children.into_iter().rev() {
5136                self.queue.push((*child).clone());
5137            }
5138        }
5139        None
5140    }
5141}
5142
5143impl<const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5144    std::iter::FusedIterator for PATCHIntoPrefixSetIterator<KEY_LEN, PREFIX_LEN, O, V, H>
5145{
5146}
5147
5148impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> Iterator
5149    for PATCHOrderedIterator<'a, KEY_LEN, O, V, H>
5150{
5151    type Item = &'a [u8; KEY_LEN];
5152
5153    fn next(&mut self) -> Option<Self::Item> {
5154        let mut level = self.stack.last_mut()?;
5155        loop {
5156            if let Some(child) = level.pop() {
5157                match child.body_ref() {
5158                    BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => {
5159                        self.remaining = self.remaining.saturating_sub(1);
5160                        return Some(child.childleaf_key());
5161                    }
5162                    BodyRef::Branch(branch) => {
5163                        self.stack.push(ArrayVec::new());
5164                        level = self.stack.last_mut()?;
5165                        level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
5166                        level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
5167                    }
5168                }
5169            } else {
5170                self.stack.pop();
5171                level = self.stack.last_mut()?;
5172            }
5173        }
5174    }
5175
5176    fn size_hint(&self) -> (usize, Option<usize>) {
5177        (self.remaining, Some(self.remaining))
5178    }
5179}
5180
5181impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> ExactSizeIterator
5182    for PATCHOrderedIterator<'a, KEY_LEN, O, V, H>
5183{
5184}
5185
5186impl<'a, const KEY_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash> std::iter::FusedIterator
5187    for PATCHOrderedIterator<'a, KEY_LEN, O, V, H>
5188{
5189}
5190
5191/// A zero-copy set view over distinct prefixes at one PATCH segment boundary.
5192///
5193/// The view borrows the physical trie. It neither allocates a second PATCH nor
5194/// gives suffix multiplicity semantic weight. Iteration collapses every suffix
5195/// subtree to its one shared prefix.
5196#[derive(Clone, Copy)]
5197pub struct PATCHPrefixSet<
5198    'a,
5199    const KEY_LEN: usize,
5200    const PREFIX_LEN: usize,
5201    O: KeySchema<KEY_LEN>,
5202    V,
5203    H: PatchHash = XorSip128,
5204> {
5205    patch: &'a PATCH<KEY_LEN, O, V, H>,
5206}
5207
5208impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5209    PATCHPrefixSet<'a, KEY_LEN, PREFIX_LEN, O, V, H>
5210{
5211    fn new(patch: &'a PATCH<KEY_LEN, O, V, H>) -> Self {
5212        const {
5213            assert!(PREFIX_LEN > 0, "a prefix set needs at least one byte");
5214            assert!(PREFIX_LEN <= KEY_LEN);
5215            if PREFIX_LEN < KEY_LEN {
5216                assert!(
5217                    <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
5218                        [O::TREE_TO_KEY[PREFIX_LEN - 1]]
5219                        != <O as KeySchema<KEY_LEN>>::Segmentation::SEGMENTS
5220                            [O::TREE_TO_KEY[PREFIX_LEN]],
5221                    "PREFIX_LEN must align to a segment boundary",
5222                );
5223            }
5224        }
5225        Self { patch }
5226    }
5227
5228    /// Whether at least one physical key has this projected prefix.
5229    pub fn contains(&self, prefix: &[u8; PREFIX_LEN]) -> bool {
5230        self.patch.has_prefix(prefix)
5231    }
5232
5233    /// Enumerate each projected prefix once in tree order.
5234    pub fn iter(&self) -> PATCHPrefixSetIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H> {
5235        PATCHPrefixSetIterator {
5236            inner: self.patch.iter_prefix_count(),
5237        }
5238    }
5239
5240    /// Whether this projected set has no members.
5241    pub fn is_empty(&self) -> bool {
5242        self.patch.is_empty()
5243    }
5244
5245    /// Intersect this projected set with an ordinary key-only PATCH.
5246    ///
5247    /// The returned PATCH retains `other`'s hash policy, making this suitable
5248    /// for filtering a typed semantic cover through a larger physical index.
5249    pub fn intersection<OH: PatchHash>(
5250        &self,
5251        other: &PATCH<PREFIX_LEN, IdentitySchema, (), OH>,
5252    ) -> PATCH<PREFIX_LEN, IdentitySchema, (), OH> {
5253        let keys = other
5254            .iter_ordered()
5255            .filter(|key| self.contains(key))
5256            .copied()
5257            .collect();
5258        PATCH::from_owned_keys(keys)
5259    }
5260}
5261
5262/// Iterator over a [`PATCHPrefixSet`].
5263pub struct PATCHPrefixSetIterator<
5264    'a,
5265    const KEY_LEN: usize,
5266    const PREFIX_LEN: usize,
5267    O: KeySchema<KEY_LEN>,
5268    V,
5269    H: PatchHash = XorSip128,
5270> {
5271    inner: PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H>,
5272}
5273
5274impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5275    Iterator for PATCHPrefixSetIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H>
5276{
5277    type Item = [u8; PREFIX_LEN];
5278
5279    fn next(&mut self) -> Option<Self::Item> {
5280        self.inner.next().map(|(prefix, _count)| prefix)
5281    }
5282}
5283
5284impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5285    std::iter::FusedIterator for PATCHPrefixSetIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H>
5286{
5287}
5288
5289/// An iterator over all keys in a PATCH that have a given prefix.
5290/// The keys are returned in tree ordering and in tree order.
5291pub struct PATCHPrefixIterator<
5292    'a,
5293    const KEY_LEN: usize,
5294    const PREFIX_LEN: usize,
5295    O: KeySchema<KEY_LEN>,
5296    V,
5297    H: PatchHash = XorSip128,
5298> {
5299    stack: Vec<ArrayVec<&'a Head<KEY_LEN, O, V, H>, 256>>,
5300}
5301
5302impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5303    PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H>
5304{
5305    fn new(patch: &'a PATCH<KEY_LEN, O, V, H>) -> Self {
5306        const {
5307            assert!(PREFIX_LEN <= KEY_LEN);
5308        }
5309        let mut r = PATCHPrefixIterator {
5310            stack: Vec::with_capacity(PREFIX_LEN),
5311        };
5312        if let Some(root) = &patch.root {
5313            r.stack.push(ArrayVec::new());
5314            if root.end_depth() >= PREFIX_LEN {
5315                r.stack[0].push(root);
5316            } else {
5317                let BodyRef::Branch(branch) = root.body_ref() else {
5318                    unreachable!();
5319                };
5320                let first_level = &mut r.stack[0];
5321                first_level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
5322                first_level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
5323            }
5324        }
5325        r
5326    }
5327}
5328
5329impl<'a, const KEY_LEN: usize, const PREFIX_LEN: usize, O: KeySchema<KEY_LEN>, V, H: PatchHash>
5330    Iterator for PATCHPrefixIterator<'a, KEY_LEN, PREFIX_LEN, O, V, H>
5331{
5332    type Item = ([u8; PREFIX_LEN], u64);
5333
5334    fn next(&mut self) -> Option<Self::Item> {
5335        let mut level = self.stack.last_mut()?;
5336        loop {
5337            if let Some(child) = level.pop() {
5338                if child.end_depth() >= PREFIX_LEN {
5339                    let key = O::tree_ordered(child.childleaf_key());
5340                    let suffix_count = child.count();
5341                    return Some((key[0..PREFIX_LEN].try_into().unwrap(), suffix_count));
5342                } else {
5343                    let BodyRef::Branch(branch) = child.body_ref() else {
5344                        unreachable!();
5345                    };
5346                    self.stack.push(ArrayVec::new());
5347                    level = self.stack.last_mut()?;
5348                    level.extend(branch.child_table.iter().filter_map(|c| c.as_ref()));
5349                    level.sort_unstable_by_key(|&k| Reverse(k.key())); // We need to reverse here because we pop from the vec.
5350                }
5351            } else {
5352                self.stack.pop();
5353                level = self.stack.last_mut()?;
5354            }
5355        }
5356    }
5357}
5358
5359#[cfg(test)]
5360mod tests {
5361    use super::*;
5362    use itertools::Itertools;
5363    use proptest::prelude::*;
5364    use std::collections::HashSet;
5365    use std::convert::TryInto;
5366    use std::iter::FromIterator;
5367    use std::mem;
5368    use std::sync::atomic::{AtomicUsize, Ordering};
5369
5370    #[repr(C, align(16))]
5371    struct AlignedArchivePair([[u8; 16]; 2]);
5372
5373    #[repr(C, align(16))]
5374    struct AlignedArchiveKey<const KEY_LEN: usize>([u8; KEY_LEN]);
5375
5376    fn blake_patch<const KEY_LEN: usize>(
5377        keys: &[[u8; KEY_LEN]],
5378    ) -> PATCH<KEY_LEN, IdentitySchema, (), Blake3Merkle> {
5379        let mut patch = PATCH::new();
5380        for key in keys {
5381            patch.insert(&Entry::<KEY_LEN, (), Blake3Merkle>::new(key));
5382        }
5383        patch
5384    }
5385
5386    fn inventory_keys<const KEY_LEN: usize>(len: usize) -> Vec<[u8; KEY_LEN]> {
5387        assert!(KEY_LEN >= 8);
5388        (0..len)
5389            .map(|index| {
5390                let mut key = [0u8; KEY_LEN];
5391                key[..8].copy_from_slice(&(index as u64).to_be_bytes());
5392                let mut state = (index as u64) ^ 0x243f_6a88_85a3_08d3;
5393                for byte in &mut key[8..] {
5394                    state ^= state >> 12;
5395                    state ^= state << 25;
5396                    state ^= state >> 27;
5397                    *byte = state.wrapping_mul(0x2545_f491_4f6c_dd1d) as u8;
5398                }
5399                key
5400            })
5401            .collect()
5402    }
5403
5404    #[test]
5405    fn bulk_owned_build_canonicalizes_order_duplicates_and_edit_history() {
5406        let keys = inventory_keys::<16>(4_097);
5407        let mut noisy = keys.clone();
5408        noisy.reverse();
5409        noisy.extend(keys.iter().step_by(7).copied());
5410        noisy.rotate_left(997);
5411
5412        let bulk = PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_keys(noisy.clone());
5413        let bulk_reversed =
5414            PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_keys(noisy.into_iter().rev());
5415        let inserted = blake_patch(&keys);
5416        let mut edited = blake_patch(&keys.iter().rev().copied().collect::<Vec<_>>());
5417        for key in keys.iter().step_by(5) {
5418            edited.remove(key);
5419        }
5420        for key in keys.iter().step_by(5).rev() {
5421            edited.insert(&Entry::new(key));
5422        }
5423
5424        let expected_root = inserted.merkle_root();
5425        assert_eq!(bulk.len(), keys.len() as u64);
5426        assert_eq!(bulk.merkle_root(), expected_root);
5427        assert_eq!(bulk_reversed.merkle_root(), expected_root);
5428        assert_eq!(edited.merkle_root(), expected_root);
5429        assert_eq!(bulk, inserted);
5430        assert_eq!(
5431            bulk.merkle_node(&[])
5432                .unwrap()
5433                .items_after(None, usize::MAX)
5434                .collect::<Vec<_>>(),
5435            keys
5436        );
5437    }
5438
5439    #[test]
5440    fn bulk_owned_build_handles_empty_singleton_and_already_canonical_input() {
5441        let empty = PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_keys([]);
5442        assert!(empty.is_empty());
5443        assert_eq!(empty.merkle_root(), None);
5444
5445        let key = [42; 16];
5446        let singleton = PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_keys([key]);
5447        assert_eq!(singleton.len(), 1);
5448        assert_eq!(singleton.merkle_node(&[]).unwrap().representative(), &key);
5449
5450        let canonical = inventory_keys::<16>(1_024);
5451        let bulk = PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_keys(canonical.clone());
5452        assert_eq!(
5453            bulk.merkle_node(&[])
5454                .unwrap()
5455                .items_after(None, usize::MAX)
5456                .collect::<Vec<_>>(),
5457            canonical
5458        );
5459    }
5460
5461    static BULK_LEAF_HASHES: AtomicUsize = AtomicUsize::new(0);
5462    static BULK_BRANCH_HASHES: AtomicUsize = AtomicUsize::new(0);
5463
5464    struct CountingBlake3;
5465    impl sealed::Sealed for CountingBlake3 {}
5466    impl PatchHash for CountingBlake3 {
5467        type Digest = [u8; 32];
5468        type BranchState = blake3::Hasher;
5469        const COMMUTATIVE_BRANCH: bool = false;
5470        const INCREMENTAL_BRANCH: bool = false;
5471
5472        fn init() {
5473            Blake3Merkle::init();
5474        }
5475
5476        fn leaf(bytes: &[u8]) -> Self::Digest {
5477            BULK_LEAF_HASHES.fetch_add(1, Ordering::Relaxed);
5478            Blake3Merkle::leaf(bytes)
5479        }
5480
5481        fn begin_branch(
5482            representative: &[u8],
5483            tree_to_key: &[usize],
5484            end_depth: usize,
5485            child_count: usize,
5486            leaf_count: u64,
5487        ) -> Self::BranchState {
5488            Blake3Merkle::begin_branch(
5489                representative,
5490                tree_to_key,
5491                end_depth,
5492                child_count,
5493                leaf_count,
5494            )
5495        }
5496
5497        fn push_child(
5498            state: &mut Self::BranchState,
5499            edge: u8,
5500            leaf_count: u64,
5501            digest: Self::Digest,
5502        ) {
5503            Blake3Merkle::push_child(state, edge, leaf_count, digest);
5504        }
5505
5506        fn finish_branch(state: Self::BranchState) -> Self::Digest {
5507            BULK_BRANCH_HASHES.fetch_add(1, Ordering::Relaxed);
5508            Blake3Merkle::finish_branch(state)
5509        }
5510
5511        fn edit_branch(
5512            _current: Self::Digest,
5513            _edge: u8,
5514            _old: Option<Self::Digest>,
5515            _new: Option<Self::Digest>,
5516        ) -> Self::Digest {
5517            unreachable!("the counting Merkle policy is not incremental")
5518        }
5519    }
5520
5521    #[test]
5522    fn bulk_owned_build_hashes_each_final_node_once_plus_debug_audit() {
5523        BULK_LEAF_HASHES.store(0, Ordering::Relaxed);
5524        BULK_BRANCH_HASHES.store(0, Ordering::Relaxed);
5525        let keys = inventory_keys::<16>(10_000);
5526        let patch = PATCH::<16, IdentitySchema, (), CountingBlake3>::from_owned_keys(keys.clone());
5527        let (branches, _, heap_leaves, archive_leaves) = patch.node_stats();
5528
5529        assert_eq!(patch.len(), keys.len() as u64);
5530        assert_eq!(heap_leaves, keys.len() as u64);
5531        assert_eq!(archive_leaves, 0);
5532        assert_eq!(BULK_LEAF_HASHES.load(Ordering::Relaxed), keys.len());
5533        // The build itself finishes each branch once. Debug builds then
5534        // deliberately recompute it once inside Branch's invariant audit;
5535        // optimized production builds compile that verification away.
5536        let expected_branch_hashes = branches as usize * if cfg!(debug_assertions) { 2 } else { 1 };
5537        assert_eq!(
5538            BULK_BRANCH_HASHES.load(Ordering::Relaxed),
5539            expected_branch_hashes
5540        );
5541    }
5542
5543    struct BulkUnwindProbe(Arc<AtomicUsize>);
5544
5545    impl Drop for BulkUnwindProbe {
5546        fn drop(&mut self) {
5547            self.0.fetch_add(1, Ordering::Relaxed);
5548        }
5549    }
5550
5551    #[test]
5552    fn wider_known_hash_branch_owns_every_child_during_unwind() {
5553        let drops = Arc::new(AtomicUsize::new(0));
5554        let keys = [[1, 0], [2, 0], [3, 0]];
5555        let digests = keys.map(|key| Blake3Merkle::leaf(&key));
5556        let mut state = Blake3Merkle::begin_branch(
5557            &keys[0],
5558            &<IdentitySchema as KeySchema<2>>::TREE_TO_KEY,
5559            0,
5560            keys.len(),
5561            keys.len() as u64,
5562        );
5563        for (edge, digest) in [1, 2, 3].into_iter().zip(digests) {
5564            Blake3Merkle::push_child(&mut state, edge, 1, digest);
5565        }
5566        let final_hash = Blake3Merkle::finish_branch(state);
5567
5568        let leaf = |key: &[u8; 2]| {
5569            // SAFETY: every returned allocation is immediately transferred
5570            // into exactly one owning Head.
5571            unsafe {
5572                Leaf::<2, BulkUnwindProbe, Blake3Merkle>::new(key, BulkUnwindProbe(drops.clone()))
5573            }
5574        };
5575        type ProbeHead = Head<2, IdentitySchema, BulkUnwindProbe, Blake3Merkle>;
5576        let first = ProbeHead::new(0, leaf(&keys[0])).with_key(1);
5577        let second = ProbeHead::new(0, leaf(&keys[1])).with_key(2);
5578        let third = ProbeHead::new(0, leaf(&keys[2])).with_key(3);
5579        let body = Branch::new_with_known_hash_capacity(0, first, second, final_hash, 4);
5580        let mut root = Head::new(0, body);
5581
5582        let panic = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
5583            let mut editor = BranchMut::from_head(&mut root);
5584            editor.install_child_growing(third);
5585            // This is the only interval where the branch contains every
5586            // child but its structural counts still describe the initial
5587            // pair. BranchMut's Drop must nevertheless return the current
5588            // allocation to `root`, whose ordinary destructor owns all three.
5589            panic!("interrupt wider bottom-up assembly");
5590        }));
5591        assert!(panic.is_err());
5592        drop(root);
5593        assert_eq!(drops.load(Ordering::Relaxed), keys.len());
5594    }
5595
5596    fn merkle_inventory<const KEY_LEN: usize, V>(
5597        node: PATCHMerkleNode<'_, KEY_LEN, V>,
5598        out: &mut Vec<(Vec<u8>, [u8; 32], u64, usize, [u8; KEY_LEN], Vec<u8>)>,
5599    ) {
5600        let child_edges = node.children().map(|(edge, _)| edge).collect::<Vec<_>>();
5601        out.push((
5602            node.prefix().to_vec(),
5603            node.digest(),
5604            node.leaf_count(),
5605            node.end_depth(),
5606            *node.representative(),
5607            child_edges,
5608        ));
5609        for (_, child) in node.children() {
5610            merkle_inventory(child, out);
5611        }
5612    }
5613
5614    #[test]
5615    fn merkle_prefix_lookup_canonicalizes_compressed_paths_and_orders_children() {
5616        let patch = blake_patch(&[[1, 2, 3, 255], [1, 2, 3, 0]]);
5617        let root = patch.merkle_node(&[]).expect("nonempty PATCH");
5618        assert_eq!(root.end_depth(), 3);
5619        assert_eq!(root.prefix(), &[1, 2, 3]);
5620        assert_eq!(root.leaf_count(), 2);
5621        assert!(!root.is_leaf());
5622
5623        for request in [&[][..], &[1][..], &[1, 2][..], &[1, 2, 3][..]] {
5624            let located = patch.merkle_node(request).expect("compressed prefix");
5625            assert_eq!(located.digest(), root.digest());
5626            assert_eq!(located.prefix(), &[1, 2, 3]);
5627        }
5628        assert!(patch.merkle_node(&[1, 2, 4]).is_none());
5629        assert!(patch.merkle_node(&[1, 2, 3, 0, 0]).is_none());
5630
5631        let children = root.children().collect::<Vec<_>>();
5632        assert_eq!(
5633            children.iter().map(|(edge, _)| *edge).collect::<Vec<_>>(),
5634            [0, 255]
5635        );
5636        for (edge, child) in children {
5637            assert!(child.is_leaf());
5638            assert_eq!(child.leaf_count(), 1);
5639            assert_eq!(child.end_depth(), 4);
5640            assert_eq!(child.representative()[3], edge);
5641            assert_eq!(child.prefix(), child.representative());
5642            assert_eq!(child.children().len(), 0);
5643        }
5644
5645        let debug = format!("{root:?}");
5646        assert!(debug.contains("PATCHMerkleNode"));
5647        assert!(!debug.contains("child_table"));
5648        assert!(!debug.contains("Branch"));
5649    }
5650
5651    #[test]
5652    fn merkle_prefix_lookup_reports_compressed_shape_mismatches_without_aliasing_nodes() {
5653        let compressed = blake_patch(&[[1, 2, 3, 0], [1, 2, 3, 255]]);
5654        let split_earlier = blake_patch(&[[1, 2, 3, 0], [1, 2, 4, 0]]);
5655
5656        let compressed_root = compressed.merkle_node(&[]).expect("root");
5657        assert_eq!(compressed_root.prefix(), &[1, 2, 3]);
5658        let corresponding = split_earlier
5659            .merkle_node(compressed_root.prefix())
5660            .expect("the shared key still exists");
5661        assert!(corresponding.is_leaf());
5662        assert_eq!(corresponding.prefix(), &[1, 2, 3, 0]);
5663        assert_ne!(corresponding.digest(), compressed_root.digest());
5664        assert_ne!(corresponding.leaf_count(), compressed_root.leaf_count());
5665
5666        let earlier_root = split_earlier.merkle_node(&[]).expect("root");
5667        assert_eq!(earlier_root.prefix(), &[1, 2]);
5668        let covered = compressed
5669            .merkle_node(earlier_root.prefix())
5670            .expect("request ends inside compressed path");
5671        assert_eq!(covered.prefix(), &[1, 2, 3]);
5672        assert_eq!(covered.digest(), compressed_root.digest());
5673    }
5674
5675    #[test]
5676    fn merkle_traversal_is_history_independent() {
5677        let keys: Vec<[u8; 4]> = (0u8..64)
5678            .map(|i| [i.wrapping_mul(73), i / 4, i.wrapping_mul(11), 255 - i])
5679            .collect();
5680        let forward = blake_patch(&keys);
5681        let mut reversed_keys = keys.clone();
5682        reversed_keys.reverse();
5683        let reversed = blake_patch(&reversed_keys);
5684        let mut edited = reversed.clone();
5685        for key in keys.iter().step_by(3) {
5686            edited.remove(key);
5687        }
5688        for key in keys.iter().step_by(3).rev() {
5689            edited.insert(&Entry::<4, (), Blake3Merkle>::new(key));
5690        }
5691
5692        let inventory = |patch: &PATCH<4, IdentitySchema, (), Blake3Merkle>| {
5693            let mut out = Vec::new();
5694            merkle_inventory(patch.merkle_node(&[]).expect("root"), &mut out);
5695            out
5696        };
5697        assert_eq!(inventory(&forward), inventory(&reversed));
5698        assert_eq!(inventory(&forward), inventory(&edited));
5699
5700        let mut expected = keys.clone();
5701        expected.sort_unstable();
5702        for patch in [&forward, &reversed, &edited] {
5703            let root = patch.merkle_node(&[]).expect("root");
5704            let mut paged = Vec::new();
5705            let mut after = None;
5706            loop {
5707                let page = root.items_after(after.as_ref(), 7).collect::<Vec<_>>();
5708                if page.is_empty() {
5709                    break;
5710                }
5711                after = page.last().copied();
5712                paged.extend(page);
5713            }
5714            assert_eq!(paged, expected);
5715        }
5716    }
5717
5718    #[test]
5719    fn merkle_items_are_prefix_scoped_exclusive_and_hard_bounded() {
5720        let mut keys = Vec::new();
5721        for i in 0u8..32 {
5722            keys.push([7, i, i.wrapping_mul(17), 255 - i]);
5723            keys.push([8, i, 0, 0]);
5724        }
5725        let patch = blake_patch(&keys);
5726        let node = patch.merkle_node(&[7]).expect("prefix seven");
5727
5728        let mut empty = node.items_after(None, 0);
5729        assert_eq!(empty.size_hint(), (0, Some(0)));
5730        assert_eq!(empty.next(), None);
5731        assert_eq!(empty.next(), None);
5732
5733        let first_five = node.items_after(None, 5).collect::<Vec<_>>();
5734        assert_eq!(first_five.len(), 5);
5735        assert!(first_five.windows(2).all(|pair| pair[0] < pair[1]));
5736        assert!(first_five.iter().all(|key| key[0] == 7));
5737
5738        let cursor = [7, 4, 128, 0];
5739        let after = node.items_after(Some(&cursor), 3).collect::<Vec<_>>();
5740        assert_eq!(after.len(), 3);
5741        assert!(after.iter().all(|key| key > &cursor && key[0] == 7));
5742
5743        let exact = keys
5744            .iter()
5745            .copied()
5746            .filter(|key| key[0] == 7)
5747            .nth(12)
5748            .unwrap();
5749        let exclusive = node
5750            .items_after(Some(&exact), usize::MAX)
5751            .collect::<Vec<_>>();
5752        assert!(exclusive.iter().all(|key| key > &exact && key[0] == 7));
5753        assert!(!exclusive.contains(&exact));
5754        assert_eq!(exclusive.len(), 19);
5755
5756        assert_eq!(node.items_after(Some(&[255; 4]), 10).next(), None);
5757        let mut one = node.items_after(None, 1);
5758        assert_eq!(one.size_hint(), (0, Some(1)));
5759        assert!(one.next().is_some());
5760        assert_eq!(one.size_hint(), (0, Some(0)));
5761        assert_eq!(one.next(), None);
5762    }
5763
5764    #[test]
5765    fn merkle_views_do_not_require_or_expose_values() {
5766        struct NotDebug(u8);
5767
5768        let key = [9, 8, 7, 6];
5769        let entry = Entry::<4, NotDebug, Blake3Merkle>::with_value(&key, NotDebug(42));
5770        let mut patch = PATCH::<4, IdentitySchema, NotDebug, Blake3Merkle>::new();
5771        patch.insert(&entry);
5772        let node = patch.merkle_node(&[]).expect("root");
5773        assert_eq!(node.items_after(None, 1).collect::<Vec<_>>(), [key]);
5774        assert!(format!("{node:?}").contains("PATCHMerkleNode"));
5775        assert_eq!(entry.value().0, 42);
5776    }
5777
5778    #[test]
5779    fn blake3_merkle_authenticates_reconciliation_descriptor() {
5780        fn framed(representative: [u8; 16], leaf_count: u64, child_counts: [u64; 2]) -> [u8; 32] {
5781            let mut state = Blake3Merkle::begin_branch(
5782                &representative,
5783                &<IdentitySchema as KeySchema<16>>::TREE_TO_KEY,
5784                4,
5785                2,
5786                leaf_count,
5787            );
5788            Blake3Merkle::push_child(&mut state, 3, child_counts[0], [7; 32]);
5789            Blake3Merkle::push_child(&mut state, 9, child_counts[1], [11; 32]);
5790            Blake3Merkle::finish_branch(state)
5791        }
5792
5793        let representative = [5; 16];
5794        let canonical = framed(representative, 4, [1, 3]);
5795        assert_ne!(canonical, framed(representative, 5, [1, 3]));
5796        assert_ne!(canonical, framed(representative, 4, [2, 2]));
5797
5798        let mut different_prefix = representative;
5799        different_prefix[2] ^= 1;
5800        assert_ne!(canonical, framed(different_prefix, 4, [1, 3]));
5801
5802        let mut different_suffix = representative;
5803        different_suffix[7] ^= 1;
5804        assert_eq!(canonical, framed(different_suffix, 4, [1, 3]));
5805    }
5806
5807    #[test]
5808    fn blake3_merkle_is_history_independent_across_edits_and_set_operations() {
5809        let keys = [
5810            [0, 0, 0, 0],
5811            [0, 0, 1, 0],
5812            [0, 2, 0, 0],
5813            [3, 0, 0, 0],
5814            [3, 0, 0, 9],
5815            [255, 1, 2, 3],
5816        ];
5817
5818        let forward = blake_patch(&keys);
5819        let mut reversed_keys = keys;
5820        reversed_keys.reverse();
5821        let reversed = blake_patch(&reversed_keys);
5822        assert_eq!(forward.merkle_root(), reversed.merkle_root());
5823        assert_eq!(forward, reversed);
5824
5825        let mut edited = forward.clone();
5826        edited.remove(&keys[2]);
5827        edited.insert(&Entry::<4, (), Blake3Merkle>::new(&keys[2]));
5828        assert_eq!(edited.merkle_root(), forward.merkle_root());
5829
5830        let left = blake_patch(&keys[..4]);
5831        let right = blake_patch(&keys[2..]);
5832        let mut union = left.clone();
5833        union.union(right.clone());
5834        assert_eq!(union.merkle_root(), forward.merkle_root());
5835
5836        let expected_intersection = blake_patch(&keys[2..4]);
5837        assert_eq!(
5838            left.intersect(&right).merkle_root(),
5839            expected_intersection.merkle_root()
5840        );
5841
5842        let expected_difference = blake_patch(&keys[..2]);
5843        assert_eq!(
5844            left.difference(&right).merkle_root(),
5845            expected_difference.merkle_root()
5846        );
5847    }
5848
5849    #[test]
5850    fn blake3_merkle_heap_and_archive_construction_have_the_same_root() {
5851        #[repr(C, align(16))]
5852        struct AlignedBlakeArchive([[u8; 16]; 6]);
5853
5854        let storage = Arc::new(AlignedBlakeArchive([
5855            [0; 16], [1; 16], [2; 16], [3; 16], [17; 16], [255; 16],
5856        ]));
5857        let owner: Arc<dyn ArchiveOwner> = storage.clone();
5858        let hashes = storage.0.map(|key| Blake3Merkle::leaf(&key));
5859        let mut rows = [5, 3, 1, 4, 0, 2];
5860
5861        // SAFETY: the aligned wrapper makes every 16-byte row 16-byte
5862        // aligned, the rows are a permutation, the keys are distinct and
5863        // immutable, and `owner` retains the allocation.
5864        let archive = unsafe {
5865            PATCH::<16, IdentitySchema, (), Blake3Merkle>::from_archive_partition(
5866                &storage.0, &hashes, &mut rows, &owner,
5867            )
5868        };
5869        let heap = blake_patch(&storage.0);
5870
5871        assert_eq!(archive.merkle_root(), heap.merkle_root());
5872        assert_eq!(archive, heap);
5873        let archive_root = archive.merkle_node(&[]).expect("archive root");
5874        assert_eq!(archive_root.leaf_count(), 6);
5875        assert_eq!(
5876            archive_root
5877                .items_after(None, usize::MAX)
5878                .collect::<Vec<_>>(),
5879            storage.0
5880        );
5881    }
5882
5883    crate::key_segmentation!(PermutedInfixSegments, 12, [4, 4, 4]);
5884    crate::key_schema!(PermutedInfixSchema, PermutedInfixSegments, 12, [1, 2, 0]);
5885    crate::key_segmentation!(PrefixProjectionSegments, 6, [4, 2]);
5886    crate::key_schema!(PrefixProjectionSchema, PrefixProjectionSegments, 6, [0, 1]);
5887    crate::key_segmentation!(PrefixSharingBlobSegments, 40, [32, 8]);
5888    crate::key_schema!(
5889        PrefixSharingBlobSchema,
5890        PrefixSharingBlobSegments,
5891        40,
5892        [0, 1]
5893    );
5894
5895    #[test]
5896    fn shares_prefix_handles_empty_and_full_prefixes() {
5897        let empty = PATCH::<4, IdentitySchema>::new();
5898        let key = [1, 2, 3, 4];
5899        assert!(empty.shares_prefix(&empty.clone(), &[]));
5900        assert!(empty.shares_prefix(&empty.clone(), &key));
5901
5902        let mut populated = empty.clone();
5903        populated.insert(&Entry::new(&key));
5904        assert!(!empty.shares_prefix(&populated, &[]));
5905        assert!(!empty.shares_prefix(&populated, &key));
5906        assert!(!populated.shares_prefix(&empty, &[1, 2]));
5907        assert!(populated.shares_prefix(&empty, &[1, 9]));
5908        assert!(populated.shares_prefix(&populated.clone(), &[]));
5909        assert!(populated.shares_prefix(&populated.clone(), &key));
5910
5911        let mut rebuilt = PATCH::<4, IdentitySchema>::new();
5912        rebuilt.insert(&Entry::new(&key));
5913        assert_eq!(populated, rebuilt);
5914        assert!(!populated.shares_prefix(&rebuilt, &[]));
5915        assert!(!populated.shares_prefix(&rebuilt, &key));
5916    }
5917
5918    #[test]
5919    fn shares_prefix_retains_compressed_subtrees_after_unrelated_insertions() {
5920        let mut original = PATCH::<4, IdentitySchema>::new();
5921        original.insert(&Entry::new(&[1, 2, 3, 0]));
5922        original.insert(&Entry::new(&[1, 2, 3, 255]));
5923        assert_eq!(original.root.as_ref().unwrap().end_depth(), 3);
5924
5925        let mut outside = original.clone();
5926        outside.insert(&Entry::new(&[9, 8, 7, 6]));
5927        // The old compressed root becomes a child with a different edge byte.
5928        assert!(!original.shares_prefix(&outside, &[]));
5929        assert!(original.shares_prefix(&outside, &[1]));
5930        assert!(original.shares_prefix(&outside, &[1, 2]));
5931        assert!(original.shares_prefix(&outside, &[1, 2, 3]));
5932        assert!(original.shares_prefix(&outside, &[1, 2, 3, 0]));
5933        assert!(original.shares_prefix(&outside, &[1, 2, 4]));
5934
5935        let mut split = outside.clone();
5936        split.insert(&Entry::new(&[1, 2, 4, 0]));
5937        assert!(!outside.shares_prefix(&split, &[1]));
5938        assert!(!outside.shares_prefix(&split, &[1, 2]));
5939        assert!(!outside.shares_prefix(&split, &[1, 2, 4]));
5940        assert!(outside.shares_prefix(&split, &[1, 2, 3]));
5941        assert!(outside.shares_prefix(&split, &[9]));
5942
5943        let mut inside = split.clone();
5944        inside.insert(&Entry::new(&[1, 2, 3, 127]));
5945        assert!(!split.shares_prefix(&inside, &[1, 2, 3]));
5946        assert!(split.shares_prefix(&inside, &[1, 2, 3, 0]));
5947        assert!(split.shares_prefix(&inside, &[1, 2, 4]));
5948    }
5949
5950    #[test]
5951    fn shares_prefix_detects_an_additional_physical_blob_occurrence() {
5952        let physical_key = |hash: [u8; 32], offset: u64| {
5953            let mut key = [0; 40];
5954            key[..32].copy_from_slice(&hash);
5955            key[32..].copy_from_slice(&offset.to_be_bytes());
5956            key
5957        };
5958        let hash = [7; 32];
5959        let other_hash = [9; 32];
5960        let first = physical_key(hash, 512);
5961        let mut before = PATCH::<40, PrefixSharingBlobSchema>::new();
5962        before.insert(&Entry::new(&first));
5963        before.insert(&Entry::new(&physical_key(other_hash, 1024)));
5964        let mut after = before.clone();
5965        after.insert(&Entry::new(&physical_key(hash, 2048)));
5966
5967        assert_eq!(
5968            before.prefix_set::<32>().iter().collect::<Vec<_>>(),
5969            after.prefix_set::<32>().iter().collect::<Vec<_>>()
5970        );
5971        assert!(!before.shares_prefix(&after, &hash));
5972        assert!(before.shares_prefix(&after, &first));
5973        assert!(before.shares_prefix(&after, &other_hash));
5974    }
5975
5976    #[test]
5977    fn shares_prefix_observes_replaced_values_with_unchanged_keys() {
5978        let key = [1, 2, 3, 4];
5979        let sibling = [1, 2, 3, 9];
5980        let unrelated = [9, 8, 7, 6];
5981        let mut before = PATCH::<4, IdentitySchema, u64>::new();
5982        for key in [key, sibling, unrelated] {
5983            before.insert(&Entry::with_value(&key, 10));
5984        }
5985        let mut after = before.clone();
5986        after.replace(&Entry::with_value(&key, 11));
5987
5988        assert_eq!(before, after);
5989        assert_eq!(before.get(&key), Some(&10));
5990        assert_eq!(after.get(&key), Some(&11));
5991        assert!(!before.shares_prefix(&after, &key));
5992        assert!(!before.shares_prefix(&after, &[1, 2, 3]));
5993        assert!(before.shares_prefix(&after, &sibling));
5994        assert!(before.shares_prefix(&after, &[9]));
5995    }
5996
5997    #[test]
5998    fn shares_prefix_uses_tree_order_inside_permuted_segments() {
5999        let first = [30, 31, 32, 33, 1, 2, 3, 4, 5, 6, 7, 8];
6000        let mut sibling = first;
6001        sibling[0] = 40;
6002        let mut before = PATCH::<12, PermutedInfixSchema>::new();
6003        before.insert(&Entry::new(&first));
6004        before.insert(&Entry::new(&sibling));
6005
6006        let mut unrelated = first;
6007        unrelated[4..8].copy_from_slice(&[9, 8, 7, 6]);
6008        let mut after = before.clone();
6009        after.insert(&Entry::new(&unrelated));
6010        assert!(before.shares_prefix(&after, &[1, 2]));
6011        assert!(before.shares_prefix(&after, &[1, 2, 3, 4]));
6012        assert!(before.shares_prefix(
6013            &after,
6014            &<PermutedInfixSchema as KeySchema<12>>::tree_ordered(&first)
6015        ));
6016        assert!(!before.shares_prefix(&after, &[9, 8]));
6017
6018        let mut added = first;
6019        added[6] = 8;
6020        let mut split = after.clone();
6021        split.insert(&Entry::new(&added));
6022        assert!(!after.shares_prefix(&split, &[1, 2]));
6023        assert!(after.shares_prefix(&split, &[1, 2, 3, 4]));
6024    }
6025
6026    #[test]
6027    fn prefix_set_projects_away_suffix_multiplicity_and_order() {
6028        let first = [1, 2, 3, 4];
6029        let second = [5, 6, 7, 8];
6030        let physical_key = |prefix: [u8; 4], suffix: [u8; 2]| {
6031            let mut key = [0; 6];
6032            key[..4].copy_from_slice(&prefix);
6033            key[4..].copy_from_slice(&suffix);
6034            key
6035        };
6036
6037        let mut left = PATCH::<6, PrefixProjectionSchema>::new();
6038        for key in [
6039            physical_key(first, [0, 2]),
6040            physical_key(second, [0, 9]),
6041            physical_key(first, [0, 1]),
6042        ] {
6043            left.insert(&Entry::new(&key));
6044        }
6045        let mut right = PATCH::<6, PrefixProjectionSchema>::new();
6046        for key in [physical_key(second, [7, 7]), physical_key(first, [8, 8])] {
6047            right.insert(&Entry::new(&key));
6048        }
6049
6050        assert_eq!(
6051            left.clone().into_prefixes::<4>().collect::<Vec<_>>(),
6052            vec![first, second]
6053        );
6054        let left = left.prefix_set::<4>();
6055        let right = right.prefix_set::<4>();
6056        assert_eq!(left.iter().collect::<Vec<_>>(), vec![first, second]);
6057        assert_eq!(right.iter().collect::<Vec<_>>(), vec![first, second]);
6058        assert!(left.contains(&first));
6059        assert!(left.contains(&second));
6060        assert!(!left.contains(&[9; 4]));
6061        assert_eq!(
6062            left.iter().collect::<Vec<_>>(),
6063            right.iter().collect::<Vec<_>>()
6064        );
6065    }
6066
6067    #[test]
6068    fn prefix_set_intersection_retains_the_other_patch_policy() {
6069        let physical_key = |prefix: [u8; 4], suffix: [u8; 2]| {
6070            let mut key = [0; 6];
6071            key[..4].copy_from_slice(&prefix);
6072            key[4..].copy_from_slice(&suffix);
6073            key
6074        };
6075        let resident = [[1; 4], [3; 4], [5; 4]];
6076        let mut physical = PATCH::<6, PrefixProjectionSchema>::new();
6077        for (prefix, suffix) in [
6078            (resident[0], [0, 1]),
6079            (resident[0], [0, 2]),
6080            (resident[1], [0, 3]),
6081            (resident[2], [0, 4]),
6082        ] {
6083            physical.insert(&Entry::new(&physical_key(prefix, suffix)));
6084        }
6085
6086        let requested = PATCH::<4, IdentitySchema, (), Blake3Merkle>::from_keys([
6087            [0; 4],
6088            resident[0],
6089            [2; 4],
6090            resident[1],
6091            [4; 4],
6092            resident[2],
6093            [6; 4],
6094        ]);
6095        let actual = physical.prefix_set::<4>().intersection(&requested);
6096        let expected = PATCH::<4, IdentitySchema, (), Blake3Merkle>::from_keys(resident);
6097        assert_eq!(actual, expected);
6098        assert_eq!(actual.merkle_root(), expected.merkle_root());
6099    }
6100
6101    struct PanicOnDrop(bool);
6102
6103    impl Drop for PanicOnDrop {
6104        fn drop(&mut self) {
6105            if self.0 {
6106                panic!("intentional value drop panic");
6107            }
6108        }
6109    }
6110
6111    /// Build the smallest all-LocalLeaf PATCH and return a weak witness for
6112    /// its backing allocation. The returned PATCH is the allocation's only
6113    /// strong owner, so liveness assertions fail before a dangling pointer is
6114    /// ever dereferenced.
6115    fn owned_archive_pair(
6116        keys: [[u8; 16]; 2],
6117    ) -> (
6118        PATCH<16, IdentitySchema>,
6119        std::sync::Weak<AlignedArchivePair>,
6120    ) {
6121        let storage = std::sync::Arc::new(AlignedArchivePair(keys));
6122        let weak = std::sync::Arc::downgrade(&storage);
6123        let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6124        let hashes = [hash_key(&storage.0[0]), hash_key(&storage.0[1])];
6125        let mut rows = [0, 1];
6126        // SAFETY: AlignedArchivePair is 16-byte aligned, each 16-byte row has
6127        // the same alignment, the two keys are distinct in every fixture, and
6128        // `owner` retains the immutable storage throughout construction.
6129        let patch =
6130            unsafe { PATCH::from_archive_partition(&storage.0, &hashes, &mut rows, &owner) };
6131        assert_eq!(patch.node_stats(), (1, 2, 0, 2));
6132        drop(owner);
6133        drop(storage);
6134        (patch, weak)
6135    }
6136
6137    /// The out-of-place pass exists only to do what the in-place one does,
6138    /// on more than one worker. Pin that: same split depth, same occupied
6139    /// bytes, same interval per byte, same rows inside each interval.
6140    ///
6141    /// Order *within* an interval is deliberately unspecified — keys are
6142    /// distinct, so a bucket's subtrie is a function of its key set — and the
6143    /// assertion is written to say so rather than to accidentally depend on
6144    /// it.
6145    #[cfg(feature = "parallel")]
6146    #[test]
6147    fn parallel_partition_pass_agrees_with_the_in_place_pass() {
6148        type Subject = PATCH<16, IdentitySchema>;
6149        let len = 4 * Subject::PARTITION_ROWS_PER_WORKER;
6150        let mut keys: Vec<[u8; 16]> = Vec::with_capacity(len);
6151        let mut state = 0x243f_6a88_85a3_08d3u64;
6152        for index in 0..len {
6153            state = state.wrapping_add(0x9e37_79b9_7f4a_7c15);
6154            let mut mixed = state;
6155            mixed = (mixed ^ (mixed >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
6156            mixed = (mixed ^ (mixed >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
6157            mixed ^= mixed >> 31;
6158            let mut key = [0u8; 16];
6159            // Nine rows in ten share a first byte, and every row shares the
6160            // seven bytes after it, so the representative's prefix has to be
6161            // walked rather than rejected on the second row.
6162            key[0] = if index % 10 == 0 {
6163                (mixed & 0xff) as u8
6164            } else {
6165                0x5a
6166            };
6167            key[1..8].copy_from_slice(&[0x5a; 7]);
6168            key[8..16].copy_from_slice(&(index as u64).to_be_bytes());
6169            keys.push(key);
6170        }
6171        keys.sort_unstable();
6172        keys.dedup();
6173        assert!(
6174            keys.len() > 2 * Subject::PARTITION_ROWS_PER_WORKER,
6175            "the fixture must be wide enough for the out-of-place pass",
6176        );
6177        assert!(Subject::partition_workers(keys.len()) > 1);
6178
6179        let rows: Vec<u32> = (0..keys.len() as u32).collect();
6180        let mut in_place = rows.clone();
6181        let ordered = Subject::partition_archive_rows(&keys, &mut in_place, 0);
6182        let (concurrent, permuted) = Subject::partition_archive_rows_parallel(&keys, &rows, 0);
6183
6184        assert_eq!(ordered.end_depth, concurrent.end_depth);
6185        assert_eq!(ordered.fanout, concurrent.fanout);
6186        assert_eq!(ordered.initial_slots, concurrent.initial_slots);
6187        assert_eq!(
6188            ordered.buckets[..ordered.fanout],
6189            concurrent.buckets[..concurrent.fanout],
6190        );
6191        assert_eq!(ordered.ends, concurrent.ends);
6192
6193        let mut start = 0usize;
6194        for &byte in &ordered.buckets[..ordered.fanout] {
6195            let end = ordered.ends[byte as usize] as usize;
6196            let mut ordered_rows: Vec<u32> = in_place[start..end].to_vec();
6197            let mut concurrent_rows: Vec<u32> = permuted[start..end].to_vec();
6198            ordered_rows.sort_unstable();
6199            concurrent_rows.sort_unstable();
6200            assert_eq!(ordered_rows, concurrent_rows, "bucket {byte:#04x}");
6201            start = end;
6202        }
6203        assert_eq!(start, keys.len());
6204    }
6205
6206    fn key(byte: u8) -> [u8; 16] {
6207        [byte; 16]
6208    }
6209
6210    fn singleton_patch(key: [u8; 16]) -> PATCH<16, IdentitySchema> {
6211        let mut patch = PATCH::new();
6212        let entry = Entry::new(&key);
6213        patch.insert(&entry);
6214        patch
6215    }
6216
6217    #[test]
6218    fn exported_fingerprint_blinding_is_not_xor_homomorphic() {
6219        let key = [0x5au8; 16];
6220        let left = 0x0123_4567_89ab_cdef_fedc_ba98_7654_3210u128;
6221        let right = 0xfedc_ba98_7654_3210_0123_4567_89ab_cdefu128;
6222        let blind_left = blind_root_hash_with_key(left, &key);
6223        let blind_right = blind_root_hash_with_key(right, &key);
6224
6225        assert_ne!(blind_left, left);
6226        assert_ne!(
6227            blind_root_hash_with_key(left ^ right, &key),
6228            blind_left ^ blind_right
6229        );
6230    }
6231
6232    #[test]
6233    fn owner_cover_shape_is_canonical_and_membership_is_exact() {
6234        let owners: Vec<Arc<dyn ArchiveOwner>> = (0u8..8)
6235            .map(|byte| Arc::new([byte]) as Arc<dyn ArchiveOwner>)
6236            .collect();
6237        let build = |order: &[usize]| {
6238            let mut cover = None;
6239            for &index in order {
6240                OwnerCover::retain(&mut cover, &owners[index]);
6241            }
6242            cover.unwrap()
6243        };
6244
6245        let forward = build(&[0, 1, 2, 3, 4, 5, 6, 7]);
6246        let shuffled = build(&[6, 2, 7, 0, 5, 1, 4, 3]);
6247        assert_eq!(forward.len, owners.len());
6248        assert_eq!(shuffled.len, owners.len());
6249        assert!(forward.root.same_shape(&shuffled.root));
6250        for owner in &owners {
6251            assert!(forward.root.contains(OwnerCover::address(owner)));
6252        }
6253        let unrelated: Arc<dyn ArchiveOwner> = Arc::new([0xff]);
6254        assert!(!forward.root.contains(OwnerCover::address(&unrelated)));
6255    }
6256
6257    #[test]
6258    fn owner_cover_overlapping_diamond_does_not_accumulate_duplicates() {
6259        let first_backing = Arc::new([0x11]);
6260        let second_backing = Arc::new([0x22]);
6261        let first_weak = Arc::downgrade(&first_backing);
6262        let second_weak = Arc::downgrade(&second_backing);
6263        let first: Arc<dyn ArchiveOwner> = first_backing.clone();
6264        let second: Arc<dyn ArchiveOwner> = second_backing.clone();
6265
6266        let mut left = Some(OwnerCover::singleton(&first));
6267        OwnerCover::retain(&mut left, &second);
6268        let mut right = Some(OwnerCover::singleton(&second));
6269        OwnerCover::retain(&mut right, &first);
6270        let left_root = match &left.as_ref().unwrap().root {
6271            OwnerNode::Branch(branch) => Arc::downgrade(branch),
6272            OwnerNode::Owner(_) => panic!("two owners require one Patricia branch"),
6273        };
6274        let right_root = match &right.as_ref().unwrap().root {
6275            OwnerNode::Branch(branch) => Arc::downgrade(branch),
6276            OwnerNode::Owner(_) => panic!("two owners require one Patricia branch"),
6277        };
6278
6279        for _ in 0..4_096 {
6280            let next_left = OwnerCover::union(left.clone(), &right);
6281            let next_right = OwnerCover::union(right.clone(), &left);
6282            left = next_left;
6283            right = next_right;
6284            assert_eq!(left.as_ref().unwrap().len, 2);
6285            assert_eq!(right.as_ref().unwrap().len, 2);
6286            assert!(matches!(
6287                &left.as_ref().unwrap().root,
6288                OwnerNode::Branch(branch) if Arc::as_ptr(branch) == left_root.as_ptr()
6289            ));
6290            assert!(matches!(
6291                &right.as_ref().unwrap().root,
6292                OwnerNode::Branch(branch) if Arc::as_ptr(branch) == right_root.as_ptr()
6293            ));
6294        }
6295
6296        drop(first);
6297        drop(second);
6298        drop(first_backing);
6299        drop(second_backing);
6300        assert!(first_weak.upgrade().is_some());
6301        assert!(second_weak.upgrade().is_some());
6302        drop(left);
6303        drop(right);
6304        assert!(first_weak.upgrade().is_none());
6305        assert!(second_weak.upgrade().is_none());
6306    }
6307
6308    #[test]
6309    fn repeated_latest_owner_retention_reuses_the_cover() {
6310        let owner: Arc<dyn ArchiveOwner> = Arc::new([0x55]);
6311        let mut cover = None;
6312        OwnerCover::retain(&mut cover, &owner);
6313        let original = cover.as_ref().unwrap().clone();
6314
6315        for _ in 0..4_096 {
6316            OwnerCover::retain(&mut cover, &owner);
6317        }
6318
6319        let cover = cover.unwrap();
6320        assert!(Arc::ptr_eq(&cover, &original));
6321        assert_eq!(cover.len, 1);
6322        assert!(matches!(&cover.root, OwnerNode::Owner(_)));
6323    }
6324
6325    proptest! {
6326        #[test]
6327        fn owner_cover_union_matches_address_set(
6328            left in prop::collection::btree_set(0usize..24, 0..24),
6329            right in prop::collection::btree_set(0usize..24, 0..24),
6330        ) {
6331            let owners: Vec<Arc<dyn ArchiveOwner>> = (0u8..24)
6332                .map(|byte| Arc::new([byte]) as Arc<dyn ArchiveOwner>)
6333                .collect();
6334            let build = |indices: Vec<usize>| {
6335                let mut cover = None;
6336                for index in indices {
6337                    OwnerCover::retain(&mut cover, &owners[index]);
6338                }
6339                cover
6340            };
6341            let left_cover = build(left.iter().copied().collect());
6342            let right_cover = build(right.iter().rev().copied().collect());
6343            let joined = OwnerCover::union(left_cover, &right_cover);
6344            let expected: std::collections::BTreeSet<_> =
6345                left.union(&right).copied().collect();
6346
6347            if expected.is_empty() {
6348                prop_assert!(joined.is_none());
6349            } else {
6350                let joined = joined.unwrap();
6351                let mut actual = HashSet::new();
6352                joined.root.for_each_owner(&mut |owner| {
6353                    assert!(actual.insert(OwnerCover::address(owner)));
6354                });
6355                let expected_addresses: HashSet<_> = expected
6356                    .iter()
6357                    .map(|&index| OwnerCover::address(&owners[index]))
6358                    .collect();
6359                prop_assert_eq!(actual, expected_addresses);
6360                prop_assert_eq!(joined.len, expected.len());
6361
6362                let canonical = build(expected.iter().copied().collect()).unwrap();
6363                prop_assert!(joined.root.same_shape(&canonical.root));
6364            }
6365        }
6366    }
6367
6368    #[test]
6369    fn disjoint_cross_owner_union_retains_both_archives() {
6370        let (mut left, left_owner) = owned_archive_pair([key(0x10), key(0x20)]);
6371        let (right, right_owner) = owned_archive_pair([key(0x30), key(0x40)]);
6372
6373        left.union(right);
6374
6375        assert!(
6376            left_owner.upgrade().is_some(),
6377            "union dropped its left archive"
6378        );
6379        assert!(
6380            right_owner.upgrade().is_some(),
6381            "union dropped its consumed right archive"
6382        );
6383        assert_eq!(
6384            left.iter().copied().collect::<HashSet<_>>(),
6385            HashSet::from([key(0x10), key(0x20), key(0x30), key(0x40)])
6386        );
6387        drop(left);
6388        assert!(left_owner.upgrade().is_none());
6389        assert!(right_owner.upgrade().is_none());
6390    }
6391
6392    #[test]
6393    fn one_key_intersection_retains_both_source_archives() {
6394        let (left, left_owner) = owned_archive_pair([key(0x10), key(0x20)]);
6395        let (right, right_owner) = owned_archive_pair([key(0x10), key(0x30)]);
6396
6397        let intersection = left.intersect(&right);
6398        drop(left);
6399        drop(right);
6400
6401        assert!(
6402            left_owner.upgrade().is_some(),
6403            "intersection dropped the archive backing its surviving LocalLeaf"
6404        );
6405        assert!(
6406            right_owner.upgrade().is_some(),
6407            "intersection must conservatively retain both source covers"
6408        );
6409        assert_eq!(intersection.iter().copied().collect_vec(), vec![key(0x10)]);
6410        drop(intersection);
6411        assert!(left_owner.upgrade().is_none());
6412        assert!(right_owner.upgrade().is_none());
6413    }
6414
6415    #[test]
6416    fn one_key_difference_retains_its_left_archive() {
6417        let (left, left_owner) = owned_archive_pair([key(0x10), key(0x20)]);
6418        let (right, right_owner) = owned_archive_pair([key(0x10), key(0x30)]);
6419
6420        let difference = left.difference(&right);
6421        drop(left);
6422        drop(right);
6423
6424        assert!(
6425            left_owner.upgrade().is_some(),
6426            "difference dropped the archive backing its surviving LocalLeaf"
6427        );
6428        assert!(
6429            right_owner.upgrade().is_none(),
6430            "difference should not retain an archive used only for subtraction"
6431        );
6432        assert_eq!(difference.iter().copied().collect_vec(), vec![key(0x20)]);
6433        drop(difference);
6434        assert!(left_owner.upgrade().is_none());
6435        assert!(right_owner.upgrade().is_none());
6436    }
6437
6438    #[test]
6439    fn asymmetric_difference_collapses_its_surviving_child() {
6440        let (left, owner) = owned_archive_pair([key(0x10), key(0x20)]);
6441        assert_eq!(left.root.as_ref().map(Head::tag), Some(HeadTag::Branch2));
6442        let removed = singleton_patch(key(0x10));
6443
6444        let survivor = left.difference(&removed);
6445        drop(left);
6446        drop(removed);
6447
6448        assert_eq!(survivor.len(), 1);
6449        assert_eq!(survivor.node_stats(), (0, 0, 0, 1));
6450        assert_eq!(
6451            survivor.root.as_ref().map(Head::tag),
6452            Some(HeadTag::LocalLeaf),
6453            "Branch-minus-Leaf left a unary Branch instead of its child",
6454        );
6455        assert_eq!(survivor.iter().copied().collect_vec(), vec![key(0x20)]);
6456        assert!(owner.upgrade().is_some());
6457
6458        let final_key = singleton_patch(key(0x20));
6459        let empty = survivor.difference(&final_key);
6460        drop(survivor);
6461        drop(final_key);
6462
6463        assert!(empty.root.is_none());
6464        assert!(empty.owners.is_none());
6465        assert!(owner.upgrade().is_none());
6466    }
6467
6468    #[test]
6469    fn clone_and_consuming_iterator_retain_the_archive() {
6470        let (patch, owner) = owned_archive_pair([key(0x10), key(0x20)]);
6471        let clone = patch.clone();
6472        drop(patch);
6473        assert!(owner.upgrade().is_some(), "clone lost the archive owner");
6474
6475        let mut iter = clone.into_iter();
6476        assert!(
6477            owner.upgrade().is_some(),
6478            "consuming iterator lost the archive owner"
6479        );
6480        assert!(matches!(iter.next(), Some(value) if value == key(0x10) || value == key(0x20)));
6481        drop(iter);
6482        assert!(owner.upgrade().is_none());
6483    }
6484
6485    #[test]
6486    fn ordered_consuming_iterator_retains_the_archive() {
6487        let (patch, owner) = owned_archive_pair([key(0x10), key(0x20)]);
6488
6489        let mut iter = patch.into_iter_ordered();
6490        assert!(
6491            owner.upgrade().is_some(),
6492            "ordered consuming iterator lost the archive owner"
6493        );
6494        assert_eq!(iter.next(), Some(key(0x10)));
6495        drop(iter);
6496        assert!(owner.upgrade().is_none());
6497    }
6498
6499    #[test]
6500    fn removal_retains_collapsed_local_root_and_releases_empty_cover() {
6501        let (mut patch, owner) = owned_archive_pair([key(0x10), key(0x20)]);
6502
6503        patch.remove(&key(0x10));
6504        assert!(
6505            owner.upgrade().is_some(),
6506            "removal lost the owner of the surviving LocalLeaf"
6507        );
6508        assert_eq!(patch.iter().copied().collect_vec(), vec![key(0x20)]);
6509
6510        patch.remove(&key(0x20));
6511        assert!(patch.is_empty());
6512        assert!(owner.upgrade().is_none(), "empty PATCH retained its cover");
6513    }
6514
6515    #[test]
6516    fn head_tag() {
6517        let head = Head::<64, IdentitySchema, ()>::new::<Leaf<64, ()>>(0, NonNull::dangling());
6518        assert_eq!(head.tag(), HeadTag::Leaf);
6519        mem::forget(head);
6520    }
6521
6522    #[test]
6523    fn head_key() {
6524        for k in 0..=255 {
6525            let head = Head::<64, IdentitySchema, ()>::new::<Leaf<64, ()>>(k, NonNull::dangling());
6526            assert_eq!(head.key(), k);
6527            mem::forget(head);
6528        }
6529    }
6530
6531    #[test]
6532    fn head_size() {
6533        assert_eq!(mem::size_of::<Head<64, IdentitySchema, ()>>(), 8);
6534    }
6535
6536    #[test]
6537    fn option_head_size() {
6538        assert_eq!(mem::size_of::<Option<Head<64, IdentitySchema, ()>>>(), 8);
6539    }
6540
6541    #[test]
6542    fn empty_tree() {
6543        let _tree = PATCH::<64, IdentitySchema, ()>::new();
6544    }
6545
6546    #[test]
6547    fn tree_put_one() {
6548        const KEY_SIZE: usize = 64;
6549        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6550        let entry = Entry::new(&[0; KEY_SIZE]);
6551        tree.insert(&entry);
6552    }
6553
6554    #[test]
6555    fn tree_clone_one() {
6556        const KEY_SIZE: usize = 64;
6557        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6558        let entry = Entry::new(&[0; KEY_SIZE]);
6559        tree.insert(&entry);
6560        let _clone = tree.clone();
6561    }
6562
6563    #[test]
6564    fn consuming_shared_leaf_does_not_mutably_alias_value() {
6565        const KEY_SIZE: usize = 4;
6566        let key = [1u8; KEY_SIZE];
6567        let mut retained = PATCH::<KEY_SIZE, IdentitySchema, String>::new();
6568        let entry = Entry::with_value(&key, String::from("still borrowed"));
6569        retained.insert(&entry);
6570        drop(entry);
6571
6572        let unordered = retained.clone();
6573        let value = retained.get(&key).expect("inserted value");
6574        assert_eq!(unordered.into_iter().collect::<Vec<_>>(), vec![key]);
6575        assert_eq!(value, "still borrowed");
6576
6577        let ordered = retained.clone();
6578        let value = retained.get(&key).expect("inserted value");
6579        assert_eq!(ordered.into_iter_ordered().collect::<Vec<_>>(), vec![key]);
6580        assert_eq!(value, "still borrowed");
6581    }
6582
6583    #[test]
6584    fn tree_put_same() {
6585        const KEY_SIZE: usize = 64;
6586        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6587        let entry = Entry::new(&[0; KEY_SIZE]);
6588        tree.insert(&entry);
6589        tree.insert(&entry);
6590    }
6591
6592    #[test]
6593    fn ordered_infix_bounds_include_all_zero_and_all_ff() {
6594        let mut tree = PATCH::<4, IdentitySchema, ()>::new();
6595        tree.insert(&Entry::new(&[0x00; 4]));
6596        tree.insert(&Entry::new(&[0x80, 0x00, 0x00, 0x00]));
6597        tree.insert(&Entry::new(&[0xff; 4]));
6598
6599        assert_eq!(
6600            tree.first_infix_range(&[], &[0x00; 4], &[0xff; 4]),
6601            Some([0x00; 4]),
6602        );
6603        assert_eq!(
6604            tree.next_infix_after(&[], &[0x00; 4], &[0xff; 4]),
6605            Some([0x80, 0x00, 0x00, 0x00]),
6606        );
6607        assert_eq!(
6608            tree.first_infix_range(&[], &[0xff; 4], &[0xff; 4]),
6609            Some([0xff; 4]),
6610        );
6611        assert_eq!(tree.next_infix_after(&[], &[0xff; 4], &[0xff; 4]), None,);
6612        assert_eq!(tree.first_infix_range(&[], &[0xff; 4], &[0x00; 4]), None,);
6613    }
6614
6615    #[test]
6616    fn ordered_infix_descent_reads_local_leaves() {
6617        #[repr(C, align(16))]
6618        struct AlignedKey([u8; 16]);
6619
6620        let storage = std::sync::Arc::new([
6621            AlignedKey([0x10; 16]),
6622            AlignedKey([0x20; 16]),
6623            AlignedKey([0xf0; 16]),
6624        ]);
6625        let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6626        let mut tree = PATCH::<16, IdentitySchema, ()>::new();
6627        for key in storage.iter() {
6628            let entry = unsafe { ArchiveEntry::new(NonNull::from(&key.0), &owner) };
6629            tree.insert_archive(&entry);
6630        }
6631
6632        assert!(tree.node_stats().3 > 0, "fixture must contain a LocalLeaf");
6633        assert_eq!(
6634            tree.first_infix_range(&[], &[0x11; 16], &[0xff; 16]),
6635            Some([0x20; 16]),
6636        );
6637        assert_eq!(
6638            tree.next_infix_after(&[], &[0x20; 16], &[0xff; 16]),
6639            Some([0xf0; 16]),
6640        );
6641    }
6642
6643    #[test]
6644    fn ordered_infix_descent_honors_permuted_segments_in_local_leaves() {
6645        fn physical_key(prefix: [u8; 4], infix: [u8; 4], suffix: [u8; 4]) -> [u8; 12] {
6646            let mut key = [0; 12];
6647            key[..4].copy_from_slice(&suffix);
6648            key[4..8].copy_from_slice(&prefix);
6649            key[8..].copy_from_slice(&infix);
6650            key
6651        }
6652
6653        let selected = [0x10; 4];
6654        let other = [0x20; 4];
6655        let first = [0x11; 4];
6656        let second = [0x22; 4];
6657        let storage = std::sync::Arc::new([
6658            AlignedArchiveKey(physical_key(other, [0x33; 4], [0x44; 4])),
6659            AlignedArchiveKey(physical_key(selected, second, [0x44; 4])),
6660            AlignedArchiveKey(physical_key(selected, first, [0x55; 4])),
6661            AlignedArchiveKey(physical_key(selected, first, [0x44; 4])),
6662        ]);
6663        let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6664        let mut tree = PATCH::<12, PermutedInfixSchema, ()>::new();
6665        for key in storage.iter() {
6666            // SAFETY: every key is aligned and remains immutable and alive
6667            // through `owner` for the lifetime of the archive-backed PATCH.
6668            let entry = unsafe { ArchiveEntry::new(NonNull::from(&key.0), &owner) };
6669            tree.insert_archive(&entry);
6670        }
6671
6672        assert!(tree.node_stats().3 > 0, "fixture must contain a LocalLeaf");
6673        assert_eq!(
6674            tree.first_infix_range(&selected, &[u8::MIN; 4], &[u8::MAX; 4]),
6675            Some(first),
6676        );
6677        assert_eq!(
6678            tree.next_infix_after(&selected, &first, &[u8::MAX; 4]),
6679            Some(second),
6680        );
6681        assert_eq!(
6682            tree.next_infix_after(&selected, &second, &[u8::MAX; 4]),
6683            None,
6684        );
6685    }
6686
6687    #[test]
6688    fn bounded_infixes_are_atomic_over_archive_local_leaves() {
6689        #[repr(C, align(16))]
6690        struct AlignedKey([u8; 16]);
6691
6692        let storage = std::sync::Arc::new([
6693            AlignedKey([0x10; 16]),
6694            AlignedKey([0x20; 16]),
6695            AlignedKey([0xf0; 16]),
6696        ]);
6697        let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6698        let mut tree = PATCH::<16, IdentitySchema, ()>::new();
6699        for key in storage.iter() {
6700            let entry = unsafe { ArchiveEntry::new(NonNull::from(&key.0), &owner) };
6701            tree.insert_archive(&entry);
6702        }
6703        assert!(tree.node_stats().3 > 0, "fixture must contain a LocalLeaf");
6704
6705        assert!(tree.bounded_infixes::<0, 16>(&[], 2).is_none());
6706
6707        let mut expected = Vec::new();
6708        tree.infixes(&[], |value: &[u8; 16]| expected.push(*value));
6709        let mut accepted = Vec::new();
6710        let bounded = tree
6711            .bounded_infixes::<0, 16>(&[], 3)
6712            .expect("the exact count fits");
6713        assert_eq!(bounded.len(), 3);
6714        bounded.for_each(|value: &[u8; 16]| accepted.push(*value));
6715        assert_eq!(accepted, expected);
6716    }
6717
6718    #[test]
6719    fn archive_singleton_pairs_follow_exact_key_identity() {
6720        const KEY_SIZE: usize = 64;
6721        #[repr(C, align(16))]
6722        struct AlignedKey([u8; KEY_SIZE]);
6723
6724        let key_a = [0x44; KEY_SIZE];
6725        let mut key_b = key_a;
6726        key_b[KEY_SIZE - 1] = 0x55;
6727        let storage = std::sync::Arc::new([AlignedKey(key_a), AlignedKey(key_b)]);
6728        let _owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6729
6730        let local_a = unsafe { Head::new_local_leaf(0, NonNull::from(&storage[0].0)) };
6731        let local_b = unsafe { Head::new_local_leaf(0, NonNull::from(&storage[1].0)) };
6732        let heap_a_entry = Entry::new(&key_a);
6733        let heap_b_entry = Entry::new(&key_b);
6734        let heap_a = heap_a_entry.leaf::<IdentitySchema>();
6735        let heap_b = heap_b_entry.leaf::<IdentitySchema>();
6736
6737        fn assert_pair(
6738            left: &Head<64, IdentitySchema, ()>,
6739            right: &Head<64, IdentitySchema, ()>,
6740            equal: bool,
6741        ) {
6742            let union = Head::union(left.clone(), right.clone(), 0);
6743            assert_eq!(union.count(), if equal { 1 } else { 2 });
6744            assert_eq!(
6745                left.intersect(right, 0).as_ref().map(Head::count),
6746                equal.then_some(1)
6747            );
6748            assert_eq!(
6749                left.difference(right, 0).as_ref().map(Head::count),
6750                (!equal).then_some(1)
6751            );
6752        }
6753
6754        assert_pair(&local_a, &local_a, true);
6755        assert_pair(&local_a, &local_b, false);
6756        assert_pair(&heap_a, &local_a, true);
6757        assert_pair(&local_a, &heap_a, true);
6758        assert_pair(&heap_a, &local_b, false);
6759        assert_pair(&local_a, &heap_b, false);
6760        assert_pair(&heap_a, &heap_a, true);
6761        assert_pair(&heap_a, &heap_b, false);
6762    }
6763
6764    #[test]
6765    fn local_leaf_and_unary_branch_keep_equal_fingerprint_path() {
6766        const KEY_SIZE: usize = 16;
6767        #[repr(C, align(16))]
6768        struct AlignedKey([u8; KEY_SIZE]);
6769
6770        let storage =
6771            std::sync::Arc::new([AlignedKey([0x10; KEY_SIZE]), AlignedKey([0x20; KEY_SIZE])]);
6772        let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6773        let mut pair = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6774        for key in storage.iter() {
6775            let entry = unsafe { ArchiveEntry::new(NonNull::from(&key.0), &owner) };
6776            pair.insert_archive(&entry);
6777        }
6778
6779        // Deliberately retain a unary Branch representation. Cardinality one
6780        // is not enough to infer its tag or reject equality with a LocalLeaf.
6781        let mut unary = pair.root.as_ref().expect("pair has a root").clone();
6782        let removed_slot = match unary.body_ref() {
6783            BodyRef::Branch(branch) => branch
6784                .child_table
6785                .iter()
6786                .flatten()
6787                .find(|child| child.childleaf_key() == &storage[0].0)
6788                .expect("first archive key is present")
6789                .key(),
6790            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => panic!("pair root must be a Branch"),
6791        };
6792        {
6793            let mut editor = crate::patch::branch::BranchMut::from_head(&mut unary);
6794            editor.modify_child(removed_slot, |_| None);
6795        }
6796        assert!(matches!(unary.body_ref(), BodyRef::Branch(_)));
6797        assert_eq!(unary.count(), 1);
6798
6799        let local = match unary.body_ref() {
6800            BodyRef::Branch(branch) => branch
6801                .child_table
6802                .iter()
6803                .flatten()
6804                .next()
6805                .expect("unary Branch has one child")
6806                .clone(),
6807            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => unreachable!(),
6808        };
6809        assert_eq!(local.tag(), HeadTag::LocalLeaf);
6810        assert_eq!(local.count(), 1);
6811        assert_eq!(local.hash(), unary.hash());
6812
6813        // The equal-fingerprint shortcut returns its left operand unchanged.
6814        // These shape checks therefore prove that the count-one case reaches
6815        // fingerprints rather than taking the unequal-cardinality descent.
6816        let union = Head::union(local.clone(), unary.clone(), 0);
6817        assert_eq!(union.tag(), HeadTag::LocalLeaf);
6818        let intersection = unary
6819            .intersect(&local, 0)
6820            .expect("equal singleton sets intersect");
6821        assert!(matches!(intersection.body_ref(), BodyRef::Branch(_)));
6822        assert!(unary.difference(&local, 0).is_none());
6823
6824        #[cfg(feature = "parallel")]
6825        {
6826            let union = Head::par_union(local.clone(), unary.clone(), 0);
6827            assert_eq!(union.tag(), HeadTag::LocalLeaf);
6828            let intersection = unary
6829                .par_intersect(&local, 0)
6830                .expect("equal singleton sets intersect");
6831            assert!(matches!(intersection.body_ref(), BodyRef::Branch(_)));
6832            assert!(unary.par_difference(&local, 0).is_none());
6833        }
6834    }
6835
6836    #[test]
6837    fn archive_set_ops_retain_shared_backing() {
6838        const KEY_SIZE: usize = 16;
6839        #[repr(C, align(16))]
6840        struct AlignedKey([u8; KEY_SIZE]);
6841
6842        let key_a = [0x10; KEY_SIZE];
6843        let key_b = [0x20; KEY_SIZE];
6844        let key_c = [0x30; KEY_SIZE];
6845        let (left, right) = {
6846            let storage =
6847                std::sync::Arc::new([AlignedKey(key_a), AlignedKey(key_b), AlignedKey(key_c)]);
6848            let owner: std::sync::Arc<dyn ArchiveOwner> = storage.clone();
6849            let mut left = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6850            let mut right = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
6851            for index in [0, 1] {
6852                let entry = unsafe { ArchiveEntry::new(NonNull::from(&storage[index].0), &owner) };
6853                left.insert_archive(&entry);
6854            }
6855            for index in [1, 2] {
6856                let entry = unsafe { ArchiveEntry::new(NonNull::from(&storage[index].0), &owner) };
6857                right.insert_archive(&entry);
6858            }
6859            assert!(left.node_stats().3 > 0);
6860            assert!(right.node_stats().3 > 0);
6861            (left, right)
6862        };
6863
6864        let mut union = left.clone();
6865        union.union(right.clone());
6866        assert_eq!(union.len(), 3);
6867        assert!(union.get(&key_a).is_some());
6868        assert!(union.get(&key_b).is_some());
6869        assert!(union.get(&key_c).is_some());
6870
6871        let intersection = left.intersect(&right);
6872        assert_eq!(intersection.len(), 1);
6873        assert!(intersection.get(&key_b).is_some());
6874
6875        let difference = left.difference(&right);
6876        assert_eq!(difference.len(), 1);
6877        assert!(difference.get(&key_a).is_some());
6878    }
6879
6880    #[test]
6881    fn tree_replace_existing() {
6882        const KEY_SIZE: usize = 64;
6883        let key = [1u8; KEY_SIZE];
6884        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
6885        let entry1 = Entry::with_value(&key, 1);
6886        tree.insert(&entry1);
6887        let entry2 = Entry::with_value(&key, 2);
6888        tree.replace(&entry2);
6889        assert_eq!(tree.get(&key), Some(&2));
6890    }
6891
6892    #[test]
6893    fn tree_replace_childleaf_updates_branch() {
6894        const KEY_SIZE: usize = 64;
6895        let key1 = [0u8; KEY_SIZE];
6896        let key2 = [1u8; KEY_SIZE];
6897        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
6898        let entry1 = Entry::with_value(&key1, 1);
6899        let entry2 = Entry::with_value(&key2, 2);
6900        tree.insert(&entry1);
6901        tree.insert(&entry2);
6902        let entry1b = Entry::with_value(&key1, 3);
6903        tree.replace(&entry1b);
6904        assert_eq!(tree.get(&key1), Some(&3));
6905        assert_eq!(tree.get(&key2), Some(&2));
6906    }
6907
6908    #[test]
6909    fn update_child_refreshes_childleaf_on_replace() {
6910        const KEY_SIZE: usize = 4;
6911        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
6912
6913        let key1 = [0u8; KEY_SIZE];
6914        let key2 = [1u8; KEY_SIZE];
6915        tree.insert(&Entry::with_value(&key1, 1));
6916        tree.insert(&Entry::with_value(&key2, 2));
6917
6918        // Determine which child currently provides the branch childleaf.
6919        let root_ref = tree.root.as_ref().expect("root exists");
6920        let before_childleaf = *root_ref.childleaf_key();
6921
6922        // Find the slot key (the byte index used in the branch table) for the child
6923        // that currently provides the childleaf.
6924        let slot_key = match root_ref.body_ref() {
6925            BodyRef::Branch(branch) => branch
6926                .child_table
6927                .iter()
6928                .filter_map(|c| c.as_ref())
6929                .find(|c| c.childleaf_key() == &before_childleaf)
6930                .expect("child exists")
6931                .key(),
6932            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => panic!("root should be a branch"),
6933        };
6934
6935        // Replace that child with a new leaf that has a different childleaf key.
6936        let new_key = [2u8; KEY_SIZE];
6937        {
6938            let mut ed = crate::patch::branch::BranchMut::from_slot(&mut tree.root);
6939            ed.modify_child(slot_key, |_| {
6940                Some(Entry::with_value(&new_key, 42).leaf::<IdentitySchema>())
6941            });
6942            // drop(ed) commits
6943        }
6944
6945        let after = tree.root.as_ref().expect("root exists");
6946        assert_eq!(after.childleaf_key(), &new_key);
6947    }
6948
6949    #[test]
6950    fn replace_commits_nested_structure_before_value_drop_panics() {
6951        use std::panic::{catch_unwind, AssertUnwindSafe};
6952
6953        const KEY_LEN: usize = 4;
6954        let replaced = [0, 0, 0, 0];
6955        let nested_sibling = [0, 0, 0, 1];
6956        let root_sibling = [1, 0, 0, 0];
6957        let mut patch = PATCH::<KEY_LEN, IdentitySchema, PanicOnDrop>::new();
6958
6959        for (key, should_panic) in [
6960            (replaced, true),
6961            (nested_sibling, false),
6962            (root_sibling, false),
6963        ] {
6964            let entry = Entry::with_value(&key, PanicOnDrop(should_panic));
6965            patch.insert(&entry);
6966            drop(entry);
6967        }
6968        let old_hash = patch.root_hash().expect("fixture hash");
6969        let old_nodes = patch.node_stats();
6970
6971        let replacement = Entry::with_value(&replaced, PanicOnDrop(false));
6972        let result = catch_unwind(AssertUnwindSafe(|| patch.replace(&replacement)));
6973        assert!(result.is_err());
6974
6975        assert_eq!(patch.len(), 3);
6976        assert_eq!(patch.get(&replaced).map(|value| value.0), Some(false));
6977        assert_eq!(patch.get(&nested_sibling).map(|value| value.0), Some(false));
6978        assert_eq!(patch.get(&root_sibling).map(|value| value.0), Some(false));
6979        assert_eq!(patch.root_hash(), Some(old_hash));
6980        assert_eq!(patch.node_stats(), old_nodes);
6981        assert_eq!(
6982            patch.iter_ordered().copied().collect::<Vec<_>>(),
6983            vec![replaced, nested_sibling, root_sibling],
6984        );
6985    }
6986
6987    #[test]
6988    fn replace_commits_singleton_root_before_value_drop_panics() {
6989        use std::panic::{catch_unwind, AssertUnwindSafe};
6990
6991        const KEY_LEN: usize = 4;
6992        let key = [7; KEY_LEN];
6993        let mut patch = PATCH::<KEY_LEN, IdentitySchema, PanicOnDrop>::new();
6994        let original = Entry::with_value(&key, PanicOnDrop(true));
6995        patch.insert(&original);
6996        drop(original);
6997
6998        let replacement = Entry::with_value(&key, PanicOnDrop(false));
6999        let result = catch_unwind(AssertUnwindSafe(|| patch.replace(&replacement)));
7000        assert!(result.is_err());
7001
7002        assert_eq!(patch.len(), 1);
7003        assert_eq!(patch.get(&key).map(|value| value.0), Some(false));
7004        assert_eq!(patch.root_hash(), Some(hash_key(&key)));
7005        assert!(matches!(
7006            patch.root.as_ref().expect("replacement root").body_ref(),
7007            BodyRef::Leaf(_),
7008        ));
7009    }
7010
7011    #[test]
7012    fn remove_commits_nested_structure_before_value_drop_panics() {
7013        use std::panic::{catch_unwind, AssertUnwindSafe};
7014
7015        const KEY_LEN: usize = 4;
7016        let removed = [0, 0, 0, 0];
7017        let nested_sibling = [0, 0, 0, 1];
7018        let root_sibling = [1, 0, 0, 0];
7019        let mut patch = PATCH::<KEY_LEN, IdentitySchema, PanicOnDrop>::new();
7020
7021        for (key, should_panic) in [
7022            (removed, true),
7023            (nested_sibling, false),
7024            (root_sibling, false),
7025        ] {
7026            let entry = Entry::with_value(&key, PanicOnDrop(should_panic));
7027            patch.insert(&entry);
7028            drop(entry);
7029        }
7030        assert_eq!(patch.node_stats().0, 2, "fixture must contain two branches");
7031        assert_eq!(
7032            patch.root.as_ref().expect("root branch").childleaf_key(),
7033            &removed,
7034            "the removed leaf must back the ancestor representative pointer",
7035        );
7036        let old_hash = patch.root_hash().expect("fixture hash");
7037
7038        let result = catch_unwind(AssertUnwindSafe(|| patch.remove(&removed)));
7039        assert!(result.is_err());
7040
7041        assert_eq!(patch.len(), 2);
7042        assert!(patch.get(&removed).is_none());
7043        assert!(patch.get(&nested_sibling).is_some());
7044        assert!(patch.get(&root_sibling).is_some());
7045        assert_eq!(
7046            patch.iter_ordered().copied().collect::<Vec<_>>(),
7047            vec![nested_sibling, root_sibling],
7048        );
7049        assert_eq!(patch.node_stats().0, 1, "the nested unary branch collapsed");
7050        assert_ne!(
7051            patch.root.as_ref().expect("surviving root").childleaf_key(),
7052            &removed,
7053            "the surviving branch must not retain a dangling representative",
7054        );
7055        assert_eq!(patch.root_hash(), Some(old_hash ^ hash_key(&removed)));
7056        let fanout = patch.branch_fanout_histogram();
7057        assert_eq!(fanout[0], 0);
7058        assert_eq!(fanout[1], 0);
7059    }
7060
7061    #[test]
7062    fn remove_collapses_root_before_value_drop_panics() {
7063        use std::panic::{catch_unwind, AssertUnwindSafe};
7064
7065        const KEY_LEN: usize = 4;
7066        let removed = [0; KEY_LEN];
7067        let retained = [1; KEY_LEN];
7068        let mut patch = PATCH::<KEY_LEN, IdentitySchema, PanicOnDrop>::new();
7069        for (key, should_panic) in [(removed, true), (retained, false)] {
7070            let entry = Entry::with_value(&key, PanicOnDrop(should_panic));
7071            patch.insert(&entry);
7072            drop(entry);
7073        }
7074
7075        let result = catch_unwind(AssertUnwindSafe(|| patch.remove(&removed)));
7076        assert!(result.is_err());
7077        assert_eq!(patch.len(), 1);
7078        assert!(patch.get(&removed).is_none());
7079        assert!(patch.get(&retained).is_some());
7080        assert_eq!(patch.root_hash(), Some(hash_key(&retained)));
7081        assert!(matches!(
7082            patch.root.as_ref().expect("retained root").body_ref(),
7083            BodyRef::Leaf(_),
7084        ));
7085    }
7086
7087    #[test]
7088    fn remove_commits_cow_snapshot_before_deferred_value_drop_panics() {
7089        use std::panic::{catch_unwind, AssertUnwindSafe};
7090
7091        const KEY_LEN: usize = 4;
7092        let removed = [0; KEY_LEN];
7093        let retained = [1; KEY_LEN];
7094        let mut edited = PATCH::<KEY_LEN, IdentitySchema, PanicOnDrop>::new();
7095        for (key, should_panic) in [(removed, true), (retained, false)] {
7096            let entry = Entry::with_value(&key, PanicOnDrop(should_panic));
7097            edited.insert(&entry);
7098            drop(entry);
7099        }
7100        let snapshot = edited.clone();
7101
7102        // The untouched snapshot still owns the removed leaf, so this is not
7103        // yet its final release and the edit itself cannot run `V::drop`.
7104        edited.remove(&removed);
7105        assert!(edited.get(&removed).is_none());
7106        assert!(edited.get(&retained).is_some());
7107        assert_eq!(edited.root_hash(), Some(hash_key(&retained)));
7108        assert!(snapshot.get(&removed).is_some());
7109
7110        let result = catch_unwind(AssertUnwindSafe(|| drop(snapshot)));
7111        assert!(result.is_err());
7112        assert_eq!(edited.len(), 1);
7113        assert!(edited.get(&retained).is_some());
7114    }
7115
7116    #[test]
7117    fn remove_retains_archive_owner_until_empty_then_commits_before_drop_panics() {
7118        use std::panic::{catch_unwind, AssertUnwindSafe};
7119
7120        const KEY_LEN: usize = 16;
7121        #[repr(C, align(16))]
7122        struct PanickingOwner {
7123            keys: [AlignedArchiveKey<KEY_LEN>; 2],
7124            drops: Arc<AtomicUsize>,
7125        }
7126
7127        impl Drop for PanickingOwner {
7128            fn drop(&mut self) {
7129                self.drops.fetch_add(1, Ordering::Relaxed);
7130                panic!("intentional archive owner drop panic");
7131            }
7132        }
7133
7134        let first = [7; KEY_LEN];
7135        let second = [8; KEY_LEN];
7136        let drops = Arc::new(AtomicUsize::new(0));
7137        let owner = Arc::new(PanickingOwner {
7138            keys: [AlignedArchiveKey(first), AlignedArchiveKey(second)],
7139            drops: drops.clone(),
7140        });
7141        let erased: Arc<dyn ArchiveOwner> = owner.clone();
7142        let mut patch = PATCH::<KEY_LEN, IdentitySchema>::new();
7143        for index in 0..2 {
7144            let entry = unsafe { ArchiveEntry::new(NonNull::from(&owner.keys[index].0), &erased) };
7145            patch.insert_archive(&entry);
7146        }
7147        drop(erased);
7148        drop(owner);
7149
7150        // Removing one LocalLeaf may collapse its parent, but must retain the
7151        // owner cover for the promoted survivor.
7152        patch.remove(&first);
7153        assert_eq!(drops.load(Ordering::Relaxed), 0);
7154        assert!(patch.owners.is_some());
7155        assert_eq!(patch.iter().copied().collect::<Vec<_>>(), vec![second]);
7156        assert!(matches!(
7157            patch.root.as_ref().expect("archive root").body_ref(),
7158            BodyRef::LocalLeaf(_),
7159        ));
7160
7161        let result = catch_unwind(AssertUnwindSafe(|| patch.remove(&second)));
7162        assert!(result.is_err());
7163        assert_eq!(drops.load(Ordering::Relaxed), 1);
7164        assert!(patch.root.is_none(), "the empty root was committed first");
7165        assert!(
7166            patch.owners.is_none(),
7167            "the owner cover was detached before reclamation"
7168        );
7169        assert!(patch.is_empty());
7170    }
7171
7172    #[test]
7173    fn remove_promotes_a_multi_leaf_only_child_subtree() {
7174        const KEY_LEN: usize = 4;
7175        let removed = [0, 0, 0, 0];
7176        let retained_a = [1, 0, 0, 0];
7177        let retained_b = [1, 1, 0, 0];
7178        let mut patch = PATCH::<KEY_LEN, IdentitySchema>::new();
7179        for key in [removed, retained_a, retained_b] {
7180            patch.insert(&Entry::new(&key));
7181        }
7182        assert_eq!(patch.node_stats().0, 2, "fixture must contain two branches");
7183
7184        patch.remove(&removed);
7185
7186        assert_eq!(patch.len(), 2);
7187        assert_eq!(patch.node_stats().0, 1, "unary root must be removed");
7188        assert_eq!(patch.branch_fanout_histogram()[1], 0);
7189        assert!(patch.get(&retained_a).is_some());
7190        assert!(patch.get(&retained_b).is_some());
7191    }
7192
7193    #[test]
7194    fn remove_childleaf_updates_branch() {
7195        const KEY_SIZE: usize = 4;
7196        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7197
7198        let key1 = [0u8; KEY_SIZE];
7199        let key2 = [1u8; KEY_SIZE];
7200        tree.insert(&Entry::with_value(&key1, 1));
7201        tree.insert(&Entry::with_value(&key2, 2));
7202
7203        let childleaf_before = *tree.root.as_ref().unwrap().childleaf_key();
7204        // remove the leaf that currently provides the branch.childleaf
7205        tree.remove(&childleaf_before);
7206
7207        // Ensure the removed key is gone and the other key remains and is now the childleaf.
7208        let other = if childleaf_before == key1 { key2 } else { key1 };
7209        assert_eq!(tree.get(&childleaf_before), None);
7210        assert_eq!(tree.get(&other), Some(&2u32));
7211        let after_childleaf = tree.root.as_ref().unwrap().childleaf_key();
7212        assert_eq!(after_childleaf, &other);
7213    }
7214
7215    #[test]
7216    fn remove_collapses_branch_to_single_child() {
7217        const KEY_SIZE: usize = 4;
7218        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7219
7220        let key1 = [0u8; KEY_SIZE];
7221        let key2 = [1u8; KEY_SIZE];
7222        tree.insert(&Entry::with_value(&key1, 1));
7223        tree.insert(&Entry::with_value(&key2, 2));
7224
7225        // Remove one key and ensure the root collapses to the remaining child.
7226        tree.remove(&key1);
7227        assert_eq!(tree.get(&key1), None);
7228        assert_eq!(tree.get(&key2), Some(&2u32));
7229        let root = tree.root.as_ref().expect("root exists");
7230        match root.body_ref() {
7231            BodyRef::Leaf(_) | BodyRef::LocalLeaf(_) => {}
7232            BodyRef::Branch(_) => panic!("root should have collapsed to a leaf"),
7233        }
7234    }
7235
7236    #[test]
7237    fn branch_size() {
7238        // Ownership lives once on PATCH, leaving the original 48-byte Branch
7239        // header. Each child is an 8-byte tagged Head.
7240        assert_eq!(
7241            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 2], ()>>(
7242            ),
7243            48 + 8 * 2
7244        );
7245        assert_eq!(
7246            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 4], ()>>(
7247            ),
7248            48 + 8 * 4
7249        );
7250        assert_eq!(
7251            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 8], ()>>(
7252            ),
7253            48 + 8 * 8
7254        );
7255        assert_eq!(
7256            mem::size_of::<
7257                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 16], ()>,
7258            >(),
7259            48 + 8 * 16
7260        );
7261        assert_eq!(
7262            mem::size_of::<
7263                Branch<64, IdentitySchema, [Option<Head<32, IdentitySchema, ()>>; 32], ()>,
7264            >(),
7265            48 + 8 * 32
7266        );
7267        assert_eq!(
7268            mem::size_of::<
7269                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 64], ()>,
7270            >(),
7271            48 + 8 * 64
7272        );
7273        assert_eq!(
7274            mem::size_of::<
7275                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 128], ()>,
7276            >(),
7277            48 + 8 * 128
7278        );
7279        assert_eq!(
7280            mem::size_of::<
7281                Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 256], ()>,
7282            >(),
7283            48 + 8 * 256
7284        );
7285    }
7286
7287    #[test]
7288    fn patch_root_owner_cover_is_one_thin_arc() {
7289        // Default-policy layout is a compatibility and performance contract:
7290        // making PATCH generic must not charge TribleSet for the stronger
7291        // digest it does not use.
7292        assert_eq!(mem::size_of::<Entry<64, ()>>(), 8);
7293        assert_eq!(mem::size_of::<Leaf<64, ()>>(), 96);
7294        assert_eq!(mem::size_of::<Head<64, IdentitySchema, ()>>(), 8);
7295        assert_eq!(
7296            mem::size_of::<Branch<64, IdentitySchema, [Option<Head<64, IdentitySchema, ()>>; 0], ()>>(
7297            ),
7298            48
7299        );
7300        assert_eq!(mem::size_of::<Option<Arc<OwnerCover>>>(), 8);
7301        assert_eq!(mem::size_of::<PATCH<64, IdentitySchema, ()>>(), 16);
7302
7303        assert_eq!(mem::size_of::<Entry<64, (), Blake3Merkle>>(), 8);
7304        assert_eq!(mem::size_of::<Leaf<64, (), Blake3Merkle>>(), 112);
7305        assert_eq!(
7306            mem::size_of::<
7307                Branch<
7308                    64,
7309                    IdentitySchema,
7310                    [Option<Head<64, IdentitySchema, (), Blake3Merkle>>; 0],
7311                    (),
7312                    Blake3Merkle,
7313                >,
7314            >(),
7315            64
7316        );
7317        assert_eq!(
7318            mem::size_of::<PATCH<64, IdentitySchema, (), Blake3Merkle>>(),
7319            16
7320        );
7321    }
7322
7323    /// Checks what happens if we join two PATCHes that
7324    /// only contain a single element each, that differs in the last byte.
7325    #[test]
7326    fn tree_union_single() {
7327        const KEY_SIZE: usize = 8;
7328        let mut left = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7329        let mut right = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7330        let left_entry = Entry::new(&[0, 0, 0, 0, 0, 0, 0, 0]);
7331        let right_entry = Entry::new(&[0, 0, 0, 0, 0, 0, 0, 1]);
7332        left.insert(&left_entry);
7333        right.insert(&right_entry);
7334        left.union(right);
7335        assert_eq!(left.len(), 2);
7336    }
7337
7338    /// Both union arms must produce the same trie.
7339    ///
7340    /// `PATCH::union` dispatches to the work-stealing `Head::par_union`
7341    /// when the `parallel` feature is compiled, and to the serial
7342    /// `Head::union` when it is not, so no single build exercises both.
7343    /// This compares whichever arm the build selected against a
7344    /// reference that uses neither: the same key set inserted directly.
7345    /// Running it under both feature settings pins the two arms to the
7346    /// same trie without either of them being the other's oracle.
7347    ///
7348    /// It exists because `trible`'s manifest dropped the feature for
7349    /// months, so a rollout that restores it changes which arm the
7350    /// maintenance daemons run. That is only safe if the arms agree,
7351    /// and agreeing is a claim a test should make rather than a reader.
7352    #[test]
7353    fn union_matches_insertion_reference() {
7354        const KEY_SIZE: usize = 8;
7355        // Comfortably past PARALLEL_PATCH_UNION_THRESHOLD (4096) so the
7356        // parallel build takes its scatter-and-spawn arm rather than the
7357        // per-key fallback that a small asymmetric merge would take.
7358        const KEYS: u64 = 12_000;
7359
7360        let build = |start: u64, step: u64| {
7361            let mut tree = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7362            for index in 0..KEYS {
7363                let key = (start + index * step).to_be_bytes();
7364                tree.insert(&Entry::new(&key));
7365            }
7366            tree
7367        };
7368
7369        // The disjoint even/odd key sets have interleaved ranges and shared
7370        // byte prefixes, so the equal-depth branch arm has "both" pairs to
7371        // drain. Root-level scatter is exercised; child pairs are smaller.
7372        let mut united = build(0, 2);
7373        united.union(build(1, 2));
7374
7375        let mut reference = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7376        for index in 0..(2 * KEYS) {
7377            reference.insert(&Entry::new(&index.to_be_bytes()));
7378        }
7379
7380        assert_eq!(united.len(), 2 * KEYS);
7381        assert_eq!(united.len(), reference.len());
7382        assert_eq!(united, reference);
7383
7384        let mut united_keys = Vec::new();
7385        united.infixes(&[0u8; 0], &mut |&key: &[u8; KEY_SIZE]| {
7386            united_keys.push(key)
7387        });
7388        let mut reference_keys = Vec::new();
7389        reference.infixes(&[0u8; 0], &mut |&key: &[u8; KEY_SIZE]| {
7390            reference_keys.push(key)
7391        });
7392        united_keys.sort_unstable();
7393        reference_keys.sort_unstable();
7394        assert_eq!(united_keys, reference_keys);
7395    }
7396
7397    // Small unit tests that ensure BranchMut-based editing is used by
7398    // the higher-level set operations like intersect/difference. These are
7399    // ordinary unit tests (not proptest) and must appear outside the
7400    // `proptest!` macro below.
7401
7402    proptest! {
7403        #[test]
7404        fn tree_insert(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
7405            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
7406            for key in keys {
7407                let key: [u8; 64] = key.try_into().unwrap();
7408                let entry = Entry::new(&key);
7409                tree.insert(&entry);
7410            }
7411        }
7412
7413        #[test]
7414        fn tree_len(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
7415            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
7416            let mut set = HashSet::new();
7417            for key in keys {
7418                let key: [u8; 64] = key.try_into().unwrap();
7419                let entry = Entry::new(&key);
7420                tree.insert(&entry);
7421                set.insert(key);
7422            }
7423
7424            prop_assert_eq!(set.len() as u64, tree.len())
7425        }
7426
7427        #[test]
7428        fn tree_infixes(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
7429            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
7430            let mut set = HashSet::new();
7431            for key in keys {
7432                let key: [u8; 64] = key.try_into().unwrap();
7433                let entry = Entry::new(&key);
7434                tree.insert(&entry);
7435                set.insert(key);
7436            }
7437            let mut set_vec = Vec::from_iter(set.into_iter());
7438            let mut tree_vec = vec![];
7439            tree.infixes(&[0; 0], &mut |&x: &[u8; 64]| tree_vec.push(x));
7440
7441            set_vec.sort();
7442            tree_vec.sort();
7443
7444            prop_assert_eq!(set_vec, tree_vec);
7445        }
7446
7447        #[test]
7448        fn tree_iter(keys in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 1..1024)) {
7449            let mut tree = PATCH::<64, IdentitySchema, ()>::new();
7450            let mut set = HashSet::new();
7451            for key in keys {
7452                let key: [u8; 64] = key.try_into().unwrap();
7453                let entry = Entry::new(&key);
7454                tree.insert(&entry);
7455                set.insert(key);
7456            }
7457            let mut set_vec = Vec::from_iter(set.into_iter());
7458            let mut tree_vec = vec![];
7459            for key in &tree {
7460                tree_vec.push(*key);
7461            }
7462
7463            set_vec.sort();
7464            tree_vec.sort();
7465
7466            prop_assert_eq!(set_vec, tree_vec);
7467        }
7468
7469        #[test]
7470        fn tree_union(left in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 200),
7471                        right in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 200)) {
7472            let mut set = HashSet::new();
7473
7474            let mut left_tree = PATCH::<64, IdentitySchema, ()>::new();
7475            for entry in left {
7476                let mut key = [0; 64];
7477                key.iter_mut().set_from(entry.iter().cloned());
7478                let entry = Entry::new(&key);
7479                left_tree.insert(&entry);
7480                set.insert(key);
7481            }
7482
7483            let mut right_tree = PATCH::<64, IdentitySchema, ()>::new();
7484            for entry in right {
7485                let mut key = [0; 64];
7486                key.iter_mut().set_from(entry.iter().cloned());
7487                let entry = Entry::new(&key);
7488                right_tree.insert(&entry);
7489                set.insert(key);
7490            }
7491
7492            left_tree.union(right_tree);
7493
7494            let mut set_vec = Vec::from_iter(set.into_iter());
7495            let mut tree_vec = vec![];
7496            left_tree.infixes(&[0; 0], &mut |&x: &[u8;64]| tree_vec.push(x));
7497
7498            set_vec.sort();
7499            tree_vec.sort();
7500
7501            prop_assert_eq!(set_vec, tree_vec);
7502            }
7503
7504        #[test]
7505        fn tree_union_empty(left in prop::collection::vec(prop::collection::vec(0u8..=255, 64), 2)) {
7506            let mut set = HashSet::new();
7507
7508            let mut left_tree = PATCH::<64, IdentitySchema, ()>::new();
7509            for entry in left {
7510                let mut key = [0; 64];
7511                key.iter_mut().set_from(entry.iter().cloned());
7512                let entry = Entry::new(&key);
7513                left_tree.insert(&entry);
7514                set.insert(key);
7515            }
7516
7517            let right_tree = PATCH::<64, IdentitySchema, ()>::new();
7518
7519            left_tree.union(right_tree);
7520
7521            let mut set_vec = Vec::from_iter(set.into_iter());
7522            let mut tree_vec = vec![];
7523            left_tree.infixes(&[0; 0], &mut |&x: &[u8;64]| tree_vec.push(x));
7524
7525            set_vec.sort();
7526            tree_vec.sort();
7527
7528            prop_assert_eq!(set_vec, tree_vec);
7529            }
7530
7531        // I got a feeling that we're not testing COW properly.
7532        // We should check if a tree remains the same after a clone of it
7533        // is modified by inserting new keys.
7534
7535    #[test]
7536    fn cow_on_insert(base_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024),
7537                         new_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024)) {
7538            // Note that we can't compare the trees directly, as that uses the hash,
7539            // which might not be affected by nodes in lower levels being changed accidentally.
7540            // Instead we need to iterate over the keys and check if they are the same.
7541
7542            let mut tree = PATCH::<8, IdentitySchema, ()>::new();
7543            for key in base_keys {
7544                let key: [u8; 8] = key[..].try_into().unwrap();
7545                let entry = Entry::new(&key);
7546                tree.insert(&entry);
7547            }
7548            let base_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
7549
7550            let mut tree_clone = tree.clone();
7551            for key in new_keys {
7552                let key: [u8; 8] = key[..].try_into().unwrap();
7553                let entry = Entry::new(&key);
7554                tree_clone.insert(&entry);
7555            }
7556
7557            let new_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
7558            prop_assert_eq!(base_tree_content, new_tree_content);
7559        }
7560
7561        #[test]
7562    fn cow_on_union(base_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024),
7563                         new_keys in prop::collection::vec(prop::collection::vec(0u8..=255, 8), 1..1024)) {
7564            // Note that we can't compare the trees directly, as that uses the hash,
7565            // which might not be affected by nodes in lower levels being changed accidentally.
7566            // Instead we need to iterate over the keys and check if they are the same.
7567
7568            let mut tree = PATCH::<8, IdentitySchema, ()>::new();
7569            for key in base_keys {
7570                let key: [u8; 8] = key[..].try_into().unwrap();
7571                let entry = Entry::new(&key);
7572                tree.insert(&entry);
7573            }
7574            let base_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
7575
7576            let mut tree_clone = tree.clone();
7577            let mut new_tree = PATCH::<8, IdentitySchema, ()>::new();
7578            for key in new_keys {
7579                let key: [u8; 8] = key[..].try_into().unwrap();
7580                let entry = Entry::new(&key);
7581                new_tree.insert(&entry);
7582            }
7583            tree_clone.union(new_tree);
7584
7585            let new_tree_content: Vec<[u8; 8]> = tree.iter().copied().collect();
7586            prop_assert_eq!(base_tree_content, new_tree_content);
7587        }
7588    }
7589
7590    #[test]
7591    fn intersect_multiple_common_children_commits_branchmut() {
7592        const KEY_SIZE: usize = 4;
7593        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7594        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7595
7596        let a = [0u8, 0u8, 0u8, 1u8];
7597        let b = [0u8, 0u8, 0u8, 2u8];
7598        let c = [0u8, 0u8, 0u8, 3u8];
7599        let d = [2u8, 0u8, 0u8, 0u8];
7600        let e = [3u8, 0u8, 0u8, 0u8];
7601
7602        left.insert(&Entry::with_value(&a, 1));
7603        left.insert(&Entry::with_value(&b, 2));
7604        left.insert(&Entry::with_value(&c, 3));
7605        left.insert(&Entry::with_value(&d, 4));
7606
7607        right.insert(&Entry::with_value(&a, 10));
7608        right.insert(&Entry::with_value(&b, 11));
7609        right.insert(&Entry::with_value(&c, 12));
7610        right.insert(&Entry::with_value(&e, 13));
7611
7612        let res = left.intersect(&right);
7613        // A, B, C are common
7614        assert_eq!(res.len(), 3);
7615        assert!(res.get(&a).is_some());
7616        assert!(res.get(&b).is_some());
7617        assert!(res.get(&c).is_some());
7618    }
7619
7620    #[test]
7621    fn difference_multiple_children_commits_branchmut() {
7622        const KEY_SIZE: usize = 4;
7623        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7624        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7625
7626        let a = [0u8, 0u8, 0u8, 1u8];
7627        let b = [0u8, 0u8, 0u8, 2u8];
7628        let c = [0u8, 0u8, 0u8, 3u8];
7629        let d = [2u8, 0u8, 0u8, 0u8];
7630        let e = [3u8, 0u8, 0u8, 0u8];
7631
7632        left.insert(&Entry::with_value(&a, 1));
7633        left.insert(&Entry::with_value(&b, 2));
7634        left.insert(&Entry::with_value(&c, 3));
7635        left.insert(&Entry::with_value(&d, 4));
7636
7637        right.insert(&Entry::with_value(&a, 10));
7638        right.insert(&Entry::with_value(&b, 11));
7639        right.insert(&Entry::with_value(&c, 12));
7640        right.insert(&Entry::with_value(&e, 13));
7641
7642        let res = left.difference(&right);
7643        // left only has d
7644        assert_eq!(res.len(), 1);
7645        assert!(res.get(&d).is_some());
7646    }
7647
7648    #[test]
7649    fn difference_equal_singleton_after_survivor_collapse_is_empty() {
7650        const KEY_SIZE: usize = 16;
7651        let removed_key = [0x10; KEY_SIZE];
7652        let survivor_key = [0x20; KEY_SIZE];
7653
7654        let mut pair = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7655        pair.insert(&Entry::with_value(&removed_key, 1));
7656        pair.insert(&Entry::with_value(&survivor_key, 2));
7657
7658        let mut removed = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7659        removed.insert(&Entry::with_value(&removed_key, 1));
7660        let collapsed_survivor = pair.difference(&removed);
7661        assert_eq!(collapsed_survivor.len(), 1);
7662        assert_eq!(
7663            collapsed_survivor.root.as_ref().map(Head::tag),
7664            Some(HeadTag::Leaf),
7665        );
7666
7667        let mut survivor = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7668        survivor.insert(&Entry::with_value(&survivor_key, 2));
7669        assert_eq!(collapsed_survivor, survivor);
7670        assert!(collapsed_survivor.difference(&survivor).root.is_none());
7671    }
7672
7673    #[test]
7674    fn difference_empty_left_is_empty() {
7675        const KEY_SIZE: usize = 4;
7676        let left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7677        let mut right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7678        let key = [1u8, 2u8, 3u8, 4u8];
7679        right.insert(&Entry::with_value(&key, 7));
7680
7681        let res = left.difference(&right);
7682        assert_eq!(res.len(), 0);
7683    }
7684
7685    fn inclusion_agrees_with_difference<const KEY_SIZE: usize>(
7686        left: &PATCH<KEY_SIZE, IdentitySchema, ()>,
7687        right: &PATCH<KEY_SIZE, IdentitySchema, ()>,
7688    ) {
7689        let left_inside = left.difference(right).is_empty();
7690        let right_inside = right.difference(left).is_empty();
7691        let expected = match (left_inside, right_inside) {
7692            (true, true) => Some(std::cmp::Ordering::Equal),
7693            (true, false) => Some(std::cmp::Ordering::Less),
7694            (false, true) => Some(std::cmp::Ordering::Greater),
7695            (false, false) => None,
7696        };
7697        assert_eq!(left.partial_cmp(right), expected);
7698        assert_eq!(right.partial_cmp(left), expected.map(std::cmp::Ordering::reverse));
7699        assert_eq!(left <= right, left_inside);
7700        assert_eq!(right <= left, right_inside);
7701    }
7702
7703    #[test]
7704    fn inclusion_matches_the_difference_oracle_on_wide_random_keys() {
7705        use rand::RngCore;
7706        const KEY_SIZE: usize = 32;
7707        let mut rng = thread_rng();
7708        for _ in 0..64 {
7709            let mut left = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7710            let mut right = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7711            for _ in 0..(rng.next_u32() % 48) {
7712                let mut key = [0u8; KEY_SIZE];
7713                rng.fill_bytes(&mut key);
7714                // Shared, left-only, or right-only.
7715                match rng.next_u32() % 3 {
7716                    0 => {
7717                        left.insert(&Entry::new(&key));
7718                        right.insert(&Entry::new(&key));
7719                    }
7720                    1 => left.insert(&Entry::new(&key)),
7721                    _ => right.insert(&Entry::new(&key)),
7722                }
7723            }
7724            inclusion_agrees_with_difference(&left, &right);
7725            let mut union = left.clone();
7726            union.union(right.clone());
7727            assert!(left <= union);
7728            assert!(right <= union);
7729            assert_eq!(union <= left, right <= left);
7730            assert_eq!(union == left, right <= left);
7731        }
7732    }
7733
7734    #[test]
7735    fn inclusion_matches_the_difference_oracle_on_narrow_alphabets() {
7736        use rand::RngCore;
7737        // Three symbols over eight bytes: keys collide on long prefixes, so
7738        // every depth case of the walk is exercised, including subtrees the
7739        // two tries hold with equal contents.
7740        const KEY_SIZE: usize = 8;
7741        let mut rng = thread_rng();
7742        for _ in 0..256 {
7743            let mut left = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7744            let mut right = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7745            for _ in 0..(rng.next_u32() % 24) {
7746                let mut key = [0u8; KEY_SIZE];
7747                for byte in &mut key {
7748                    *byte = (rng.next_u32() % 3) as u8;
7749                }
7750                match rng.next_u32() % 3 {
7751                    0 => {
7752                        left.insert(&Entry::new(&key));
7753                        right.insert(&Entry::new(&key));
7754                    }
7755                    1 => left.insert(&Entry::new(&key)),
7756                    _ => right.insert(&Entry::new(&key)),
7757                }
7758            }
7759            inclusion_agrees_with_difference(&left, &right);
7760            let empty = PATCH::<KEY_SIZE, IdentitySchema, ()>::new();
7761            assert!(empty <= left);
7762            assert_eq!(left <= empty, left.is_empty());
7763            assert_eq!(left.partial_cmp(&left), Some(std::cmp::Ordering::Equal));
7764        }
7765    }
7766
7767    #[test]
7768    fn difference_empty_right_returns_left() {
7769        const KEY_SIZE: usize = 4;
7770        let mut left = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7771        let right = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7772        let key = [1u8, 2u8, 3u8, 4u8];
7773        left.insert(&Entry::with_value(&key, 7));
7774
7775        let res = left.difference(&right);
7776        assert_eq!(res.len(), 1);
7777        assert!(res.get(&key).is_some());
7778    }
7779
7780    #[test]
7781    fn slot_edit_branchmut_insert_update() {
7782        // Small unit test demonstrating the Slot::edit -> BranchMut insert/update pattern.
7783        const KEY_SIZE: usize = 8;
7784        let mut tree = PATCH::<KEY_SIZE, IdentitySchema, u32>::new();
7785
7786        let entry1 = Entry::with_value(&[0u8; KEY_SIZE], 1u32);
7787        let entry2 = Entry::with_value(&[1u8; KEY_SIZE], 2u32);
7788        tree.insert(&entry1);
7789        tree.insert(&entry2);
7790        assert_eq!(tree.len(), 2);
7791
7792        // Edit the root slot in-place using the BranchMut editor.
7793        {
7794            let mut ed = crate::patch::branch::BranchMut::from_slot(&mut tree.root);
7795
7796            // Compute the insertion start depth first to avoid borrowing `ed` inside the closure.
7797            let start_depth = ed.end_depth as usize;
7798            let inserted = Entry::with_value(&[2u8; KEY_SIZE], 3u32)
7799                .leaf::<IdentitySchema>()
7800                .with_start(start_depth);
7801            let key = inserted.key();
7802
7803            ed.modify_child(key, |opt| match opt {
7804                Some(old) => Some(Head::insert_leaf(old, inserted, start_depth)),
7805                None => Some(inserted),
7806            });
7807            // BranchMut is dropped here and commits the updated branch pointer back into the head.
7808        }
7809
7810        assert_eq!(tree.len(), 3);
7811        assert_eq!(tree.get(&[2u8; KEY_SIZE]), Some(&3u32));
7812    }
7813}