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    /// Unseal the inner item, discarding the hash.
111    #[inline(always)]
112    #[allow(clippy::missing_const_for_fn)] // false positive
113    pub fn into_inner(self) -> T {
114        self.inner
115    }
116
117    /// Unseal the inner item, discarding the hash. Alias for
118    /// [`Self::into_inner`].
119    #[inline(always)]
120    #[allow(clippy::missing_const_for_fn)] // false positive
121    pub fn unseal(self) -> T {
122        self.into_inner()
123    }
124}
125
126impl<T> Sealed<&T> {
127    /// Maps a `Sealed<&T>` to a `Sealed<T>` by cloning the inner value.
128    pub fn cloned(self) -> Sealed<T>
129    where
130        T: Clone,
131    {
132        let Self { inner, seal } = self;
133        Sealed::new_unchecked(inner.clone(), seal)
134    }
135}
136
137impl<T> Default for Sealed<T>
138where
139    T: Sealable + Default,
140{
141    fn default() -> Self {
142        T::default().seal_slow()
143    }
144}
145
146#[cfg(feature = "arbitrary")]
147impl<'a, T> arbitrary::Arbitrary<'a> for Sealed<T>
148where
149    T: for<'b> arbitrary::Arbitrary<'b> + Sealable,
150{
151    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
152        Ok(T::arbitrary(u)?.seal_slow())
153    }
154}
155
156/// Sealeable objects.
157pub trait Sealable: Sized {
158    /// Calculate the seal hash, this may be slow.
159    fn hash_slow(&self) -> B256;
160
161    /// Seal the object by calculating the hash. This may be slow.
162    fn seal_slow(self) -> Sealed<Self> {
163        Sealed::new(self)
164    }
165
166    /// Seal a borrowed object by calculating the hash. This may be slow.
167    fn seal_ref_slow(&self) -> Sealed<&Self> {
168        Sealed::new_ref(self)
169    }
170
171    /// Instantiate an unchecked seal. This should be used with caution.
172    fn seal_unchecked(self, seal: B256) -> Sealed<Self> {
173        Sealed::new_unchecked(self, seal)
174    }
175
176    /// Instantiate an unchecked seal. This should be used with caution.
177    fn seal_ref_unchecked(&self, seal: B256) -> Sealed<&Self> {
178        Sealed::new_unchecked(self, seal)
179    }
180}