1use std::borrow::Cow;
8
9use custom_debug_derive::Debug;
10use serde::{Deserialize, Serialize};
11
12use crate::crypto::{BcsHashable, CryptoHash};
13
14#[derive(Debug)]
16pub struct Hashed<T> {
17 value: T,
18 hash: CryptoHash,
20}
21
22impl<T> Hashed<T> {
23 pub fn unchecked_new(value: T, hash: CryptoHash) -> Self {
29 Self { value, hash }
30 }
31
32 pub fn new<'de>(value: T) -> Self
37 where
38 T: BcsHashable<'de>,
39 {
40 let hash = CryptoHash::new(&value);
41 Self { value, hash }
42 }
43
44 pub fn hash(&self) -> CryptoHash {
46 self.hash
47 }
48
49 pub fn inner(&self) -> &T {
51 &self.value
52 }
53
54 pub fn into_inner(self) -> T {
56 self.value
57 }
58}
59
60impl<T: Serialize> Serialize for Hashed<T> {
61 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62 where
63 S: serde::Serializer,
64 {
65 self.value.serialize(serializer)
66 }
67}
68
69impl<'de, T: BcsHashable<'de>> Deserialize<'de> for Hashed<T> {
70 fn deserialize<D>(deserializer: D) -> Result<Hashed<T>, D::Error>
71 where
72 D: serde::Deserializer<'de>,
73 {
74 Ok(Hashed::new(T::deserialize(deserializer)?))
75 }
76}
77
78impl<T: Clone> Clone for Hashed<T> {
79 fn clone(&self) -> Self {
80 Self {
81 value: self.value.clone(),
82 hash: self.hash,
83 }
84 }
85}
86
87impl<T: async_graphql::OutputType> async_graphql::TypeName for Hashed<T> {
88 fn type_name() -> Cow<'static, str> {
89 format!("Hashed{}", T::type_name()).into()
90 }
91}
92
93#[async_graphql::Object(cache_control(no_cache), name_type)]
94impl<T: async_graphql::OutputType + Clone> Hashed<T> {
95 #[graphql(derived(name = "hash"))]
96 async fn _hash(&self) -> CryptoHash {
97 self.hash()
98 }
99
100 #[graphql(derived(name = "value"))]
101 async fn _value(&self) -> T {
102 self.inner().clone()
103 }
104}
105
106impl<T> PartialEq for Hashed<T> {
107 fn eq(&self, other: &Self) -> bool {
108 self.hash() == other.hash()
109 }
110}
111
112impl<T> Eq for Hashed<T> {}