reth_db/static_file/
cursor.rs

1use super::mask::{ColumnSelectorOne, ColumnSelectorThree, ColumnSelectorTwo};
2use alloy_primitives::B256;
3use derive_more::{Deref, DerefMut};
4use reth_db_api::table::Decompress;
5use reth_nippy_jar::{DataReader, NippyJar, NippyJarCursor};
6use reth_static_file_types::SegmentHeader;
7use reth_storage_errors::provider::{ProviderError, ProviderResult};
8use std::sync::Arc;
9
10/// Cursor of a static file segment.
11#[derive(Debug, Deref, DerefMut)]
12pub struct StaticFileCursor<'a>(NippyJarCursor<'a, SegmentHeader>);
13
14/// Type alias for column results with optional values.
15type ColumnResult<T> = ProviderResult<Option<T>>;
16
17impl<'a> StaticFileCursor<'a> {
18    /// Returns a new [`StaticFileCursor`].
19    pub fn new(jar: &'a NippyJar<SegmentHeader>, reader: Arc<DataReader>) -> ProviderResult<Self> {
20        Ok(Self(NippyJarCursor::with_reader(jar, reader).map_err(ProviderError::other)?))
21    }
22
23    /// Returns the current `BlockNumber` or `TxNumber` of the cursor depending on the kind of
24    /// static file segment.
25    pub fn number(&self) -> Option<u64> {
26        self.jar().user_header().start().map(|start| self.row_index() + start)
27    }
28
29    /// Gets a row of values.
30    pub fn get(
31        &mut self,
32        key_or_num: KeyOrNumber<'_>,
33        mask: usize,
34    ) -> ProviderResult<Option<Vec<&'_ [u8]>>> {
35        if self.jar().rows() == 0 {
36            return Ok(None)
37        }
38
39        let row = match key_or_num {
40            KeyOrNumber::Key(_) => unimplemented!(),
41            KeyOrNumber::Number(n) => match self.jar().user_header().start() {
42                Some(offset) => {
43                    if offset > n {
44                        return Ok(None)
45                    }
46                    self.row_by_number_with_cols((n - offset) as usize, mask)
47                }
48                None => Ok(None),
49            },
50        }
51        .map_or(None, |v| v);
52
53        Ok(row)
54    }
55
56    /// Gets one column value from a row.
57    pub fn get_one<M: ColumnSelectorOne>(
58        &mut self,
59        key_or_num: KeyOrNumber<'_>,
60    ) -> ColumnResult<M::FIRST> {
61        let row = self.get(key_or_num, M::MASK)?;
62
63        match row {
64            Some(row) => Ok(Some(M::FIRST::decompress(row[0])?)),
65            None => Ok(None),
66        }
67    }
68
69    /// Gets two column values from a row.
70    pub fn get_two<M: ColumnSelectorTwo>(
71        &mut self,
72        key_or_num: KeyOrNumber<'_>,
73    ) -> ColumnResult<(M::FIRST, M::SECOND)> {
74        let row = self.get(key_or_num, M::MASK)?;
75
76        match row {
77            Some(row) => Ok(Some((M::FIRST::decompress(row[0])?, M::SECOND::decompress(row[1])?))),
78            None => Ok(None),
79        }
80    }
81
82    /// Gets three column values from a row.
83    pub fn get_three<M: ColumnSelectorThree>(
84        &mut self,
85        key_or_num: KeyOrNumber<'_>,
86    ) -> ColumnResult<(M::FIRST, M::SECOND, M::THIRD)> {
87        let row = self.get(key_or_num, M::MASK)?;
88
89        match row {
90            Some(row) => Ok(Some((
91                M::FIRST::decompress(row[0])?,
92                M::SECOND::decompress(row[1])?,
93                M::THIRD::decompress(row[2])?,
94            ))),
95            None => Ok(None),
96        }
97    }
98}
99
100/// Either a key _or_ a block/tx number
101#[derive(Debug)]
102pub enum KeyOrNumber<'a> {
103    /// A slice used as a key. Usually a block/tx hash
104    Key(&'a [u8]),
105    /// A block/tx number
106    Number(u64),
107}
108
109impl<'a> From<&'a B256> for KeyOrNumber<'a> {
110    fn from(value: &'a B256) -> Self {
111        KeyOrNumber::Key(value.as_slice())
112    }
113}
114
115impl From<u64> for KeyOrNumber<'_> {
116    fn from(value: u64) -> Self {
117        KeyOrNumber::Number(value)
118    }
119}