linera_views/views/
hashable_wrapper.rs1use std::{
5 marker::PhantomData,
6 ops::{Deref, DerefMut},
7 sync::Mutex,
8};
9
10use serde::{de::DeserializeOwned, Serialize};
11
12use crate::{
13 batch::Batch,
14 common::from_bytes_option,
15 context::Context,
16 store::ReadableKeyValueStore as _,
17 views::{ClonableView, HashableView, Hasher, View, ViewError, MIN_VIEW_TAG},
18};
19
20#[derive(Debug)]
22pub struct WrappedHashableContainerView<C, W, O> {
23 _phantom: PhantomData<C>,
24 stored_hash: Option<O>,
25 hash: Mutex<Option<O>>,
26 inner: W,
27}
28
29#[repr(u8)]
31enum KeyTag {
32 Inner = MIN_VIEW_TAG,
34 Hash,
36}
37
38impl<W: HashableView, O> View for WrappedHashableContainerView<W::Context, W, O>
39where
40 W: HashableView<Hasher: Hasher<Output = O>>,
41 O: Serialize + DeserializeOwned + Send + Sync + Copy + PartialEq,
42{
43 const NUM_INIT_KEYS: usize = 1 + W::NUM_INIT_KEYS;
44
45 type Context = W::Context;
46
47 fn context(&self) -> &Self::Context {
48 self.inner.context()
49 }
50
51 fn pre_load(context: &Self::Context) -> Result<Vec<Vec<u8>>, ViewError> {
52 let mut v = vec![context.base_key().base_tag(KeyTag::Hash as u8)];
53 let base_key = context.base_key().base_tag(KeyTag::Inner as u8);
54 let context = context.clone_with_base_key(base_key);
55 v.extend(W::pre_load(&context)?);
56 Ok(v)
57 }
58
59 fn post_load(context: Self::Context, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
60 let hash = from_bytes_option(values.first().ok_or(ViewError::PostLoadValuesError)?)?;
61 let base_key = context.base_key().base_tag(KeyTag::Inner as u8);
62 let context = context.clone_with_base_key(base_key);
63 let inner = W::post_load(
64 context,
65 values.get(1..).ok_or(ViewError::PostLoadValuesError)?,
66 )?;
67 Ok(Self {
68 _phantom: PhantomData,
69 stored_hash: hash,
70 hash: Mutex::new(hash),
71 inner,
72 })
73 }
74
75 async fn load(context: Self::Context) -> Result<Self, ViewError> {
76 let keys = Self::pre_load(&context)?;
77 let values = context.store().read_multi_values_bytes(keys).await?;
78 Self::post_load(context, &values)
79 }
80
81 fn rollback(&mut self) {
82 self.inner.rollback();
83 *self.hash.get_mut().unwrap() = self.stored_hash;
84 }
85
86 async fn has_pending_changes(&self) -> bool {
87 if self.inner.has_pending_changes().await {
88 return true;
89 }
90 let hash = self.hash.lock().unwrap();
91 self.stored_hash != *hash
92 }
93
94 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
95 let delete_view = self.inner.flush(batch)?;
96 let hash = self.hash.get_mut().unwrap();
97 if delete_view {
98 let mut key_prefix = self.inner.context().base_key().bytes.clone();
99 key_prefix.pop();
100 batch.delete_key_prefix(key_prefix);
101 self.stored_hash = None;
102 *hash = None;
103 } else if self.stored_hash != *hash {
104 let mut key = self.inner.context().base_key().bytes.clone();
105 let tag = key.last_mut().unwrap();
106 *tag = KeyTag::Hash as u8;
107 match hash {
108 None => batch.delete_key(key),
109 Some(hash) => batch.put_key_value(key, hash)?,
110 }
111 self.stored_hash = *hash;
112 }
113 Ok(delete_view)
114 }
115
116 fn clear(&mut self) {
117 self.inner.clear();
118 *self.hash.get_mut().unwrap() = None;
119 }
120}
121
122impl<W, O> ClonableView for WrappedHashableContainerView<W::Context, W, O>
123where
124 W: HashableView + ClonableView,
125 O: Serialize + DeserializeOwned + Send + Sync + Copy + PartialEq,
126 W::Hasher: Hasher<Output = O>,
127{
128 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
129 Ok(WrappedHashableContainerView {
130 _phantom: PhantomData,
131 stored_hash: self.stored_hash,
132 hash: Mutex::new(*self.hash.get_mut().unwrap()),
133 inner: self.inner.clone_unchecked()?,
134 })
135 }
136}
137
138impl<W, O> HashableView for WrappedHashableContainerView<W::Context, W, O>
139where
140 W: HashableView,
141 O: Serialize + DeserializeOwned + Send + Sync + Copy + PartialEq,
142 W::Hasher: Hasher<Output = O>,
143{
144 type Hasher = W::Hasher;
145
146 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
147 let hash = *self.hash.get_mut().unwrap();
148 match hash {
149 Some(hash) => Ok(hash),
150 None => {
151 let new_hash = self.inner.hash_mut().await?;
152 let hash = self.hash.get_mut().unwrap();
153 *hash = Some(new_hash);
154 Ok(new_hash)
155 }
156 }
157 }
158
159 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
160 let hash = *self.hash.lock().unwrap();
161 match hash {
162 Some(hash) => Ok(hash),
163 None => {
164 let new_hash = self.inner.hash().await?;
165 let mut hash = self.hash.lock().unwrap();
166 *hash = Some(new_hash);
167 Ok(new_hash)
168 }
169 }
170 }
171}
172
173impl<C, W, O> Deref for WrappedHashableContainerView<C, W, O> {
174 type Target = W;
175
176 fn deref(&self) -> &W {
177 &self.inner
178 }
179}
180
181impl<C, W, O> DerefMut for WrappedHashableContainerView<C, W, O> {
182 fn deref_mut(&mut self) -> &mut W {
183 *self.hash.get_mut().unwrap() = None;
184 &mut self.inner
185 }
186}
187
188#[cfg(with_graphql)]
189mod graphql {
190 use std::borrow::Cow;
191
192 use super::WrappedHashableContainerView;
193 use crate::context::Context;
194
195 impl<C, W, O> async_graphql::OutputType for WrappedHashableContainerView<C, W, O>
196 where
197 C: Context,
198 W: async_graphql::OutputType + Send + Sync,
199 O: Send + Sync,
200 {
201 fn type_name() -> Cow<'static, str> {
202 W::type_name()
203 }
204
205 fn qualified_type_name() -> String {
206 W::qualified_type_name()
207 }
208
209 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
210 W::create_type_info(registry)
211 }
212
213 async fn resolve(
214 &self,
215 ctx: &async_graphql::ContextSelectionSet<'_>,
216 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
217 ) -> async_graphql::ServerResult<async_graphql::Value> {
218 (**self).resolve(ctx, field).await
219 }
220 }
221}