1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use reth_db_api::table::Decompress;

/// Generic Mask helper struct for selecting specific column values to read and decompress.
///
/// #### Explanation:
///
/// A `NippyJar` static file row can contain multiple column values. To specify the column values
/// to be read, a mask is utilized.
///
/// For example, a static file with three columns, if the first and last columns are queried, the
/// mask `0b101` would be passed. To select only the second column, the mask `0b010` would be used.
///
/// Since each static file has its own column distribution, different wrapper types are necessary.
/// For instance, `B256` might be the third column in the `Header` segment, while being the second
/// column in another segment. Hence, `Mask<B256>` would only be applicable to one of these
/// scenarios.
///
/// Alongside, the column selector traits (eg. [`ColumnSelectorOne`]) this provides a structured way
/// to tie the types to be decoded to the mask necessary to query them.
#[derive(Debug)]
pub struct Mask<FIRST, SECOND = (), THIRD = ()>(std::marker::PhantomData<(FIRST, SECOND, THIRD)>);

macro_rules! add_segments {
    ($($segment:tt),+) => {
        paste::paste! {
            $(
                #[doc = concat!("Mask for ", stringify!($segment), " static file segment. See [`Mask`] for more.")]
                #[derive(Debug)]
                // TODO: remove next attribute when nightly is fixed (ie. does
                // not return wrong warnings for never constructed structs).
                #[allow(dead_code)]
                pub struct [<$segment Mask>]<FIRST, SECOND = (), THIRD = ()>(Mask<FIRST, SECOND, THIRD>);
            )+
        }
    };
}
add_segments!(Header, Receipt, Transaction);

///  Trait for specifying a mask to select one column value.
pub trait ColumnSelectorOne {
    /// First desired column value
    type FIRST: Decompress;
    /// Mask to obtain desired values, should correspond to the order of columns in a `static_file`.
    const MASK: usize;
}

///  Trait for specifying a mask to select two column values.
pub trait ColumnSelectorTwo {
    /// First desired column value
    type FIRST: Decompress;
    /// Second desired column value
    type SECOND: Decompress;
    /// Mask to obtain desired values, should correspond to the order of columns in a `static_file`.
    const MASK: usize;
}

///  Trait for specifying a mask to select three column values.
pub trait ColumnSelectorThree {
    /// First desired column value
    type FIRST: Decompress;
    /// Second desired column value
    type SECOND: Decompress;
    /// Third desired column value
    type THIRD: Decompress;
    /// Mask to obtain desired values, should correspond to the order of columns in a `static_file`.
    const MASK: usize;
}

#[macro_export]
/// Add mask to select `N` column values from a specific static file segment row.
macro_rules! add_static_file_mask {
    ($mask_struct:tt, $type1:ty, $mask:expr) => {
        impl ColumnSelectorOne for $mask_struct<$type1> {
            type FIRST = $type1;
            const MASK: usize = $mask;
        }
    };
    ($mask_struct:tt, $type1:ty, $type2:ty, $mask:expr) => {
        impl ColumnSelectorTwo for $mask_struct<$type1, $type2> {
            type FIRST = $type1;
            type SECOND = $type2;
            const MASK: usize = $mask;
        }
    };
    ($mask_struct:tt, $type1:ty, $type2:ty, $type3:ty, $mask:expr) => {
        impl ColumnSelectorThree for $mask_struct<$type1, $type2, $type3> {
            type FIRST = $type1;
            type SECOND = $type2;
            type THIRD = $type3;
            const MASK: usize = $mask;
        }
    };
}