Skip to main content

ethexe_common/
hash.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4use alloc::string::{String, ToString};
5use anyhow::Result;
6use core::{
7    any::Any,
8    cmp::Ordering,
9    fmt::Debug,
10    hash::{Hash, Hasher},
11    marker::PhantomData,
12};
13use gprimitives::H256;
14use parity_scale_codec::{Decode, Encode};
15use scale_info::TypeInfo;
16
17fn option_string<T: ToString>(value: &Option<T>) -> String {
18    value
19        .as_ref()
20        .map(|v| v.to_string())
21        .unwrap_or_else(|| "<none>".to_string())
22}
23
24fn shortname<T: Any>() -> &'static str {
25    core::any::type_name::<T>()
26        .split("::")
27        .last()
28        .expect("name is empty")
29}
30
31#[derive(Encode, Decode, TypeInfo, derive_more::Into, derive_more::Display)]
32#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
33#[cfg_attr(feature = "std", serde(transparent))]
34#[display("{hash}")]
35#[scale_info(skip_type_params(T))]
36pub struct HashOf<T: 'static> {
37    hash: H256,
38    #[into(ignore)]
39    #[codec(skip)]
40    #[cfg_attr(feature = "std", serde(skip))]
41    _phantom: PhantomData<T>,
42}
43
44impl<T> Debug for HashOf<T> {
45    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46        write!(f, "HashOf<{}>({:?})", shortname::<T>(), self.hash)
47    }
48}
49
50impl<T> PartialEq for HashOf<T> {
51    fn eq(&self, other: &Self) -> bool {
52        self.hash.eq(&other.hash)
53    }
54}
55
56impl<T> Eq for HashOf<T> {}
57
58impl<T> PartialOrd for HashOf<T> {
59    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
60        Some(self.cmp(other))
61    }
62}
63
64impl<T> Ord for HashOf<T> {
65    fn cmp(&self, other: &Self) -> Ordering {
66        self.hash.cmp(&other.hash)
67    }
68}
69
70impl<T> Clone for HashOf<T> {
71    fn clone(&self) -> Self {
72        *self
73    }
74}
75
76impl<T> Copy for HashOf<T> {}
77
78impl<T> Hash for HashOf<T> {
79    fn hash<H: Hasher>(&self, state: &mut H) {
80        self.hash.hash(state)
81    }
82}
83
84impl<T> AsRef<[u8]> for HashOf<T> {
85    fn as_ref(&self) -> &[u8] {
86        self.hash.as_ref()
87    }
88}
89
90impl<T> HashOf<T> {
91    /// # Safety
92    /// Use it only for low-level storage implementations or tests.
93    pub unsafe fn new(hash: H256) -> Self {
94        Self {
95            hash,
96            _phantom: PhantomData,
97        }
98    }
99
100    /// Note: previous named `hash()`, but renamed to `inner()` to avoid confusion with `Hash` trait.
101    pub fn inner(self) -> H256 {
102        self.hash
103    }
104
105    pub fn zero() -> Self {
106        Self {
107            hash: H256::zero(),
108            _phantom: PhantomData,
109        }
110    }
111
112    #[cfg(feature = "mock")]
113    pub fn random() -> Self {
114        Self {
115            hash: H256::random(),
116            _phantom: PhantomData,
117        }
118    }
119}
120
121impl<T> Default for HashOf<T> {
122    fn default() -> Self {
123        Self::zero()
124    }
125}
126
127#[derive(
128    Encode, Decode, PartialEq, Eq, derive_more::Into, derive_more::From, derive_more::Display,
129)]
130#[cfg_attr(
131    feature = "std",
132    derive(serde::Serialize, serde::Deserialize),
133    serde(bound = "")
134)]
135#[display("{}", option_string(_0))]
136pub struct MaybeHashOf<T: 'static>(Option<HashOf<T>>);
137
138impl<T> Debug for MaybeHashOf<T> {
139    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
140        let option_string = option_string(&Self::to_inner(*self).map(HashOf::inner));
141        write!(f, "MaybeHashOf<{}>({})", shortname::<T>(), option_string)
142    }
143}
144
145impl<T> Clone for MaybeHashOf<T> {
146    fn clone(&self) -> Self {
147        *self
148    }
149}
150
151impl<T> Copy for MaybeHashOf<T> {}
152
153impl<T> Hash for MaybeHashOf<T> {
154    fn hash<H: Hasher>(&self, state: &mut H) {
155        self.0.hash(state)
156    }
157}
158
159impl<T> MaybeHashOf<T> {
160    pub const fn empty() -> Self {
161        Self(None)
162    }
163
164    pub const fn is_empty(&self) -> bool {
165        self.0.is_none()
166    }
167
168    pub fn from_inner(inner: Option<HashOf<T>>) -> Self {
169        Self(inner)
170    }
171
172    pub fn to_inner(self) -> Option<HashOf<T>> {
173        self.0
174    }
175
176    pub fn map<U>(&self, f: impl FnOnce(HashOf<T>) -> U) -> Option<U> {
177        self.to_inner().map(f)
178    }
179
180    pub fn map_or_default<U: Default>(&self, f: impl FnOnce(HashOf<T>) -> U) -> U {
181        self.map(f).unwrap_or_default()
182    }
183
184    pub fn try_map_or_default<U: Default>(
185        &self,
186        f: impl FnOnce(HashOf<T>) -> Result<U>,
187    ) -> Result<U> {
188        self.map(f).unwrap_or_else(|| Ok(Default::default()))
189    }
190
191    pub fn replace(&mut self, other: Option<Self>) {
192        if let Some(other) = other {
193            *self = other;
194        }
195    }
196}
197
198impl<T> From<HashOf<T>> for MaybeHashOf<T> {
199    fn from(value: HashOf<T>) -> Self {
200        Self(Some(value))
201    }
202}