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