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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Read operations for VerMap: get, contains_key, iter, range.
//!
//! Pure read path — none of these methods mutate state.
use std::ops::Bound;
use crate::{
common::ende::{KeyEnDeOrdered, ValueEnDe},
common::error::Result,
};
use super::map::VerMap;
use super::{BranchId, CommitId};
impl<K, V> VerMap<K, V>
where
K: KeyEnDeOrdered,
V: ValueEnDe,
{
/// Reads a value from the working state of `branch`.
///
/// # Panics
///
/// Panics if the stored bytes cannot be decoded back into `V`.
/// This can only happen due to data corruption or a type mismatch
/// between the writing and reading code — see the
/// [encode/decode trust model](crate::common::ende).
pub fn get(&self, branch: BranchId, key: &K) -> Result<Option<V>> {
let state = self.get_branch(branch)?;
let raw = self.tree.get(state.dirty_root, &key.to_bytes());
match raw {
Some(v) => Ok(Some(V::decode(&v).unwrap())),
None => Ok(None),
}
}
/// Reads a value at a specific historical commit.
///
/// # Panics
///
/// Panics if the stored bytes cannot be decoded — see
/// [`get`](Self::get) for details.
pub fn get_at_commit(&self, commit_id: CommitId, key: &K) -> Result<Option<V>> {
let commit = self.get_commit_inner(commit_id)?;
let raw = self.tree.get(commit.root, &key.to_bytes());
match raw {
Some(v) => Ok(Some(V::decode(&v).unwrap())),
None => Ok(None),
}
}
/// Checks if `key` exists in the working state of `branch`.
pub fn contains_key(&self, branch: BranchId, key: &K) -> Result<bool> {
let state = self.get_branch(branch)?;
Ok(self.tree.contains_key(state.dirty_root, &key.to_bytes()))
}
/// Iterates all entries on `branch` in ascending key order.
///
/// # Panics
///
/// The returned iterator panics if any stored entry cannot be
/// decoded — see [`get`](Self::get) for details.
pub fn iter(&self, branch: BranchId) -> Result<impl Iterator<Item = (K, V)> + '_> {
let state = self.get_branch(branch)?;
Ok(self
.tree
.iter(state.dirty_root)
.map(|(k, v)| (K::from_slice(&k).unwrap(), V::decode(&v).unwrap())))
}
/// Iterates entries in `[lo, hi)` on `branch` in ascending key order.
///
/// # Panics
///
/// The returned iterator panics on decode failure — see
/// [`get`](Self::get).
pub fn range(
&self,
branch: BranchId,
lo: Bound<&K>,
hi: Bound<&K>,
) -> Result<impl Iterator<Item = (K, V)> + '_> {
let state = self.get_branch(branch)?;
let lo_raw = match lo {
Bound::Included(k) => Bound::Included(k.to_bytes()),
Bound::Excluded(k) => Bound::Excluded(k.to_bytes()),
Bound::Unbounded => Bound::Unbounded,
};
let hi_raw = match hi {
Bound::Included(k) => Bound::Included(k.to_bytes()),
Bound::Excluded(k) => Bound::Excluded(k.to_bytes()),
Bound::Unbounded => Bound::Unbounded,
};
Ok(self
.tree
.range(
state.dirty_root,
lo_raw.as_ref().map(|v| v.as_slice()),
hi_raw.as_ref().map(|v| v.as_slice()),
)
.map(|(k, v)| (K::from_slice(&k).unwrap(), V::decode(&v).unwrap())))
}
/// Iterates all entries at a specific historical commit.
///
/// # Panics
///
/// The returned iterator panics on decode failure — see
/// [`get`](Self::get).
pub fn iter_at_commit(
&self,
commit_id: CommitId,
) -> Result<impl Iterator<Item = (K, V)> + '_> {
let commit = self.get_commit_inner(commit_id)?;
Ok(self
.tree
.iter(commit.root)
.map(|(k, v)| (K::from_slice(&k).unwrap(), V::decode(&v).unwrap())))
}
/// Iterates entries in `[lo, hi)` at a specific historical commit
/// in ascending key order.
///
/// # Panics
///
/// The returned iterator panics on decode failure — see
/// [`get`](Self::get).
pub fn range_at_commit(
&self,
commit_id: CommitId,
lo: Bound<&K>,
hi: Bound<&K>,
) -> Result<impl Iterator<Item = (K, V)> + '_> {
let commit = self.get_commit_inner(commit_id)?;
let lo_raw = match lo {
Bound::Included(k) => Bound::Included(k.to_bytes()),
Bound::Excluded(k) => Bound::Excluded(k.to_bytes()),
Bound::Unbounded => Bound::Unbounded,
};
let hi_raw = match hi {
Bound::Included(k) => Bound::Included(k.to_bytes()),
Bound::Excluded(k) => Bound::Excluded(k.to_bytes()),
Bound::Unbounded => Bound::Unbounded,
};
Ok(self
.tree
.range(
commit.root,
lo_raw.as_ref().map(|v| v.as_slice()),
hi_raw.as_ref().map(|v| v.as_slice()),
)
.map(|(k, v)| (K::from_slice(&k).unwrap(), V::decode(&v).unwrap())))
}
/// Iterates all raw (untyped) key-value pairs on a branch.
///
/// Returns `(Vec<u8>, Vec<u8>)` without decoding, useful for
/// feeding into external consumers (e.g. MPT hash computation).
pub fn raw_iter(
&self,
branch: BranchId,
) -> Result<impl Iterator<Item = (Vec<u8>, Vec<u8>)> + '_> {
let state = self.get_branch(branch)?;
Ok(self.tree.iter(state.dirty_root))
}
/// Iterates all raw (untyped) key-value pairs at a historical commit.
pub fn raw_iter_at_commit(
&self,
commit_id: CommitId,
) -> Result<impl Iterator<Item = (Vec<u8>, Vec<u8>)> + '_> {
let commit = self.get_commit_inner(commit_id)?;
Ok(self.tree.iter(commit.root))
}
/// Checks if `key` exists at a specific historical commit.
pub fn contains_key_at_commit(&self, commit_id: CommitId, key: &K) -> Result<bool> {
let commit = self.get_commit_inner(commit_id)?;
Ok(self.tree.contains_key(commit.root, &key.to_bytes()))
}
}