/__w/smoldot/smoldot/repo/lib/src/executor/storage_diff.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | //! "Diff" between a trie and the next. |
19 | | //! |
20 | | //! Imagine two `HashMap<Vec<u8>, Vec<u8>>`s representing the content of a trie. This data |
21 | | //! structure contains the difference from one to the other. |
22 | | //! |
23 | | //! This data structure can be used in a variety of circumstances, such as storing the storage |
24 | | //! differences between a block and its child or storing on-going changes while a runtime call is |
25 | | //! being performed. It can also be used to store an entire trie, by representing a diff where |
26 | | //! the base is an empty trie. |
27 | | //! |
28 | | //! # About keys hashing |
29 | | //! |
30 | | //! This data structure internally uses a hash map. This hash map assumes that storage keys are |
31 | | //! already uniformly distributed and doesn't perform any additional hashing. |
32 | | //! |
33 | | //! You should be aware that a malicious runtime could perform hash collision attacks that |
34 | | //! considerably slow down this data structure. |
35 | | //! |
36 | | |
37 | | // TODO: is this module properly located? |
38 | | |
39 | | // TODO: more docs |
40 | | |
41 | | use alloc::{collections::BTreeMap, vec::Vec}; |
42 | | use core::{borrow::Borrow, cmp, fmt, ops}; |
43 | | use hashbrown::HashMap; |
44 | | |
45 | | #[derive(Clone)] |
46 | | pub struct TrieDiff<T = ()> { |
47 | | /// Contains the same entries as [`TrieDiff::hashmap`], except that values are booleans |
48 | | /// indicating whether the value updates (`true`) or deletes (`false`) the underlying |
49 | | /// storage item. |
50 | | btree: BTreeMap<Vec<u8>, bool>, |
51 | | |
52 | | /// Actual diff. For each key, `Some` if the underlying storage item is updated by this diff, |
53 | | /// and `None` if it is deleted. |
54 | | /// |
55 | | /// A FNV hasher is used because the runtime is supposed to guarantee a uniform distribution |
56 | | /// of storage keys. |
57 | | hashmap: HashMap<Vec<u8>, (Option<Vec<u8>>, T), fnv::FnvBuildHasher>, |
58 | | } |
59 | | |
60 | | impl<T> TrieDiff<T> { |
61 | | /// Builds a new empty diff. |
62 | 33.3k | pub fn empty() -> Self { |
63 | 33.3k | Self { |
64 | 33.3k | btree: BTreeMap::default(), |
65 | 33.3k | // TODO: with_capacity? |
66 | 33.3k | hashmap: HashMap::with_capacity_and_hasher(0, Default::default()), |
67 | 33.3k | } |
68 | 33.3k | } _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyB6_ Line | Count | Source | 62 | 33.2k | pub fn empty() -> Self { | 63 | 33.2k | Self { | 64 | 33.2k | btree: BTreeMap::default(), | 65 | 33.2k | // TODO: with_capacity? | 66 | 33.2k | hashmap: HashMap::with_capacity_and_hasher(0, Default::default()), | 67 | 33.2k | } | 68 | 33.2k | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsDDUKWWCHAU_18smoldot_light_wasm _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyB6_ Line | Count | Source | 62 | 126 | pub fn empty() -> Self { | 63 | 126 | Self { | 64 | 126 | btree: BTreeMap::default(), | 65 | 126 | // TODO: with_capacity? | 66 | 126 | hashmap: HashMap::with_capacity_and_hasher(0, Default::default()), | 67 | 126 | } | 68 | 126 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsiLzmwikkc22_14json_rpc_basic _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsiUjFBJteJ7x_17smoldot_full_node Line | Count | Source | 62 | 1 | pub fn empty() -> Self { | 63 | 1 | Self { | 64 | 1 | btree: BTreeMap::default(), | 65 | 1 | // TODO: with_capacity? | 66 | 1 | hashmap: HashMap::with_capacity_and_hasher(0, Default::default()), | 67 | 1 | } | 68 | 1 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsibGXYHQB8Ea_25json_rpc_general_requests |
69 | | |
70 | | /// Removes all the entries within this diff. |
71 | 0 | pub fn clear(&mut self) { |
72 | 0 | self.hashmap.clear(); |
73 | 0 | self.btree.clear(); |
74 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5clearB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5clearB6_ |
75 | | |
76 | | /// Inserts the given key-value combination in the diff. |
77 | | /// |
78 | | /// Returns the value associated to this `key` that was previously in the diff, if any. |
79 | 405k | pub fn diff_insert( |
80 | 405k | &mut self, |
81 | 405k | key: impl Into<Vec<u8>>, |
82 | 405k | value: impl Into<Vec<u8>>, |
83 | 405k | user_data: T, |
84 | 405k | ) -> Option<(Option<Vec<u8>>, T)> { |
85 | 405k | let key = key.into(); |
86 | 405k | // Note that we clone the key here. This is considered as a tolerable overhead. |
87 | 405k | let previous = self |
88 | 405k | .hashmap |
89 | 405k | .insert(key.clone(), (Some(value.into()), user_data)); |
90 | 143k | match &previous { |
91 | | Some((Some(_), _)) => { |
92 | | // No need to update `btree`. |
93 | 69.1k | debug_assert_eq!(self.btree.get(&key), Some(&true)); |
94 | | } |
95 | 336k | None | Some((None, _)) => { |
96 | 336k | self.btree.insert(key, true); |
97 | 336k | } |
98 | | } |
99 | 405k | previous |
100 | 405k | } _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1g_EB7_ Line | Count | Source | 79 | 404k | pub fn diff_insert( | 80 | 404k | &mut self, | 81 | 404k | key: impl Into<Vec<u8>>, | 82 | 404k | value: impl Into<Vec<u8>>, | 83 | 404k | user_data: T, | 84 | 404k | ) -> Option<(Option<Vec<u8>>, T)> { | 85 | 404k | let key = key.into(); | 86 | 404k | // Note that we clone the key here. This is considered as a tolerable overhead. | 87 | 404k | let previous = self | 88 | 404k | .hashmap | 89 | 404k | .insert(key.clone(), (Some(value.into()), user_data)); | 90 | 143k | match &previous { | 91 | | Some((Some(_), _)) => { | 92 | | // No need to update `btree`. | 93 | 68.9k | debug_assert_eq!(self.btree.get(&key), Some(&true)); | 94 | | } | 95 | 335k | None | Some((None, _)) => { | 96 | 335k | self.btree.insert(key, true); | 97 | 335k | } | 98 | | } | 99 | 404k | previous | 100 | 404k | } |
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertRShB1g_EB7_ Line | Count | Source | 79 | 304 | pub fn diff_insert( | 80 | 304 | &mut self, | 81 | 304 | key: impl Into<Vec<u8>>, | 82 | 304 | value: impl Into<Vec<u8>>, | 83 | 304 | user_data: T, | 84 | 304 | ) -> Option<(Option<Vec<u8>>, T)> { | 85 | 304 | let key = key.into(); | 86 | 304 | // Note that we clone the key here. This is considered as a tolerable overhead. | 87 | 304 | let previous = self | 88 | 304 | .hashmap | 89 | 304 | .insert(key.clone(), (Some(value.into()), user_data)); | 90 | 173 | match &previous { | 91 | | Some((Some(_), _)) => { | 92 | | // No need to update `btree`. | 93 | 158 | debug_assert_eq!(self.btree.get(&key), Some(&true)); | 94 | | } | 95 | 146 | None | Some((None, _)) => { | 96 | 146 | self.btree.insert(key, true); | 97 | 146 | } | 98 | | } | 99 | 304 | previous | 100 | 304 | } |
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_EB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertRShB1h_EB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECscDgN54JpMGG_6author Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsibGXYHQB8Ea_25json_rpc_general_requests |
101 | | |
102 | | /// Inserts in the diff an entry at the given key that delete the value that is located in |
103 | | /// the base storage. |
104 | | /// |
105 | | /// Returns the value associated to this `key` that was previously in the diff, if any. |
106 | 85.9k | pub fn diff_insert_erase( |
107 | 85.9k | &mut self, |
108 | 85.9k | key: impl Into<Vec<u8>>, |
109 | 85.9k | user_data: T, |
110 | 85.9k | ) -> Option<(Option<Vec<u8>>, T)> { |
111 | 85.9k | let key = key.into(); |
112 | 85.9k | // Note that we clone the key here. This is considered as a tolerable overhead. |
113 | 85.9k | let previous = self.hashmap.insert(key.clone(), (None, user_data)); |
114 | 69.4k | match &previous { |
115 | | Some((None, _)) => { |
116 | | // No need to update `btree`. |
117 | 0 | debug_assert_eq!(self.btree.get(&key), Some(&false)); |
118 | | } |
119 | 85.9k | None | Some((Some(_), _)) => { |
120 | 85.9k | self.btree.insert(key, false); |
121 | 85.9k | } |
122 | | } |
123 | 85.9k | previous |
124 | 85.9k | } _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEEB7_ Line | Count | Source | 106 | 85.8k | pub fn diff_insert_erase( | 107 | 85.8k | &mut self, | 108 | 85.8k | key: impl Into<Vec<u8>>, | 109 | 85.8k | user_data: T, | 110 | 85.8k | ) -> Option<(Option<Vec<u8>>, T)> { | 111 | 85.8k | let key = key.into(); | 112 | 85.8k | // Note that we clone the key here. This is considered as a tolerable overhead. | 113 | 85.8k | let previous = self.hashmap.insert(key.clone(), (None, user_data)); | 114 | 69.4k | match &previous { | 115 | | Some((None, _)) => { | 116 | | // No need to update `btree`. | 117 | 0 | debug_assert_eq!(self.btree.get(&key), Some(&false)); | 118 | | } | 119 | 85.8k | None | Some((Some(_), _)) => { | 120 | 85.8k | self.btree.insert(key, false); | 121 | 85.8k | } | 122 | | } | 123 | 85.8k | previous | 124 | 85.8k | } |
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseRShEB7_ Line | Count | Source | 106 | 71 | pub fn diff_insert_erase( | 107 | 71 | &mut self, | 108 | 71 | key: impl Into<Vec<u8>>, | 109 | 71 | user_data: T, | 110 | 71 | ) -> Option<(Option<Vec<u8>>, T)> { | 111 | 71 | let key = key.into(); | 112 | 71 | // Note that we clone the key here. This is considered as a tolerable overhead. | 113 | 71 | let previous = self.hashmap.insert(key.clone(), (None, user_data)); | 114 | 52 | match &previous { | 115 | | Some((None, _)) => { | 116 | | // No need to update `btree`. | 117 | 0 | debug_assert_eq!(self.btree.get(&key), Some(&false)); | 118 | | } | 119 | 71 | None | Some((Some(_), _)) => { | 120 | 71 | self.btree.insert(key, false); | 121 | 71 | } | 122 | | } | 123 | 71 | previous | 124 | 71 | } |
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseRShEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECscDgN54JpMGG_6author Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsibGXYHQB8Ea_25json_rpc_general_requests |
125 | | |
126 | | /// Removes from the diff the entry corresponding to the given `key`. |
127 | | /// |
128 | | /// Returns the value associated to this `key` that was previously in the diff, if any. |
129 | 0 | pub fn diff_remove(&mut self, key: impl AsRef<[u8]>) -> Option<(Option<Vec<u8>>, T)> { |
130 | 0 | let previous = self.hashmap.remove(key.as_ref()); |
131 | 0 | if let Some(_previous) = &previous { |
132 | 0 | let _in_btree = self.btree.remove(key.as_ref()); |
133 | 0 | debug_assert_eq!(_in_btree, Some(_previous.0.is_some())); |
134 | 0 | } |
135 | 0 | previous |
136 | 0 | } Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB3_8TrieDiffpE11diff_removepEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB3_8TrieDiffpE11diff_removepEB7_ |
137 | | |
138 | | /// Returns the diff entry at the given key. |
139 | | /// |
140 | | /// Returns `None` if the diff doesn't have any entry for this key, and `Some((None, _))` if |
141 | | /// the diff has an entry that deletes the storage item. |
142 | 313k | pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> { |
143 | 313k | self.hashmap |
144 | 313k | .get(key) |
145 | 313k | .map(|(v, ud)| (v.as_ref().map(278k |v| &v[..]267k ), ud)278k ) _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0B8_ Line | Count | Source | 145 | 278k | .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud)) |
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CsibGXYHQB8Ea_25json_rpc_general_requests _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00Ba_ Line | Count | Source | 145 | 267k | .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud)) |
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00Ba_ Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CsibGXYHQB8Ea_25json_rpc_general_requests |
146 | 313k | } _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getB6_ Line | Count | Source | 142 | 313k | pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> { | 143 | 313k | self.hashmap | 144 | 313k | .get(key) | 145 | 313k | .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud)) | 146 | 313k | } |
_RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getB6_ Line | Count | Source | 142 | 84 | pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> { | 143 | 84 | self.hashmap | 144 | 84 | .get(key) | 145 | 84 | .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud)) | 146 | 84 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCsibGXYHQB8Ea_25json_rpc_general_requests |
147 | | |
148 | | /// Returns an iterator to all the entries in the diff. |
149 | | /// |
150 | | /// Each value is either `Some` if the diff overwrites this diff, or `None` if it erases the |
151 | | /// underlying value. |
152 | 0 | pub fn diff_iter_unordered( |
153 | 0 | &self, |
154 | 0 | ) -> impl ExactSizeIterator<Item = (&[u8], Option<&[u8]>, &T)> + Clone { |
155 | 0 | self.hashmap |
156 | 0 | .iter() |
157 | 0 | .map(|(k, (v, ud))| (&k[..], v.as_ref().map(|v| &v[..]), ud)) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE19diff_iter_unordered0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff19diff_iter_unordered0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff19diff_iter_unordered0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB6_8TrieDiffpE19diff_iter_unordered00Ba_ Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff19diff_iter_unordered00Ba_ Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff19diff_iter_unordered00CsiUjFBJteJ7x_17smoldot_full_node |
158 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE19diff_iter_unorderedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff19diff_iter_unorderedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff19diff_iter_unorderedCsiUjFBJteJ7x_17smoldot_full_node |
159 | | |
160 | | /// Returns an iterator to all the entries in the diff. |
161 | | /// |
162 | | /// Each value is either `Some` if the diff overwrites this diff, or `None` if it erases the |
163 | | /// underlying value. |
164 | 0 | pub fn diff_into_iter_unordered( |
165 | 0 | self, |
166 | 0 | ) -> impl ExactSizeIterator<Item = (Vec<u8>, Option<Vec<u8>>, T)> { |
167 | 0 | self.hashmap.into_iter().map(|(k, (v, ud))| (k, v, ud)) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE24diff_into_iter_unordered0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB4_8TrieDiffpE24diff_into_iter_unordered0B8_ |
168 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE24diff_into_iter_unorderedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE24diff_into_iter_unorderedB6_ |
169 | | |
170 | | /// Returns an iterator to all the entries in the diff within a given range. |
171 | | /// |
172 | | /// Each iterator element is the given and a boolean. This boolean is `true` if the diff |
173 | | /// overwrites this entry, or `false` if it erases the underlying value. |
174 | 5.89M | pub fn diff_range_ordered<U: ?Sized>( |
175 | 5.89M | &self, |
176 | 5.89M | range: impl ops::RangeBounds<U>, |
177 | 5.89M | ) -> impl Iterator<Item = (&[u8], bool)> + Clone |
178 | 5.89M | where |
179 | 5.89M | U: Ord, |
180 | 5.89M | Vec<u8>: Borrow<U>, |
181 | 5.89M | { |
182 | 5.89M | self.btree |
183 | 5.89M | .range(range) |
184 | 5.89M | .map(|(k, inserts)| (&k[..], *inserts)5.76M ) Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullE0B9_ _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1p_EB1s_EE0B9_ Line | Count | Source | 184 | 5.76M | .map(|(k, inserts)| (&k[..], *inserts)) |
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullE0B9_ Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1q_EB1t_EE0B9_ |
185 | 5.89M | } Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullEB7_ _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1n_EB1q_EEB7_ Line | Count | Source | 174 | 5.89M | pub fn diff_range_ordered<U: ?Sized>( | 175 | 5.89M | &self, | 176 | 5.89M | range: impl ops::RangeBounds<U>, | 177 | 5.89M | ) -> impl Iterator<Item = (&[u8], bool)> + Clone | 178 | 5.89M | where | 179 | 5.89M | U: Ord, | 180 | 5.89M | Vec<u8>: Borrow<U>, | 181 | 5.89M | { | 182 | 5.89M | self.btree | 183 | 5.89M | .range(range) | 184 | 5.89M | .map(|(k, inserts)| (&k[..], *inserts)) | 185 | 5.89M | } |
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1o_EB1r_EEB7_ |
186 | | |
187 | | /// Returns the storage key that immediately follows the provided `key`. Must be passed the |
188 | | /// storage key that immediately follows the provided `key` according to the base storage this |
189 | | /// diff is based upon. |
190 | | /// |
191 | | /// If [`StorageNextKey::Found`] is returned, it contains the desired key. If |
192 | | /// [`StorageNextKey::NextOf`] is returned, then this function should be called again but by |
193 | | /// passing the `key` found in the [`StorageNextKey::NextOf`] (and of course the corresponding |
194 | | /// `in_parent_next_key`). |
195 | | /// |
196 | | /// # Panic |
197 | | /// |
198 | | /// Panics if `in_parent_next_key` is provided and is inferior or equal to `key`. |
199 | | /// |
200 | 1 | pub fn storage_next_key<'a>( |
201 | 1 | &'a self, |
202 | 1 | key: &'_ [u8], |
203 | 1 | in_parent_next_key: Option<&'a [u8]>, |
204 | 1 | or_equal: bool, |
205 | 1 | ) -> StorageNextKey<'a> { |
206 | 1 | if let Some(in_parent_next_key) = in_parent_next_key { |
207 | 1 | assert!(in_parent_next_key > key); |
208 | 0 | } |
209 | | |
210 | | // Find the diff entry that immediately follows `key`. |
211 | 1 | let in_diff = self |
212 | 1 | .btree |
213 | 1 | .range::<[u8], _>(( |
214 | 1 | if or_equal { |
215 | 0 | ops::Bound::Included(key) |
216 | | } else { |
217 | 1 | ops::Bound::Excluded(key) |
218 | | }, |
219 | 1 | ops::Bound::Unbounded, |
220 | 1 | )) |
221 | 1 | .next(); |
222 | 1 | |
223 | 1 | match (in_parent_next_key, in_diff) { |
224 | 0 | (Some(a), Some((b, true))) if a <= &b[..] => StorageNextKey::Found(Some(a)), |
225 | 0 | (Some(a), Some((b, false))) if a < &b[..] => StorageNextKey::Found(Some(a)), |
226 | 0 | (Some(a), Some((b, false))) => { |
227 | 0 | debug_assert!(a >= &b[..]); // We actually expect `a == b` but let's be defensive. |
228 | 0 | debug_assert!(&b[..] > key || or_equal); |
229 | | |
230 | | // The next key according to the parent storage has been erased in this diff. It |
231 | | // is necessary to ask the user again, this time for the key after the one that |
232 | | // has been erased. |
233 | | |
234 | | // Note that there is probably something wrong here if `a != b`, but we ignore |
235 | | // that here. |
236 | | |
237 | 0 | StorageNextKey::NextOf(b) |
238 | | } |
239 | 0 | (Some(a), Some((b, true))) => { |
240 | 0 | debug_assert!(a >= &b[..]); |
241 | 0 | StorageNextKey::Found(Some(&b[..])) |
242 | | } |
243 | | |
244 | 1 | (Some(a), None) => StorageNextKey::Found(Some(a)), |
245 | 0 | (None, Some((b, true))) => StorageNextKey::Found(Some(&b[..])), |
246 | 0 | (None, Some((b, false))) => { |
247 | 0 | debug_assert!(&b[..] > key || or_equal); |
248 | 0 | let found = self |
249 | 0 | .btree |
250 | 0 | .range::<[u8], _>((ops::Bound::Excluded(&b[..]), ops::Bound::Unbounded)) |
251 | 0 | .find(|(_, value)| **value) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsibGXYHQB8Ea_25json_rpc_general_requests |
252 | 0 | .map(|(key, _)| &key[..]); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsibGXYHQB8Ea_25json_rpc_general_requests |
253 | 0 | StorageNextKey::Found(found) |
254 | | } |
255 | 0 | (None, None) => StorageNextKey::Found(None), |
256 | | } |
257 | 1 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyB6_ Line | Count | Source | 200 | 1 | pub fn storage_next_key<'a>( | 201 | 1 | &'a self, | 202 | 1 | key: &'_ [u8], | 203 | 1 | in_parent_next_key: Option<&'a [u8]>, | 204 | 1 | or_equal: bool, | 205 | 1 | ) -> StorageNextKey<'a> { | 206 | 1 | if let Some(in_parent_next_key) = in_parent_next_key { | 207 | 1 | assert!(in_parent_next_key > key); | 208 | 0 | } | 209 | | | 210 | | // Find the diff entry that immediately follows `key`. | 211 | 1 | let in_diff = self | 212 | 1 | .btree | 213 | 1 | .range::<[u8], _>(( | 214 | 1 | if or_equal { | 215 | 0 | ops::Bound::Included(key) | 216 | | } else { | 217 | 1 | ops::Bound::Excluded(key) | 218 | | }, | 219 | 1 | ops::Bound::Unbounded, | 220 | 1 | )) | 221 | 1 | .next(); | 222 | 1 | | 223 | 1 | match (in_parent_next_key, in_diff) { | 224 | 0 | (Some(a), Some((b, true))) if a <= &b[..] => StorageNextKey::Found(Some(a)), | 225 | 0 | (Some(a), Some((b, false))) if a < &b[..] => StorageNextKey::Found(Some(a)), | 226 | 0 | (Some(a), Some((b, false))) => { | 227 | 0 | debug_assert!(a >= &b[..]); // We actually expect `a == b` but let's be defensive. | 228 | 0 | debug_assert!(&b[..] > key || or_equal); | 229 | | | 230 | | // The next key according to the parent storage has been erased in this diff. It | 231 | | // is necessary to ask the user again, this time for the key after the one that | 232 | | // has been erased. | 233 | | | 234 | | // Note that there is probably something wrong here if `a != b`, but we ignore | 235 | | // that here. | 236 | | | 237 | 0 | StorageNextKey::NextOf(b) | 238 | | } | 239 | 0 | (Some(a), Some((b, true))) => { | 240 | 0 | debug_assert!(a >= &b[..]); | 241 | 0 | StorageNextKey::Found(Some(&b[..])) | 242 | | } | 243 | | | 244 | 1 | (Some(a), None) => StorageNextKey::Found(Some(a)), | 245 | 0 | (None, Some((b, true))) => StorageNextKey::Found(Some(&b[..])), | 246 | 0 | (None, Some((b, false))) => { | 247 | 0 | debug_assert!(&b[..] > key || or_equal); | 248 | 0 | let found = self | 249 | 0 | .btree | 250 | 0 | .range::<[u8], _>((ops::Bound::Excluded(&b[..]), ops::Bound::Unbounded)) | 251 | 0 | .find(|(_, value)| **value) | 252 | 0 | .map(|(key, _)| &key[..]); | 253 | 0 | StorageNextKey::Found(found) | 254 | | } | 255 | 0 | (None, None) => StorageNextKey::Found(None), | 256 | | } | 257 | 1 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsibGXYHQB8Ea_25json_rpc_general_requests |
258 | | |
259 | | /// Applies the given diff on top of the current one. |
260 | 0 | pub fn merge(&mut self, other: &TrieDiff<T>) |
261 | 0 | where |
262 | 0 | T: Clone, |
263 | 0 | { |
264 | 0 | self.merge_map(other, |v| v.clone()) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE5merge0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB4_8TrieDiffpE5merge0B8_ |
265 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5mergeB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5mergeB6_ |
266 | | |
267 | | /// Applies the given diff on top of the current one. |
268 | | /// |
269 | | /// Each user data in the other diff is first passed through the map. |
270 | 0 | pub fn merge_map<U>(&mut self, other: &TrieDiff<U>, mut map: impl FnMut(&U) -> T) { |
271 | | // TODO: provide an alternative method that consumes `other` as well? |
272 | 0 | for (key, (value, user_data)) in &other.hashmap { |
273 | 0 | self.hashmap |
274 | 0 | .insert(key.clone(), (value.clone(), map(user_data))); |
275 | 0 | self.btree.insert(key.clone(), value.is_some()); |
276 | 0 | } |
277 | 0 | } Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB3_8TrieDiffpE9merge_mapppEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB3_8TrieDiffpE9merge_mapppEB7_ |
278 | | } |
279 | | |
280 | | impl<T> fmt::Debug for TrieDiff<T> |
281 | | where |
282 | | T: fmt::Debug, |
283 | | { |
284 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
285 | 0 | // Delegate to `self.inner` |
286 | 0 | fmt::Debug::fmt(&self.hashmap, f) |
287 | 0 | } Unexecuted instantiation: _RNvXs_NtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiffNtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB8_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs_0pEINtB5_8TrieDiffpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_ |
288 | | } |
289 | | |
290 | | // We implement `PartialEq` manually, because deriving it would mean that both the hash map and |
291 | | // the tree are compared. |
292 | | impl<T, U> cmp::PartialEq<TrieDiff<U>> for TrieDiff<T> |
293 | | where |
294 | | T: cmp::PartialEq<U>, |
295 | | { |
296 | 0 | fn eq(&self, other: &TrieDiff<U>) -> bool { |
297 | 0 | // As of the writing of this code, HashMap<K, T> doesn't implement |
298 | 0 | // PartialEq<HashMap<K, U>> where T: PartialEq<U>, so we have to implement it manually. The |
299 | 0 | // way this is implemented matches what the underlying implementation of HashMap does. |
300 | 0 | if self.hashmap.len() != other.hashmap.len() { |
301 | 0 | return false; |
302 | 0 | } |
303 | 0 |
|
304 | 0 | self.hashmap.iter().all(|(key, (v1, u1))| { |
305 | 0 | other |
306 | 0 | .hashmap |
307 | 0 | .get(key) |
308 | 0 | .map_or(false, |(v2, u2)| *v1 == *v2 && *u1 == *u2) Unexecuted instantiation: _RNCNCNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB9_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB13_pEE2eq00Bd_ Unexecuted instantiation: _RNCNCNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB9_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB14_pEE2eq00Bd_ |
309 | 0 | }) Unexecuted instantiation: _RNCNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB7_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB11_pEE2eq0Bb_ Unexecuted instantiation: _RNCNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB7_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB12_pEE2eq0Bb_ |
310 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB5_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIBZ_pEE2eqB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB5_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB10_pEE2eqB9_ |
311 | | } |
312 | | |
313 | | impl<T> cmp::Eq for TrieDiff<T> where T: cmp::Eq {} |
314 | | |
315 | | impl<T> Default for TrieDiff<T> { |
316 | 135 | fn default() -> Self { |
317 | 135 | TrieDiff::empty() |
318 | 135 | } _RNvXs2_NtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultB9_ Line | Count | Source | 316 | 8 | fn default() -> Self { | 317 | 8 | TrieDiff::empty() | 318 | 8 | } |
Unexecuted instantiation: _RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultCsDDUKWWCHAU_18smoldot_light_wasm _RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultB9_ Line | Count | Source | 316 | 126 | fn default() -> Self { | 317 | 126 | TrieDiff::empty() | 318 | 126 | } |
_RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultCsiUjFBJteJ7x_17smoldot_full_node Line | Count | Source | 316 | 1 | fn default() -> Self { | 317 | 1 | TrieDiff::empty() | 318 | 1 | } |
|
319 | | } |
320 | | |
321 | | impl<T> FromIterator<(Vec<u8>, Option<Vec<u8>>, T)> for TrieDiff<T> { |
322 | 0 | fn from_iter<I>(iter: I) -> Self |
323 | 0 | where |
324 | 0 | I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>, T)>, |
325 | 0 | { |
326 | 0 | let hashmap = iter |
327 | 0 | .into_iter() |
328 | 0 | .map(|(k, v, ud)| (k, (v, ud))) Unexecuted instantiation: _RNCINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_6option6OptionB2i_EpEE9from_iterpE0Bc_ Unexecuted instantiation: _RNCINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1r_6option6OptionB2j_EpEE9from_iterpE0Bc_ |
329 | 0 | .collect::<HashMap<Vec<u8>, (Option<Vec<u8>>, T), fnv::FnvBuildHasher>>(); |
330 | 0 | let btree = hashmap |
331 | 0 | .iter() |
332 | 0 | .map(|(k, (v, _))| (k.clone(), v.is_some())) Unexecuted instantiation: _RNCINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_6option6OptionB2i_EpEE9from_iterpEs_0Bc_ Unexecuted instantiation: _RNCINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1r_6option6OptionB2j_EpEE9from_iterpEs_0Bc_ |
333 | 0 | .collect(); |
334 | 0 |
|
335 | 0 | Self { btree, hashmap } |
336 | 0 | } Unexecuted instantiation: _RINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB6_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1o_6option6OptionB2g_EpEE9from_iterpEBa_ Unexecuted instantiation: _RINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB6_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1p_6option6OptionB2h_EpEE9from_iterpEBa_ |
337 | | } |
338 | | |
339 | | pub enum StorageNextKey<'a> { |
340 | | Found(Option<&'a [u8]>), |
341 | | NextOf(&'a [u8]), |
342 | | } |