reth_trie_sparse_parallel/
lower.rs

1use crate::SparseSubtrie;
2use reth_trie_common::Nibbles;
3
4/// Tracks the state of the lower subtries.
5///
6/// When a [`crate::ParallelSparseTrie`] is initialized/cleared then its `LowerSparseSubtrie`s are
7/// all blinded, meaning they have no nodes. A blinded `LowerSparseSubtrie` may hold onto a cleared
8/// [`SparseSubtrie`] in order to reuse allocations.
9#[derive(Clone, Debug, Eq, PartialEq)]
10pub(crate) enum LowerSparseSubtrie {
11    Blind(Option<Box<SparseSubtrie>>),
12    Revealed(Box<SparseSubtrie>),
13}
14
15impl Default for LowerSparseSubtrie {
16    /// Creates a new blinded subtrie with no allocated storage.
17    fn default() -> Self {
18        Self::Blind(None)
19    }
20}
21
22impl LowerSparseSubtrie {
23    /// Returns a reference to the underlying [`SparseSubtrie`] if this subtrie is revealed.
24    ///
25    /// Returns `None` if the subtrie is blinded (has no nodes).
26    pub(crate) fn as_revealed_ref(&self) -> Option<&SparseSubtrie> {
27        match self {
28            Self::Blind(_) => None,
29            Self::Revealed(subtrie) => Some(subtrie.as_ref()),
30        }
31    }
32
33    /// Returns a mutable reference to the underlying [`SparseSubtrie`] if this subtrie is revealed.
34    ///
35    /// Returns `None` if the subtrie is blinded (has no nodes).
36    pub(crate) fn as_revealed_mut(&mut self) -> Option<&mut SparseSubtrie> {
37        match self {
38            Self::Blind(_) => None,
39            Self::Revealed(subtrie) => Some(subtrie.as_mut()),
40        }
41    }
42
43    /// Reveals the lower [`SparseSubtrie`], transitioning it from the Blinded to the Revealed
44    /// variant, preserving allocations if possible.
45    ///
46    /// The given path is the path of a node which will be set into the [`SparseSubtrie`]'s `nodes`
47    /// map immediately upon being revealed. If the subtrie is blinded, or if its current root path
48    /// is longer than this one, than this one becomes the new root path of the subtrie.
49    pub(crate) fn reveal(&mut self, path: &Nibbles) {
50        match self {
51            Self::Blind(allocated) => {
52                debug_assert!(allocated.as_ref().is_none_or(|subtrie| subtrie.is_empty()));
53                *self = if let Some(mut subtrie) = allocated.take() {
54                    subtrie.path = *path;
55                    Self::Revealed(subtrie)
56                } else {
57                    Self::Revealed(Box::new(SparseSubtrie::new(*path)))
58                }
59            }
60            Self::Revealed(subtrie) => {
61                if path.len() < subtrie.path.len() {
62                    subtrie.path = *path;
63                }
64            }
65        };
66    }
67
68    /// Clears the subtrie and transitions it to the blinded state, preserving a cleared
69    /// [`SparseSubtrie`] if possible.
70    pub(crate) fn clear(&mut self) {
71        *self = match core::mem::take(self) {
72            Self::Blind(allocated) => {
73                debug_assert!(allocated.as_ref().is_none_or(|subtrie| subtrie.is_empty()));
74                Self::Blind(allocated)
75            }
76            Self::Revealed(mut subtrie) => {
77                subtrie.clear();
78                Self::Blind(Some(subtrie))
79            }
80        }
81    }
82
83    /// Takes ownership of the underlying [`SparseSubtrie`] if revealed, putting this
84    /// `LowerSparseSubtrie` will be put into the blinded state.
85    ///
86    /// Otherwise returns None.
87    pub(crate) fn take_revealed(&mut self) -> Option<Box<SparseSubtrie>> {
88        self.take_revealed_if(|_| true)
89    }
90
91    /// Takes ownership of the underlying [`SparseSubtrie`] if revealed and the predicate returns
92    /// true.
93    ///
94    /// If the subtrie is revealed, and the predicate function returns `true` when called with it,
95    /// then this method will take ownership of the subtrie and transition this `LowerSparseSubtrie`
96    /// to the blinded state. Otherwise, returns `None`.
97    pub(crate) fn take_revealed_if<P>(&mut self, predicate: P) -> Option<Box<SparseSubtrie>>
98    where
99        P: FnOnce(&SparseSubtrie) -> bool,
100    {
101        match self {
102            Self::Revealed(subtrie) if predicate(subtrie) => {
103                let Self::Revealed(subtrie) = core::mem::take(self) else { unreachable!() };
104                Some(subtrie)
105            }
106            Self::Revealed(_) | Self::Blind(_) => None,
107        }
108    }
109}