penumbra_sdk_tct/internal/
insert.rs

1use crate::prelude::*;
2
3/// Either an item or just its hash, to be used when inserting into a tree.
4///
5/// When inserting, only items inserted with [`Insert::Keep`] are retained as witnessed leaves of
6/// the tree; those inserted with [`Insert::Hash`] are pruned.
7#[derive(Clone, Copy, Eq, Derivative, Serialize, Deserialize)]
8#[derivative(Debug)]
9pub enum Insert<T> {
10    /// An item unto itself: when inserting, keep this witnessed in the tree.
11    Keep(T),
12    /// The hash of an item: when inserting, don't keep this witnessed in the tree.
13    #[derivative(Debug = "transparent")]
14    Hash(Hash),
15}
16
17/// The mutable-reference version of an [`Insert<T>`](Insert), distinct from `Insert<&mut T>`
18/// because it also allows mutation of the contained hash.
19#[derive(Eq, Derivative)]
20#[derivative(Debug)]
21pub enum InsertMut<'a, T> {
22    /// A mutable reference to the item.
23    Keep(&'a mut T),
24    /// A mutable reference to the hash of the item.
25    Hash(&'a mut Hash),
26}
27
28impl<T> Insert<T> {
29    /// Transform a `&Insert<T>` into a `Insert<&T>`.
30    pub fn as_ref(&self) -> Insert<&T> {
31        match self {
32            Insert::Keep(item) => Insert::Keep(item),
33            Insert::Hash(hash) => Insert::Hash(*hash),
34        }
35    }
36
37    /// Transform a `&mut Insert<T>` into a `Insert<&mut T>`.
38    pub fn as_mut(&mut self) -> InsertMut<'_, T> {
39        match self {
40            Insert::Keep(item) => InsertMut::Keep(item),
41            Insert::Hash(hash) => InsertMut::Hash(hash),
42        }
43    }
44
45    /// Test if this [`Insert`] is a [`Insert::Keep`].
46    pub fn is_keep(&self) -> bool {
47        matches!(self, Insert::Keep(_))
48    }
49
50    /// Test if this [`Insert`] is a [`Insert::Hash`].
51    pub fn is_hash(&self) -> bool {
52        matches!(self, Insert::Hash(_))
53    }
54
55    /// Map a function over the [`Insert::Keep`] part of an `Insert<T>`.
56    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Insert<U> {
57        match self {
58            Insert::Keep(item) => Insert::Keep(f(item)),
59            Insert::Hash(hash) => Insert::Hash(hash),
60        }
61    }
62
63    /// Map a function returning an `Insert<U>` over the [`Insert::Keep`] part of an `Insert<T>`.
64    pub fn and_then<U, F: FnOnce(T) -> Insert<U>>(self, f: F) -> Insert<U> {
65        match self {
66            Insert::Keep(item) => f(item),
67            Insert::Hash(hash) => Insert::Hash(hash),
68        }
69    }
70
71    /// Get the kept `T` out of this [`Insert<T>`] or return `None`.
72    pub fn keep(self) -> Option<T> {
73        match self {
74            Insert::Keep(item) => Some(item),
75            Insert::Hash(_) => None,
76        }
77    }
78}
79
80impl<'a, T> InsertMut<'a, T> {
81    /// Transform a `&InsertMut<T>` into a `InsertMut<&T>`.
82    pub fn as_ref(&self) -> Insert<&T> {
83        match self {
84            InsertMut::Keep(item) => Insert::Keep(item),
85            InsertMut::Hash(hash) => Insert::Hash(**hash),
86        }
87    }
88
89    /// Test if this [`InsertMut`] is a [`InsertMut::Keep`].
90    pub fn is_keep(&self) -> bool {
91        matches!(self, InsertMut::Keep(_))
92    }
93
94    /// Test if this [`InsertMut`] is a [`InsertMut::Hash`].
95    pub fn is_hash(&self) -> bool {
96        matches!(self, InsertMut::Hash(_))
97    }
98
99    /// Map a function over the [`InsertMut::Keep`] part of an `InsertMut<'_, T>`.
100    pub fn map<U, F: FnOnce(&mut T) -> U>(self, f: F) -> Insert<U> {
101        match self {
102            InsertMut::Keep(item) => Insert::Keep(f(item)),
103            InsertMut::Hash(hash) => Insert::Hash(*hash),
104        }
105    }
106
107    /// Map a function returning an `Insert<U>` over the [`InsertMut::Keep`] part of an
108    /// `InsertMut<T>`.
109    pub fn and_then<U, F: FnOnce(&mut T) -> Insert<U>>(self, f: F) -> Insert<U> {
110        match self {
111            InsertMut::Keep(item) => f(item),
112            InsertMut::Hash(hash) => Insert::Hash(*hash),
113        }
114    }
115
116    /// Get the kept `T` out of this [`Insert<T>`] or return `None`.
117    pub fn keep(self) -> Option<&'a mut T> {
118        match self {
119            InsertMut::Keep(item) => Some(item),
120            InsertMut::Hash(_) => None,
121        }
122    }
123}
124
125impl<T: PartialEq<S>, S> PartialEq<Insert<S>> for Insert<T> {
126    fn eq(&self, other: &Insert<S>) -> bool {
127        match (self, other) {
128            (Insert::Keep(item), Insert::Keep(other)) => item == other,
129            (Insert::Hash(hash), Insert::Hash(other)) => hash == other,
130            _ => false,
131        }
132    }
133}
134
135impl<T: PartialEq<S>, S> PartialEq<InsertMut<'_, S>> for InsertMut<'_, T> {
136    fn eq(&self, other: &InsertMut<S>) -> bool {
137        match (self, other) {
138            (InsertMut::Keep(item), InsertMut::Keep(other)) => item == other,
139            (InsertMut::Hash(hash), InsertMut::Hash(other)) => hash == other,
140            _ => false,
141        }
142    }
143}
144
145impl<T: GetHash> GetHash for Insert<T> {
146    #[inline]
147    fn hash(&self) -> Hash {
148        match self {
149            Insert::Keep(item) => item.hash(),
150            Insert::Hash(hash) => *hash,
151        }
152    }
153
154    #[inline]
155    fn cached_hash(&self) -> Option<Hash> {
156        match self {
157            Insert::Keep(item) => item.cached_hash(),
158            Insert::Hash(hash) => Some(*hash),
159        }
160    }
161}
162
163impl<T: Height> Height for Insert<T> {
164    type Height = T::Height;
165}
166
167impl<T: Height + ForgetOwned> Forget for Insert<T> {
168    fn forget(&mut self, forgotten: Option<Forgotten>, index: impl Into<u64>) -> bool {
169        // Replace `self` temporarily with an empty hash, so we can move out of it
170        let this = std::mem::replace(self, Insert::Hash(Hash::zero()));
171
172        // Whether something was actually forgotten
173        let was_forgotten;
174
175        // No matter which branch we take, we always put something valid back into `self` before
176        // returning from this function
177        (*self, was_forgotten) = match this {
178            Insert::Keep(item) => item.forget_owned(forgotten, index),
179            Insert::Hash(_) => (this, false),
180        };
181
182        // Return whether something was actually forgotten
183        was_forgotten
184    }
185}