Skip to main content

reth_db_api/
cursor.rs

1use std::{
2    fmt,
3    ops::{Bound, RangeBounds},
4};
5
6use crate::{
7    common::{IterPairResult, PairResult, ValueOnlyResult},
8    table::{DupSort, Table, TableRow},
9    DatabaseError,
10};
11
12/// A read-only cursor over table `T`.
13pub trait DbCursorRO<T: Table> {
14    /// Positions the cursor at the first entry in the table, returning it.
15    fn first(&mut self) -> PairResult<T>;
16
17    /// Seeks to the KV pair exactly at `key`.
18    fn seek_exact(&mut self, key: T::Key) -> PairResult<T>;
19
20    /// Seeks to the KV pair whose key is greater than or equal to `key`.
21    fn seek(&mut self, key: T::Key) -> PairResult<T>;
22
23    /// Position the cursor at the next KV pair, returning it.
24    fn next(&mut self) -> PairResult<T>;
25
26    /// Position the cursor at the previous KV pair, returning it.
27    fn prev(&mut self) -> PairResult<T>;
28
29    /// Positions the cursor at the last entry in the table, returning it.
30    fn last(&mut self) -> PairResult<T>;
31
32    /// Get the KV pair at the cursor's current position.
33    fn current(&mut self) -> PairResult<T>;
34
35    /// Get an iterator that walks through the table.
36    ///
37    /// If `start_key` is `None`, then the walker will start from the first entry of the table,
38    /// otherwise it starts at the entry greater than or equal to the provided key.
39    fn walk(&mut self, start_key: Option<T::Key>) -> Result<Walker<'_, T, Self>, DatabaseError>
40    where
41        Self: Sized;
42
43    /// Get an iterator that walks over a range of keys in the table.
44    fn walk_range(
45        &mut self,
46        range: impl RangeBounds<T::Key>,
47    ) -> Result<RangeWalker<'_, T, Self>, DatabaseError>
48    where
49        Self: Sized;
50
51    /// Get an iterator that walks through the table in reverse order.
52    ///
53    /// If `start_key` is `None`, then the walker will start from the last entry of the table,
54    /// otherwise it starts at the entry greater than or equal to the provided key.
55    fn walk_back(
56        &mut self,
57        start_key: Option<T::Key>,
58    ) -> Result<ReverseWalker<'_, T, Self>, DatabaseError>
59    where
60        Self: Sized;
61}
62
63/// A read-only cursor over the dup table `T`.
64pub trait DbDupCursorRO<T: DupSort> {
65    /// Positions the cursor at the prev KV pair of the table, returning it.
66    fn prev_dup(&mut self) -> PairResult<T>;
67
68    /// Positions the cursor at the next KV pair of the table, returning it.
69    fn next_dup(&mut self) -> PairResult<T>;
70
71    /// Positions the cursor at the last duplicate value of the current key.
72    fn last_dup(&mut self) -> ValueOnlyResult<T>;
73
74    /// Positions the cursor at the next KV pair of the table, skipping duplicates.
75    fn next_no_dup(&mut self) -> PairResult<T>;
76
77    /// Positions the cursor at the next duplicate value of the current key.
78    fn next_dup_val(&mut self) -> ValueOnlyResult<T>;
79
80    /// Positions the cursor at the entry greater than or equal to the provided key/subkey pair.
81    ///
82    /// # Note
83    ///
84    /// The position of the cursor might not correspond to the key/subkey pair if the entry does not
85    /// exist.
86    fn seek_by_key_subkey(&mut self, key: T::Key, subkey: T::SubKey) -> ValueOnlyResult<T>;
87
88    /// Get an iterator that walks through the dup table.
89    ///
90    /// The cursor will start at different points in the table depending on the values of `key` and
91    /// `subkey`:
92    ///
93    /// | `key`  | `subkey` | **Equivalent starting position**        |
94    /// |--------|----------|-----------------------------------------|
95    /// | `None` | `None`   | [`DbCursorRO::first()`]                 |
96    /// | `Some` | `None`   | [`DbCursorRO::seek_exact()`]            |
97    /// | `None` | `Some`   | [`DbDupCursorRO::seek_by_key_subkey()`] |
98    /// | `Some` | `Some`   | [`DbDupCursorRO::seek_by_key_subkey()`] |
99    fn walk_dup(
100        &mut self,
101        key: Option<T::Key>,
102        subkey: Option<T::SubKey>,
103    ) -> Result<DupWalker<'_, T, Self>, DatabaseError>
104    where
105        Self: Sized;
106}
107
108/// Read write cursor over table.
109pub trait DbCursorRW<T: Table> {
110    /// Database operation that will update an existing row if a specified value already
111    /// exists in a table, and insert a new row if the specified value doesn't already exist
112    fn upsert(&mut self, key: T::Key, value: &T::Value) -> Result<(), DatabaseError>;
113
114    /// Database operation that will insert a row at a given key. If the key is already
115    /// present, the operation will result in an error.
116    fn insert(&mut self, key: T::Key, value: &T::Value) -> Result<(), DatabaseError>;
117
118    /// Append value to next cursor item.
119    ///
120    /// This is efficient for pre-sorted data. If the data is not pre-sorted, use
121    /// [`DbCursorRW::insert`].
122    fn append(&mut self, key: T::Key, value: &T::Value) -> Result<(), DatabaseError>;
123
124    /// Delete current value that cursor points to
125    fn delete_current(&mut self) -> Result<(), DatabaseError>;
126}
127
128/// Read Write Cursor over `DupSort` table.
129pub trait DbDupCursorRW<T: DupSort> {
130    /// Delete all duplicate entries for current key.
131    fn delete_current_duplicates(&mut self) -> Result<(), DatabaseError>;
132
133    /// Append duplicate value.
134    ///
135    /// This is efficient for pre-sorted data. If the data is not pre-sorted, use `insert`.
136    fn append_dup(&mut self, key: T::Key, value: T::Value) -> Result<(), DatabaseError>;
137}
138
139/// Provides an iterator to `Cursor` when handling `Table`.
140pub struct Walker<'cursor, T: Table, CURSOR: DbCursorRO<T>> {
141    /// Cursor to be used to walk through the table.
142    cursor: &'cursor mut CURSOR,
143    /// `(key, value)` where to start the walk.
144    start: IterPairResult<T>,
145}
146
147impl<T, CURSOR> fmt::Debug for Walker<'_, T, CURSOR>
148where
149    T: Table,
150    CURSOR: DbCursorRO<T> + fmt::Debug,
151{
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        f.debug_struct("Walker").field("cursor", &self.cursor).field("start", &self.start).finish()
154    }
155}
156
157impl<T: Table, CURSOR: DbCursorRO<T>> Iterator for Walker<'_, T, CURSOR> {
158    type Item = Result<TableRow<T>, DatabaseError>;
159    fn next(&mut self) -> Option<Self::Item> {
160        self.start.take().or_else(|| self.cursor.next().transpose())
161    }
162}
163
164impl<'cursor, T: Table, CURSOR: DbCursorRO<T>> Walker<'cursor, T, CURSOR> {
165    /// construct Walker
166    pub const fn new(cursor: &'cursor mut CURSOR, start: IterPairResult<T>) -> Self {
167        Self { cursor, start }
168    }
169
170    /// convert current [`Walker`] to [`ReverseWalker`] which iterates reversely
171    pub fn rev(self) -> ReverseWalker<'cursor, T, CURSOR> {
172        let start = self.cursor.current().transpose();
173        ReverseWalker::new(self.cursor, start)
174    }
175}
176
177impl<T: Table, CURSOR: DbCursorRW<T> + DbCursorRO<T>> Walker<'_, T, CURSOR> {
178    /// Delete current item that walker points to.
179    pub fn delete_current(&mut self) -> Result<(), DatabaseError> {
180        self.start.take();
181        self.cursor.delete_current()
182    }
183}
184
185/// Provides a reverse iterator to `Cursor` when handling `Table`.
186/// Also check [`Walker`]
187pub struct ReverseWalker<'cursor, T: Table, CURSOR: DbCursorRO<T>> {
188    /// Cursor to be used to walk through the table.
189    cursor: &'cursor mut CURSOR,
190    /// `(key, value)` where to start the walk.
191    start: IterPairResult<T>,
192}
193
194impl<T, CURSOR> fmt::Debug for ReverseWalker<'_, T, CURSOR>
195where
196    T: Table,
197    CURSOR: DbCursorRO<T> + fmt::Debug,
198{
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        f.debug_struct("ReverseWalker")
201            .field("cursor", &self.cursor)
202            .field("start", &self.start)
203            .finish()
204    }
205}
206
207impl<'cursor, T: Table, CURSOR: DbCursorRO<T>> ReverseWalker<'cursor, T, CURSOR> {
208    /// construct `ReverseWalker`
209    pub const fn new(cursor: &'cursor mut CURSOR, start: IterPairResult<T>) -> Self {
210        Self { cursor, start }
211    }
212
213    /// convert current [`ReverseWalker`] to [`Walker`] which iterate forwardly
214    pub fn forward(self) -> Walker<'cursor, T, CURSOR> {
215        let start = self.cursor.current().transpose();
216        Walker::new(self.cursor, start)
217    }
218}
219
220impl<T: Table, CURSOR: DbCursorRW<T> + DbCursorRO<T>> ReverseWalker<'_, T, CURSOR> {
221    /// Delete current item that walker points to.
222    pub fn delete_current(&mut self) -> Result<(), DatabaseError> {
223        self.start.take();
224        self.cursor.delete_current()
225    }
226}
227
228impl<T: Table, CURSOR: DbCursorRO<T>> Iterator for ReverseWalker<'_, T, CURSOR> {
229    type Item = Result<TableRow<T>, DatabaseError>;
230
231    fn next(&mut self) -> Option<Self::Item> {
232        let start = self.start.take();
233        if start.is_some() {
234            return start
235        }
236
237        self.cursor.prev().transpose()
238    }
239}
240
241/// Provides a range iterator to `Cursor` when handling `Table`.
242/// Also check [`Walker`]
243pub struct RangeWalker<'cursor, T: Table, CURSOR: DbCursorRO<T>> {
244    /// Cursor to be used to walk through the table.
245    cursor: &'cursor mut CURSOR,
246    /// `(key, value)` where to start the walk.
247    start: IterPairResult<T>,
248    /// `key` where to stop the walk.
249    end_key: Bound<T::Key>,
250    /// flag whether is ended
251    is_done: bool,
252}
253
254impl<T, CURSOR> fmt::Debug for RangeWalker<'_, T, CURSOR>
255where
256    T: Table,
257    CURSOR: DbCursorRO<T> + fmt::Debug,
258{
259    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260        f.debug_struct("RangeWalker")
261            .field("cursor", &self.cursor)
262            .field("start", &self.start)
263            .field("end_key", &self.end_key)
264            .field("is_done", &self.is_done)
265            .finish()
266    }
267}
268
269impl<T: Table, CURSOR: DbCursorRO<T>> Iterator for RangeWalker<'_, T, CURSOR> {
270    type Item = Result<TableRow<T>, DatabaseError>;
271
272    fn next(&mut self) -> Option<Self::Item> {
273        if self.is_done {
274            return None
275        }
276
277        let next_item = self.start.take().or_else(|| self.cursor.next().transpose());
278
279        match next_item {
280            Some(Ok((key, value))) => match &self.end_key {
281                Bound::Included(end_key) if &key <= end_key => Some(Ok((key, value))),
282                Bound::Excluded(end_key) if &key < end_key => Some(Ok((key, value))),
283                Bound::Unbounded => Some(Ok((key, value))),
284                _ => {
285                    self.is_done = true;
286                    None
287                }
288            },
289            Some(res @ Err(_)) => Some(res),
290            None => {
291                self.is_done = matches!(self.end_key, Bound::Unbounded);
292                None
293            }
294        }
295    }
296}
297
298impl<'cursor, T: Table, CURSOR: DbCursorRO<T>> RangeWalker<'cursor, T, CURSOR> {
299    /// construct `RangeWalker`
300    pub fn new(
301        cursor: &'cursor mut CURSOR,
302        start: IterPairResult<T>,
303        end_key: Bound<T::Key>,
304    ) -> Self {
305        // mark done if range is empty.
306        let is_done = match start {
307            Some(Ok((ref start_key, _))) => match &end_key {
308                Bound::Included(end_key) if start_key > end_key => true,
309                Bound::Excluded(end_key) if start_key >= end_key => true,
310                _ => false,
311            },
312            None => true,
313            _ => false,
314        };
315        Self { cursor, start, end_key, is_done }
316    }
317}
318
319impl<T: Table, CURSOR: DbCursorRW<T> + DbCursorRO<T>> RangeWalker<'_, T, CURSOR> {
320    /// Delete current item that walker points to.
321    pub fn delete_current(&mut self) -> Result<(), DatabaseError> {
322        self.start.take();
323        self.cursor.delete_current()
324    }
325}
326
327impl<T: DupSort, CURSOR: DbDupCursorRW<T> + DbCursorRO<T>> RangeWalker<'_, T, CURSOR> {
328    /// Delete all duplicate entries for current key that walker points to.
329    pub fn delete_current_duplicates(&mut self) -> Result<(), DatabaseError> {
330        self.start.take();
331        self.cursor.delete_current_duplicates()
332    }
333}
334
335/// Provides an iterator to `Cursor` when handling a `DupSort` table.
336///
337/// Reason why we have two lifetimes is to distinguish between `'cursor` lifetime
338/// and inherited `'tx` lifetime. If there is only one, rust would short circle
339/// the Cursor lifetime and it wouldn't be possible to use Walker.
340pub struct DupWalker<'cursor, T: DupSort, CURSOR: DbDupCursorRO<T>> {
341    /// Cursor to be used to walk through the table.
342    pub cursor: &'cursor mut CURSOR,
343    /// Value where to start the walk.
344    pub start: IterPairResult<T>,
345}
346
347impl<T, CURSOR> fmt::Debug for DupWalker<'_, T, CURSOR>
348where
349    T: DupSort,
350    CURSOR: DbDupCursorRO<T> + fmt::Debug,
351{
352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        f.debug_struct("DupWalker")
354            .field("cursor", &self.cursor)
355            .field("start", &self.start)
356            .finish()
357    }
358}
359
360impl<T: DupSort, CURSOR: DbCursorRW<T> + DbDupCursorRO<T>> DupWalker<'_, T, CURSOR> {
361    /// Delete current item that walker points to.
362    pub fn delete_current(&mut self) -> Result<(), DatabaseError> {
363        self.start.take();
364        self.cursor.delete_current()
365    }
366}
367
368impl<T: DupSort, CURSOR: DbDupCursorRO<T>> Iterator for DupWalker<'_, T, CURSOR> {
369    type Item = Result<TableRow<T>, DatabaseError>;
370    fn next(&mut self) -> Option<Self::Item> {
371        let start = self.start.take();
372        if start.is_some() {
373            return start
374        }
375        self.cursor.next_dup().transpose()
376    }
377}