Skip to main content

prolly/prolly/
range.rs

1//! Range iteration operations for Prolly trees
2//!
3//! This module handles range queries and iteration over key-value pairs
4//! within specified bounds. It provides efficient traversal of the tree
5//! in lexicographic order with support for start and end bounds.
6//!
7//! # Overview
8//!
9//! Range iteration allows traversing key-value pairs in sorted order within
10//! a specified key range. The iterator efficiently navigates the tree structure,
11//! handling node boundaries transparently.
12//!
13//! # Iteration Behavior
14//!
15//! ## Start Bound (Inclusive)
16//!
17//! The iterator begins at the first key greater than or equal to the start bound.
18//! If the start key exists, iteration begins there. If not, iteration begins at
19//! the next key in lexicographic order.
20//!
21//! Use an empty slice (`&[]`) to start from the beginning of the tree.
22//!
23//! ## End Bound (Exclusive)
24//!
25//! The iterator stops before reaching the end bound. Keys equal to or greater
26//! than the end bound are not yielded.
27//!
28//! Use `None` to iterate to the end of the tree.
29//!
30//! # Implementation Details
31//!
32//! The iterator maintains a stack of (node, index) pairs representing the
33//! current position in the tree. This allows efficient traversal across
34//! node boundaries without restarting from the root.
35//!
36//! ## Traversal Algorithm
37//!
38//! 1. **Initial positioning**: Find the path to the start key
39//! 2. **Leaf iteration**: Yield entries from the current leaf
40//! 3. **Node advancement**: When a leaf is exhausted, backtrack to find the next leaf
41//! 4. **Bound checking**: Stop when the end bound is reached
42//!
43//! # Example
44//!
45//! ```rust
46//! use prolly::{Prolly, MemStore, Config};
47//!
48//! let store = MemStore::new();
49//! let prolly = Prolly::new(store, Config::default());
50//! let mut tree = prolly.create();
51//!
52//! // Insert some data
53//! tree = prolly.put(&tree, b"a".to_vec(), b"1".to_vec()).unwrap();
54//! tree = prolly.put(&tree, b"b".to_vec(), b"2".to_vec()).unwrap();
55//! tree = prolly.put(&tree, b"c".to_vec(), b"3".to_vec()).unwrap();
56//! tree = prolly.put(&tree, b"d".to_vec(), b"4".to_vec()).unwrap();
57//!
58//! // Iterate over all keys
59//! for result in prolly.range(&tree, &[], None).unwrap() {
60//!     let (key, val) = result.unwrap();
61//!     println!("{:?} -> {:?}", key, val);
62//! }
63//!
64//! // Iterate over range [b, d) - yields "b" and "c"
65//! for result in prolly.range(&tree, b"b", Some(b"d")).unwrap() {
66//!     let (key, val) = result.unwrap();
67//!     println!("{:?} -> {:?}", key, val);
68//! }
69//! ```
70//!
71//! # Performance
72//!
73//! - **Initial seek**: O(log n) to find the starting position
74//! - **Per-entry**: O(1) amortized for sequential access within a leaf
75//! - **Node transitions**: O(log n) worst case, but typically O(1) amortized
76//!
77//! The iterator is lazy and only loads nodes as needed, making it memory-efficient
78//! for large trees.
79
80use super::cid::Cid;
81use super::error::Error;
82use super::node::Node;
83use super::store::Store;
84use super::tree::Tree;
85
86use super::Prolly;
87#[cfg(feature = "async-store")]
88use super::{store::AsyncStore, AsyncProlly};
89#[cfg(feature = "async-store")]
90use futures_util::stream::{self, Stream};
91use serde::{Deserialize, Serialize};
92use std::sync::Arc;
93
94type RangeItem = Result<(Vec<u8>, Vec<u8>), Error>;
95type LeafEntry = (Vec<u8>, Vec<u8>);
96type OptionalLeafEntry = Result<Option<LeafEntry>, Error>;
97pub(crate) const RANGE_CHILD_PREFETCH_PARALLELISM: usize = 16;
98
99/// Stable cursor token for resumable range scans.
100///
101/// The token is independent of in-memory traversal state: it records the last
102/// emitted key, and the next scan resumes strictly after that key. This makes it
103/// suitable for checkpointing background indexing or sync jobs for an immutable
104/// tree snapshot.
105#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
106pub struct RangeCursor {
107    after_key: Option<Vec<u8>>,
108}
109
110impl RangeCursor {
111    /// Start scanning from the beginning of the requested range.
112    pub fn start() -> Self {
113        Self { after_key: None }
114    }
115
116    /// Resume scanning strictly after `key`.
117    pub fn after_key(key: impl Into<Vec<u8>>) -> Self {
118        Self {
119            after_key: Some(key.into()),
120        }
121    }
122
123    /// Return the key this cursor resumes after, if any.
124    pub fn after(&self) -> Option<&[u8]> {
125        self.after_key.as_deref()
126    }
127
128    /// Whether this cursor represents the beginning of a range.
129    pub fn is_start(&self) -> bool {
130        self.after_key.is_none()
131    }
132}
133
134/// A bounded page of range-scan results.
135///
136/// `next_cursor` is `Some` when another call should resume after the last entry
137/// in this page. It is `None` when the scan reached the end bound or the end of
138/// the tree.
139#[derive(Clone, Debug, Default, PartialEq, Eq)]
140pub struct RangePage {
141    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
142    pub next_cursor: Option<RangeCursor>,
143}
144
145/// Stable cursor token for resumable reverse scans.
146///
147/// The token records the next exclusive upper bound. A start cursor scans from
148/// the end of the requested range; a resumed cursor scans keys strictly before
149/// `before_key`.
150#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
151pub struct ReverseCursor {
152    before_key: Option<Vec<u8>>,
153}
154
155impl ReverseCursor {
156    /// Start scanning from the end of the requested range.
157    pub fn end() -> Self {
158        Self { before_key: None }
159    }
160
161    /// Resume scanning strictly before `key`.
162    pub fn before_key(key: impl Into<Vec<u8>>) -> Self {
163        Self {
164            before_key: Some(key.into()),
165        }
166    }
167
168    /// Return the key this cursor resumes before, if any.
169    pub fn before(&self) -> Option<&[u8]> {
170        self.before_key.as_deref()
171    }
172
173    /// Whether this cursor represents the end of a range.
174    pub fn is_end(&self) -> bool {
175        self.before_key.is_none()
176    }
177}
178
179/// A bounded page of reverse-scan results.
180///
181/// Entries are returned in descending key order. `next_cursor` is `Some` when
182/// another call should resume before the last entry in this page.
183#[derive(Clone, Debug, Default, PartialEq, Eq)]
184pub struct ReversePage {
185    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
186    pub next_cursor: Option<ReverseCursor>,
187}
188
189/// Bounded result for a stateless cursor seek.
190///
191/// `position_key`/`position_value` report where the internal cursor lands for
192/// the requested seek key. This is the exact key when `found` is true; otherwise
193/// it is the closest leaf entry chosen by cursor navigation. `entries` are the
194/// forward window starting at the first key greater than or equal to the seek
195/// key, and `next_cursor` resumes after the last emitted entry.
196#[derive(Clone, Debug, Default, PartialEq, Eq)]
197pub struct CursorWindow {
198    pub position_key: Option<Vec<u8>>,
199    pub position_value: Option<Vec<u8>>,
200    pub found: bool,
201    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
202    pub next_cursor: Option<RangeCursor>,
203}
204
205/// Backward-compatible name for async range pages.
206#[cfg(feature = "async-store")]
207pub type AsyncRangePage = RangePage;
208
209/// Backward-compatible name for async reverse range pages.
210#[cfg(feature = "async-store")]
211pub type AsyncReversePage = ReversePage;
212
213/// Create a range iterator over key-value pairs.
214///
215/// Returns an iterator that yields `(key, value)` pairs in lexicographic order,
216/// starting from `start` (inclusive) up to `end` (exclusive).
217///
218/// # Arguments
219/// * `prolly` - Reference to the Prolly tree manager
220/// * `tree` - The tree to iterate over
221/// * `start` - The starting key (inclusive). Use `&[]` to start from the beginning.
222/// * `end` - Optional ending key (exclusive). Use `None` to iterate to the end.
223///
224/// # Returns
225/// * `Ok(RangeIter)` - An iterator over the range
226/// * `Err` on storage or deserialization errors during path finding
227pub fn create_range_iter<'a, S: Store>(
228    prolly: &'a Prolly<S>,
229    tree: &Tree,
230    start: &[u8],
231    end: Option<&[u8]>,
232) -> Result<RangeIter<'a, S>, Error> {
233    if end.is_some_and(|end| end <= start) {
234        return Ok(RangeIter::new(prolly, Vec::new(), start, end));
235    }
236
237    // Find path to start key
238    let path = prolly.find_path_arcs(tree, start)?;
239    Ok(RangeIter::new(prolly, path, start, end))
240}
241
242/// Create a range iterator that starts strictly after `after_key`.
243pub fn create_range_after_iter<'a, S: Store>(
244    prolly: &'a Prolly<S>,
245    tree: &Tree,
246    after_key: &[u8],
247    end: Option<&[u8]>,
248) -> Result<RangeIter<'a, S>, Error> {
249    if end.is_some_and(|end| end <= after_key) {
250        return Ok(RangeIter::new_after(prolly, Vec::new(), after_key, end));
251    }
252
253    let path = prolly.find_path_arcs(tree, after_key)?;
254    Ok(RangeIter::new_after(prolly, path, after_key, end))
255}
256
257/// Create an async range iterator over key-value pairs.
258#[cfg(feature = "async-store")]
259pub async fn create_async_range_iter<'a, S>(
260    prolly: &'a AsyncProlly<S>,
261    tree: &Tree,
262    start: &[u8],
263    end: Option<&[u8]>,
264) -> Result<AsyncRangeIter<'a, S>, Error>
265where
266    S: AsyncStore,
267    S::Error: Send + Sync,
268{
269    if end.is_some_and(|end| end <= start) {
270        return Ok(AsyncRangeIter::new(prolly, Vec::new(), start, end));
271    }
272
273    let path = prolly.find_path_arcs(tree, start).await?;
274    Ok(AsyncRangeIter::new(prolly, path, start, end))
275}
276
277/// Create an async range iterator that starts strictly after `after_key`.
278#[cfg(feature = "async-store")]
279pub async fn create_async_range_after_iter<'a, S>(
280    prolly: &'a AsyncProlly<S>,
281    tree: &Tree,
282    after_key: &[u8],
283    end: Option<&[u8]>,
284) -> Result<AsyncRangeIter<'a, S>, Error>
285where
286    S: AsyncStore,
287    S::Error: Send + Sync,
288{
289    if end.is_some_and(|end| end <= after_key) {
290        return Ok(AsyncRangeIter::new_after(
291            prolly,
292            Vec::new(),
293            after_key,
294            end,
295        ));
296    }
297
298    let path = prolly.find_path_arcs(tree, after_key).await?;
299    Ok(AsyncRangeIter::new_after(prolly, path, after_key, end))
300}
301
302/// Iterator over key-value pairs in a range.
303///
304/// Created by [`Prolly::range`]. Yields `(key, value)` pairs in lexicographic
305/// order.
306///
307/// Maintains a stack of (node, index) pairs to track the current position in the tree
308/// and supports optional end bounds for range queries.
309pub struct RangeIter<'a, S: Store> {
310    /// Reference to the Prolly tree manager
311    prolly: &'a Prolly<S>,
312    /// Stack of (node, index) pairs representing the traversal path
313    stack: Vec<(Arc<Node>, usize)>,
314    /// Optional end bound (exclusive)
315    end: Option<Vec<u8>>,
316    /// Whether we've started iteration (for positioning at start key)
317    started: bool,
318    /// The start key for initial positioning
319    start_key: Vec<u8>,
320    /// Whether to skip an entry equal to the start key.
321    skip_start_key: bool,
322    /// Last key yielded by this iterator.
323    last_key: Option<Vec<u8>>,
324}
325
326impl<'a, S: Store> RangeIter<'a, S> {
327    /// Create a new range iterator.
328    ///
329    /// # Arguments
330    /// * `prolly` - Reference to the Prolly tree manager
331    /// * `stack` - Initial traversal path from find_path
332    /// * `start` - The starting key (inclusive)
333    /// * `end` - Optional ending key (exclusive)
334    pub(crate) fn new(
335        prolly: &'a Prolly<S>,
336        stack: Vec<(Arc<Node>, usize)>,
337        start: &[u8],
338        end: Option<&[u8]>,
339    ) -> Self {
340        Self {
341            prolly,
342            stack,
343            end: end.map(|e| e.to_vec()),
344            started: false,
345            start_key: start.to_vec(),
346            skip_start_key: false,
347            last_key: None,
348        }
349    }
350
351    pub(crate) fn new_after(
352        prolly: &'a Prolly<S>,
353        stack: Vec<(Arc<Node>, usize)>,
354        after_key: &[u8],
355        end: Option<&[u8]>,
356    ) -> Self {
357        Self {
358            prolly,
359            stack,
360            end: end.map(|e| e.to_vec()),
361            started: false,
362            start_key: after_key.to_vec(),
363            skip_start_key: true,
364            last_key: None,
365        }
366    }
367
368    /// Return a resumable cursor for the last key yielded by this iterator.
369    ///
370    /// If the iterator has not yielded an item yet, this returns
371    /// [`RangeCursor::start`].
372    pub fn resume_cursor(&self) -> RangeCursor {
373        self.last_key
374            .clone()
375            .map(RangeCursor::after_key)
376            .unwrap_or_else(RangeCursor::start)
377    }
378
379    /// Position the iterator at the first key >= start_key.
380    ///
381    /// Called on the first iteration to find the correct starting position
382    /// in the leaf node.
383    fn position_at_start(&mut self) -> Option<RangeItem> {
384        self.started = true;
385
386        // If stack is empty, tree is empty
387        if self.stack.is_empty() {
388            return None;
389        }
390
391        // Find the first key >= start_key in the leaf
392        let (node, idx) = self.stack.last_mut()?;
393
394        // If we're at a leaf, find the correct starting position
395        if node.leaf {
396            // Find first key >= start_key
397            let start_idx = match node.search(&self.start_key) {
398                Ok(i) if self.skip_start_key => i.saturating_add(1),
399                Ok(i) => i,  // Exact match
400                Err(i) => i, // First key > start_key
401            };
402
403            *idx = start_idx;
404
405            // Check if we're past the end of this node
406            if *idx >= node.len() {
407                // Need to advance to next node
408                return self.advance_to_next_leaf();
409            }
410
411            match leaf_entry_before_end(node, *idx, self.end.as_deref()) {
412                Ok(Some(entry)) => {
413                    *idx += 1;
414                    self.last_key = Some(entry.0.clone());
415                    return Some(Ok(entry));
416                }
417                Ok(None) => return None,
418                Err(e) => return Some(Err(e)),
419            }
420        }
421
422        // Not at a leaf - descend to the correct leaf
423        self.descend_to_leaf()
424    }
425
426    /// Descend from current internal node to the leftmost leaf.
427    ///
428    /// Follows child pointers until reaching a leaf node, then returns
429    /// the first entry from that leaf.
430    fn descend_to_leaf(&mut self) -> Option<RangeItem> {
431        loop {
432            let (node, idx) = self.stack.last()?;
433
434            if node.leaf {
435                // We're at a leaf, return the current entry
436                if *idx >= node.len() {
437                    return self.advance_to_next_leaf();
438                }
439
440                match leaf_entry_before_end(node, *idx, self.end.as_deref()) {
441                    Ok(Some(entry)) => {
442                        if let Some((_, idx)) = self.stack.last_mut() {
443                            *idx += 1;
444                        }
445                        self.last_key = Some(entry.0.clone());
446                        return Some(Ok(entry));
447                    }
448                    Ok(None) => return None,
449                    Err(e) => return Some(Err(e)),
450                }
451            }
452
453            // Internal node - descend to child
454            if *idx >= node.len() {
455                // No more children, go back up
456                return self.advance_to_next_leaf();
457            }
458
459            match child_starts_at_or_after_end(self.end.as_deref(), node, *idx) {
460                Ok(true) => return None,
461                Ok(false) => {}
462                Err(e) => return Some(Err(e)),
463            }
464
465            match self.load_child_for_descent(node, *idx) {
466                Ok(child) => {
467                    self.stack.push((child, 0));
468                }
469                Err(e) => return Some(Err(e)),
470            }
471        }
472    }
473
474    /// Advance to the next leaf node when current leaf is exhausted.
475    ///
476    /// Pops nodes from the stack until finding a parent with more children,
477    /// then descends to the next child's leftmost leaf.
478    fn advance_to_next_leaf(&mut self) -> Option<RangeItem> {
479        loop {
480            // Pop the current node
481            self.stack.pop();
482
483            if self.stack.is_empty() {
484                return None;
485            }
486
487            // Increment parent's index
488            if let Some((parent, parent_idx)) = self.stack.last_mut() {
489                *parent_idx += 1;
490
491                // Check if parent has more children
492                if *parent_idx < parent.len() {
493                    match child_starts_at_or_after_end(self.end.as_deref(), parent, *parent_idx) {
494                        Ok(true) => return None,
495                        Ok(false) => {}
496                        Err(e) => return Some(Err(e)),
497                    }
498                    // Descend to the next child
499                    return self.descend_to_leaf();
500                }
501                if parent.keys.len() != parent.vals.len() {
502                    return Some(Err(Error::InvalidNode));
503                }
504                // Otherwise, continue popping
505            }
506        }
507    }
508
509    fn load_child_for_descent(&self, node: &Node, idx: usize) -> Result<Arc<Node>, Error> {
510        let child_cid = child_cid_at(node, idx)?;
511
512        if !self.prolly.store().prefers_batch_reads() {
513            return self.prolly.load_arc(&child_cid);
514        }
515
516        if let Some(child) = self.prolly.cached_node_arc(&child_cid) {
517            return Ok(child);
518        }
519
520        let max_child_idx = node
521            .len()
522            .min(idx.saturating_add(RANGE_CHILD_PREFETCH_PARALLELISM));
523        let mut child_cids = Vec::with_capacity(max_child_idx.saturating_sub(idx));
524        child_cids.push(child_cid);
525
526        for child_idx in idx + 1..max_child_idx {
527            match child_starts_at_or_after_end(self.end.as_deref(), node, child_idx) {
528                Ok(true) => break,
529                Ok(false) => {}
530                Err(_) => break,
531            }
532
533            match child_cid_at(node, child_idx) {
534                Ok(cid) => child_cids.push(cid),
535                Err(_) => break,
536            }
537        }
538
539        if child_cids.len() == 1 {
540            return self.prolly.load_arc(&child_cids[0]);
541        }
542
543        let children = self
544            .prolly
545            .load_many_ordered_with_parallelism(&child_cids, RANGE_CHILD_PREFETCH_PARALLELISM)?;
546        children.into_iter().next().ok_or(Error::InvalidNode)
547    }
548}
549
550/// Iterator implementation for RangeIter.
551///
552/// Yields `(key, value)` pairs in lexicographic order, handling cursor advancement
553/// across node boundaries and checking end bounds for each yielded entry.
554impl<'a, S: Store> Iterator for RangeIter<'a, S> {
555    type Item = Result<(Vec<u8>, Vec<u8>), Error>;
556
557    fn next(&mut self) -> Option<Self::Item> {
558        // First call: position at start key
559        if !self.started {
560            return self.position_at_start();
561        }
562
563        loop {
564            let (node, idx) = self.stack.last_mut()?;
565
566            if !node.leaf && node.keys.len() != node.vals.len() {
567                return Some(Err(Error::InvalidNode));
568            }
569
570            // If we've exhausted this node, advance to next
571            if *idx >= node.len() {
572                return self.advance_to_next_leaf();
573            }
574
575            // If we're at a leaf, yield the current entry
576            if node.leaf {
577                match leaf_entry_before_end(node, *idx, self.end.as_deref()) {
578                    Ok(Some(entry)) => {
579                        *idx += 1;
580                        self.last_key = Some(entry.0.clone());
581                        return Some(Ok(entry));
582                    }
583                    Ok(None) => return None,
584                    Err(e) => return Some(Err(e)),
585                }
586            }
587
588            // Internal node - descend to child
589            match child_starts_at_or_after_end(self.end.as_deref(), node, *idx) {
590                Ok(true) => return None,
591                Ok(false) => {}
592                Err(e) => return Some(Err(e)),
593            }
594
595            let child = {
596                let (node, idx) = self.stack.last()?;
597                self.load_child_for_descent(node, *idx)
598            };
599
600            match child {
601                Ok(child) => {
602                    self.stack.push((child, 0));
603                }
604                Err(e) => return Some(Err(e)),
605            }
606        }
607    }
608}
609
610/// Async iterator over key-value pairs in a range.
611///
612/// Created by [`AsyncProlly::range`](crate::AsyncProlly::range). Call
613/// [`AsyncRangeIter::next`] to lazily read one item at a time, or
614/// [`AsyncRangeIter::into_stream`] to adapt it to a `futures_util::Stream`.
615#[cfg(feature = "async-store")]
616pub struct AsyncRangeIter<'a, S: AsyncStore> {
617    prolly: &'a AsyncProlly<S>,
618    stack: Vec<(Arc<Node>, usize)>,
619    end: Option<Vec<u8>>,
620    started: bool,
621    start_key: Vec<u8>,
622    skip_start_key: bool,
623    last_key: Option<Vec<u8>>,
624}
625
626#[cfg(feature = "async-store")]
627impl<'a, S> AsyncRangeIter<'a, S>
628where
629    S: AsyncStore,
630    S::Error: Send + Sync,
631{
632    pub(crate) fn new(
633        prolly: &'a AsyncProlly<S>,
634        stack: Vec<(Arc<Node>, usize)>,
635        start: &[u8],
636        end: Option<&[u8]>,
637    ) -> Self {
638        Self {
639            prolly,
640            stack,
641            end: end.map(|e| e.to_vec()),
642            started: false,
643            start_key: start.to_vec(),
644            skip_start_key: false,
645            last_key: None,
646        }
647    }
648
649    pub(crate) fn new_after(
650        prolly: &'a AsyncProlly<S>,
651        stack: Vec<(Arc<Node>, usize)>,
652        after_key: &[u8],
653        end: Option<&[u8]>,
654    ) -> Self {
655        Self {
656            prolly,
657            stack,
658            end: end.map(|e| e.to_vec()),
659            started: false,
660            start_key: after_key.to_vec(),
661            skip_start_key: true,
662            last_key: None,
663        }
664    }
665
666    /// Return the next key-value pair in lexicographic order.
667    pub async fn next(&mut self) -> Option<RangeItem> {
668        self.position_at_start();
669
670        loop {
671            let (node, idx) = self.stack.last_mut()?;
672
673            if !node.leaf && node.keys.len() != node.vals.len() {
674                return Some(Err(Error::InvalidNode));
675            }
676
677            if *idx >= node.len() {
678                match self.advance_to_next_sibling() {
679                    Ok(true) => continue,
680                    Ok(false) => return None,
681                    Err(e) => return Some(Err(e)),
682                }
683            }
684
685            if node.leaf {
686                match leaf_entry_before_end(node, *idx, self.end.as_deref()) {
687                    Ok(Some(entry)) => {
688                        *idx += 1;
689                        self.last_key = Some(entry.0.clone());
690                        return Some(Ok(entry));
691                    }
692                    Ok(None) => return None,
693                    Err(e) => return Some(Err(e)),
694                }
695            }
696
697            match child_starts_at_or_after_end(self.end.as_deref(), node, *idx) {
698                Ok(true) => return None,
699                Ok(false) => {}
700                Err(e) => return Some(Err(e)),
701            }
702
703            let child = {
704                let (node, idx) = self.stack.last()?;
705                self.load_child_for_descent(node, *idx).await
706            };
707
708            match child {
709                Ok(child) => self.stack.push((child, 0)),
710                Err(e) => return Some(Err(e)),
711            }
712        }
713    }
714
715    /// Collect all remaining range entries into memory.
716    pub async fn collect(mut self) -> Result<Vec<LeafEntry>, Error> {
717        let mut entries = Vec::new();
718        while let Some(item) = self.next().await {
719            entries.push(item?);
720        }
721        Ok(entries)
722    }
723
724    /// Return a resumable cursor for the last key yielded by this iterator.
725    ///
726    /// If the iterator has not yielded an item yet, this returns
727    /// [`RangeCursor::start`].
728    pub fn resume_cursor(&self) -> RangeCursor {
729        self.last_key
730            .clone()
731            .map(RangeCursor::after_key)
732            .unwrap_or_else(RangeCursor::start)
733    }
734
735    /// Convert this iterator into a `futures_util::Stream`.
736    pub fn into_stream(self) -> impl Stream<Item = RangeItem> + 'a {
737        stream::unfold(self, |mut iter| async move {
738            iter.next().await.map(|item| (item, iter))
739        })
740    }
741
742    fn position_at_start(&mut self) {
743        if self.started {
744            return;
745        }
746
747        self.started = true;
748        let Some((node, idx)) = self.stack.last_mut() else {
749            return;
750        };
751
752        if node.leaf {
753            *idx = match node.search(&self.start_key) {
754                Ok(i) if self.skip_start_key => i.saturating_add(1),
755                Ok(i) | Err(i) => i,
756            };
757        }
758    }
759
760    fn advance_to_next_sibling(&mut self) -> Result<bool, Error> {
761        loop {
762            self.stack.pop();
763            let Some((parent, parent_idx)) = self.stack.last_mut() else {
764                return Ok(false);
765            };
766
767            *parent_idx += 1;
768
769            if *parent_idx < parent.len() {
770                if child_starts_at_or_after_end(self.end.as_deref(), parent, *parent_idx)? {
771                    return Ok(false);
772                }
773                return Ok(true);
774            }
775
776            if parent.keys.len() != parent.vals.len() {
777                return Err(Error::InvalidNode);
778            }
779        }
780    }
781
782    async fn load_child_for_descent(&self, node: &Node, idx: usize) -> Result<Arc<Node>, Error> {
783        let child_cid = child_cid_at(node, idx)?;
784
785        if !self.prolly.store().prefers_batch_reads() {
786            return self.prolly.load_arc(&child_cid).await;
787        }
788
789        if let Some(child) = self.prolly.cached_node_arc(&child_cid) {
790            return Ok(child);
791        }
792
793        let max_child_idx = node
794            .len()
795            .min(idx.saturating_add(RANGE_CHILD_PREFETCH_PARALLELISM));
796        let mut child_cids = Vec::with_capacity(max_child_idx.saturating_sub(idx));
797        child_cids.push(child_cid);
798
799        for child_idx in idx + 1..max_child_idx {
800            if child_starts_at_or_after_end(self.end.as_deref(), node, child_idx).unwrap_or(true) {
801                break;
802            }
803
804            match child_cid_at(node, child_idx) {
805                Ok(cid) => child_cids.push(cid),
806                Err(_) => break,
807            }
808        }
809
810        if child_cids.len() == 1 {
811            return self.prolly.load_arc(&child_cids[0]).await;
812        }
813
814        let children = self.prolly.load_child_frontier_ordered(&child_cids).await?;
815        children.into_iter().next().ok_or(Error::InvalidNode)
816    }
817}
818
819fn leaf_entry_before_end(node: &Node, idx: usize, end: Option<&[u8]>) -> OptionalLeafEntry {
820    let key = node.keys.get(idx).ok_or(Error::InvalidNode)?;
821    if let Some(end) = end {
822        if key.as_slice() >= end {
823            return Ok(None);
824        }
825    }
826
827    let val = node.vals.get(idx).ok_or(Error::InvalidNode)?;
828    Ok(Some((key.clone(), val.clone())))
829}
830
831fn child_starts_at_or_after_end(
832    end: Option<&[u8]>,
833    node: &Node,
834    child_index: usize,
835) -> Result<bool, Error> {
836    let Some(end) = end else {
837        return Ok(false);
838    };
839
840    let first_key = node.keys.get(child_index).ok_or(Error::InvalidNode)?;
841    Ok(first_key.as_slice() >= end)
842}
843
844fn child_cid_at(node: &Node, idx: usize) -> Result<Cid, Error> {
845    let child = node.vals.get(idx).ok_or(Error::InvalidNode)?;
846    Ok(Cid(child
847        .as_slice()
848        .try_into()
849        .map_err(|_| Error::InvalidNode)?))
850}