alloy_primitives/
sealed.rs

1use crate::B256;
2use derive_more::{AsRef, Deref};
3
4/// A consensus hashable item, with its memoized hash.
5///
6/// We do not implement any specific hashing algorithm here. Instead types
7/// implement the [`Sealable`] trait to provide define their own hash.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, AsRef, Deref)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
11pub struct Sealed<T> {
12    /// The inner item.
13    #[as_ref]
14    #[deref]
15    #[cfg_attr(feature = "serde", serde(flatten))]
16    inner: T,
17    #[cfg_attr(feature = "serde", serde(rename = "hash"))]
18    /// Its hash.
19    seal: B256,
20}
21
22impl<T> Sealed<T> {
23    /// Seal the inner item.
24    pub fn new(inner: T) -> Self
25    where
26        T: Sealable,
27    {
28        let seal = inner.hash_slow();
29        Self { inner, seal }
30    }
31
32    /// Seal the inner item, by reference.
33    pub fn new_ref(inner: &T) -> Sealed<&T>
34    where
35        T: Sealable,
36    {
37        let seal = inner.hash_slow();
38        Sealed { inner, seal }
39    }
40
41    /// Seal the inner item with some function.
42    pub fn new_with<F>(inner: T, f: F) -> Self
43    where
44        T: Sized,
45        F: FnOnce(&T) -> B256,
46    {
47        let seal = f(&inner);
48        Self::new_unchecked(inner, seal)
49    }
50
51    /// Seal a reference to the inner item with some function.
52    pub fn new_ref_with<F>(inner: &T, f: F) -> Sealed<&T>
53    where
54        T: Sized,
55        F: FnOnce(&T) -> B256,
56    {
57        let seal = f(inner);
58        Sealed::new_unchecked(inner, seal)
59    }
60
61    /// Instantiate without performing the hash. This should be used carefully.
62    pub const fn new_unchecked(inner: T, seal: B256) -> Self {
63        Self { inner, seal }
64    }
65
66    /// Converts from `&Sealed<T>` to `Sealed<&T>`.
67    pub const fn as_sealed_ref(&self) -> Sealed<&T> {
68        Sealed { inner: &self.inner, seal: self.seal }
69    }
70
71    /// Decompose into parts.
72    #[allow(clippy::missing_const_for_fn)] // false positive
73    pub fn into_parts(self) -> (T, B256) {
74        (self.inner, self.seal)
75    }
76
77    /// Decompose into parts. Alias for [`Self::into_parts`].
78    #[allow(clippy::missing_const_for_fn)] // false positive
79    pub fn split(self) -> (T, B256) {
80        self.into_parts()
81    }
82
83    /// Clone the inner item.
84    #[inline(always)]
85    pub fn clone_inner(&self) -> T
86    where
87        T: Clone,
88    {
89        self.inner.clone()
90    }
91
92    /// Get the inner item.
93    #[inline(always)]
94    pub const fn inner(&self) -> &T {
95        &self.inner
96    }
97
98    /// Get the hash.
99    #[inline(always)]
100    pub const fn seal(&self) -> B256 {
101        self.seal
102    }
103
104    /// Get the hash.
105    #[inline(always)]
106    pub const fn hash(&self) -> B256 {
107        self.seal
108    }
109
110    /// Get the hash.
111    #[inline(always)]
112    pub const fn hash_ref(&self) -> &B256 {
113        &self.seal
114    }
115
116    /// Unseal the inner item, discarding the hash.
117    #[inline(always)]
118    #[allow(clippy::missing_const_for_fn)] // false positive
119    pub fn into_inner(self) -> T {
120        self.inner
121    }
122
123    /// Unseal the inner item, discarding the hash. Alias for
124    /// [`Self::into_inner`].
125    #[inline(always)]
126    #[allow(clippy::missing_const_for_fn)] // false positive
127    pub fn unseal(self) -> T {
128        self.into_inner()
129    }
130}
131
132impl<T> Sealed<&T> {
133    /// Maps a `Sealed<&T>` to a `Sealed<T>` by cloning the inner value.
134    pub fn cloned(self) -> Sealed<T>
135    where
136        T: Clone,
137    {
138        let Self { inner, seal } = self;
139        Sealed::new_unchecked(inner.clone(), seal)
140    }
141}
142
143impl<T> Default for Sealed<T>
144where
145    T: Sealable + Default,
146{
147    fn default() -> Self {
148        T::default().seal_slow()
149    }
150}
151
152#[cfg(feature = "arbitrary")]
153impl<'a, T> arbitrary::Arbitrary<'a> for Sealed<T>
154where
155    T: for<'b> arbitrary::Arbitrary<'b> + Sealable,
156{
157    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
158        Ok(T::arbitrary(u)?.seal_slow())
159    }
160}
161
162/// Sealeable objects.
163pub trait Sealable: Sized {
164    /// Calculate the seal hash, this may be slow.
165    fn hash_slow(&self) -> B256;
166
167    /// Seal the object by calculating the hash. This may be slow.
168    fn seal_slow(self) -> Sealed<Self> {
169        Sealed::new(self)
170    }
171
172    /// Seal a borrowed object by calculating the hash. This may be slow.
173    fn seal_ref_slow(&self) -> Sealed<&Self> {
174        Sealed::new_ref(self)
175    }
176
177    /// Instantiate an unchecked seal. This should be used with caution.
178    fn seal_unchecked(self, seal: B256) -> Sealed<Self> {
179        Sealed::new_unchecked(self, seal)
180    }
181
182    /// Instantiate an unchecked seal. This should be used with caution.
183    fn seal_ref_unchecked(&self, seal: B256) -> Sealed<&Self> {
184        Sealed::new_unchecked(self, seal)
185    }
186}