penumbra_sdk_tct/internal/frontier/
top.rs1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4
5use crate::prelude::*;
6
7use frontier::tier::Nested;
8
9#[derive(Derivative, Serialize, Deserialize)]
12#[derivative(
13 Debug(bound = "Item: Debug, Item::Complete: Debug"),
14 Clone(bound = "Item: Clone, Item::Complete: Clone")
15)]
16#[serde(bound(
17 serialize = "Item: Serialize, Item::Complete: Serialize",
18 deserialize = "Item: Deserialize<'de>, Item::Complete: Deserialize<'de>"
19))]
20pub struct Top<Item: Focus + Clone>
21where
22 Item::Complete: Clone,
23{
24 track_forgotten: TrackForgotten,
25 inner: Option<Nested<Item>>,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
35pub enum TrackForgotten {
36 Yes,
38 No,
40}
41
42impl<Item: Focus + Clone> Top<Item>
43where
44 Item::Complete: Clone,
45{
46 #[allow(unused)]
48 pub fn new(track_forgotten: TrackForgotten) -> Self {
49 Self {
50 track_forgotten,
51 inner: None,
52 }
53 }
54
55 #[inline]
59 pub fn insert(&mut self, item: Item) -> Result<(), Item> {
60 let inner = std::mem::take(&mut self.inner);
63
64 let (result, inner) = if let Some(inner) = inner {
65 if inner.is_full() {
66 (Err(item), inner)
69 } else {
70 let inner = inner
72 .insert_owned(item)
73 .unwrap_or_else(|_| panic!("frontier is not full, so insert must succeed"));
74 (Ok(()), inner)
75 }
76 } else {
77 let inner = Nested::new(item);
79 (Ok(()), inner)
80 };
81
82 self.inner = Some(inner);
84
85 result
86 }
87
88 #[inline]
94 pub fn forget(&mut self, index: impl Into<u64>) -> bool
95 where
96 Item: Forget,
97 Item::Complete: ForgetOwned,
98 {
99 let forgotten = self.forgotten();
100
101 if let Some(ref mut inner) = self.inner {
102 inner.forget(forgotten, index)
103 } else {
104 false
105 }
106 }
107
108 #[inline]
110 pub fn forgotten(&self) -> Option<Forgotten> {
111 if let TrackForgotten::Yes = self.track_forgotten {
112 Some(
113 self.inner
114 .iter()
115 .flat_map(|inner| inner.forgotten().iter().copied())
116 .max()
117 .unwrap_or_default(),
118 )
119 } else {
120 None
121 }
122 }
123
124 #[inline]
130 pub fn update<T>(&mut self, f: impl FnOnce(&mut Item) -> T) -> Option<T> {
131 self.inner.as_mut().and_then(|inner| inner.update(f))
132 }
133
134 #[inline]
138 pub fn focus(&self) -> Option<&Item> {
139 if let Some(ref inner) = self.inner {
140 inner.focus()
141 } else {
142 None
143 }
144 }
145
146 #[inline]
148 pub fn finalize(self) -> Insert<complete::Top<Item::Complete>> {
149 if let Some(inner) = self.inner {
150 inner.finalize_owned().map(|inner| complete::Top { inner })
151 } else {
152 Insert::Hash(Hash::one())
154 }
155 }
156
157 #[inline]
159 pub fn is_full(&self) -> bool {
160 if let Some(ref inner) = self.inner {
161 inner.is_full()
162 } else {
163 false
164 }
165 }
166
167 #[inline]
169 pub fn is_empty(&self) -> bool {
170 self.inner.is_none()
171 }
172}
173
174impl<Item: Focus + Clone> Height for Top<Item>
175where
176 Item::Complete: Clone,
177{
178 type Height = <Nested<Item> as Height>::Height;
179}
180
181impl<Item: Focus + GetPosition + Clone> GetPosition for Top<Item>
182where
183 Item::Complete: Clone,
184{
185 #[inline]
186 fn position(&self) -> Option<u64> {
187 if let Some(ref frontier) = self.inner {
188 frontier.position()
189 } else {
190 Some(0)
191 }
192 }
193}
194
195impl<Item: Focus + Clone> GetHash for Top<Item>
196where
197 Item::Complete: Clone,
198{
199 #[inline]
200 fn hash(&self) -> Hash {
201 if let Some(ref inner) = self.inner {
202 inner.hash()
203 } else {
204 Hash::zero()
205 }
206 }
207
208 #[inline]
209 fn cached_hash(&self) -> Option<Hash> {
210 if let Some(ref inner) = self.inner {
211 inner.cached_hash()
212 } else {
213 Some(Hash::zero())
214 }
215 }
216}
217
218impl<Item: Focus + Witness + Clone> Witness for Top<Item>
219where
220 Item::Complete: Witness + Clone,
221{
222 fn witness(&self, index: impl Into<u64>) -> Option<(AuthPath<Self>, Hash)> {
223 if let Some(ref inner) = self.inner {
224 inner.witness(index)
225 } else {
226 None
227 }
228 }
229}
230
231impl<'tree, Item: Focus + GetPosition + Height + structure::Any<'tree> + Clone>
232 structure::Any<'tree> for Top<Item>
233where
234 Item::Complete: structure::Any<'tree> + Clone,
235{
236 fn kind(&self) -> Kind {
237 Kind::Internal {
238 height: <Self as Height>::Height::HEIGHT,
239 }
240 }
241
242 fn forgotten(&self) -> Forgotten {
243 self.forgotten().unwrap_or_default()
244 }
245
246 fn children(&'tree self) -> Vec<HashOrNode<'tree>> {
247 self.inner
248 .as_ref()
249 .map(structure::Any::children)
250 .unwrap_or_default()
251 }
252}
253
254impl<Item: Focus + Height + OutOfOrder + Clone> OutOfOrder for Top<Item>
255where
256 Item::Complete: OutOfOrderOwned + Clone,
257{
258 fn uninitialized(position: Option<u64>, forgotten: Forgotten) -> Self {
259 let inner = if position == Some(0) {
260 None
262 } else {
263 Some(Nested::uninitialized(position, forgotten))
265 };
266
267 Self {
268 inner,
269 track_forgotten: TrackForgotten::Yes,
272 }
273 }
274
275 fn uninitialized_out_of_order_insert_commitment(
276 &mut self,
277 index: u64,
278 commitment: StateCommitment,
279 ) {
280 if let Some(ref mut inner) = self.inner {
281 inner.uninitialized_out_of_order_insert_commitment(index, commitment);
282 }
283 }
284}
285
286impl<Item: Focus + Height + UncheckedSetHash + Clone> UncheckedSetHash for Top<Item>
287where
288 Item::Complete: UncheckedSetHash + Clone,
289{
290 fn unchecked_set_hash(&mut self, index: u64, height: u8, hash: Hash) {
291 if let Some(ref mut inner) = self.inner {
292 inner.unchecked_set_hash(index, height, hash);
293 }
294 }
295
296 fn finish_initialize(&mut self) {
297 if let Some(ref mut inner) = self.inner {
298 inner.finish_initialize();
299 }
300 }
301}
302
303#[cfg(test)]
304mod test {
305 use super::*;
306
307 #[test]
308 fn position_advances_by_one() {
309 let mut top: Top<Item> = Top::new(TrackForgotten::No);
310 for expected_position in 0..=(u16::MAX as u64) {
311 assert_eq!(top.position(), Some(expected_position));
312 top.insert(Hash::zero().into()).unwrap();
313 }
314 assert_eq!(top.position(), None);
315 }
316}