linera_views/views/set_view.rs
1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{borrow::Borrow, collections::BTreeMap, marker::PhantomData, mem};
5
6#[cfg(with_metrics)]
7use linera_base::prometheus_util::MeasureLatency as _;
8use serde::{de::DeserializeOwned, Serialize};
9
10use crate::{
11 batch::Batch,
12 common::{CustomSerialize, HasherOutput, Update},
13 context::{BaseKey, Context},
14 hashable_wrapper::WrappedHashableContainerView,
15 store::ReadableKeyValueStore as _,
16 views::{ClonableView, HashableView, Hasher, View, ViewError},
17};
18
19#[cfg(with_metrics)]
20mod metrics {
21 use std::sync::LazyLock;
22
23 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
24 use prometheus::HistogramVec;
25
26 /// The runtime of hash computation
27 pub static SET_VIEW_HASH_RUNTIME: LazyLock<HistogramVec> = LazyLock::new(|| {
28 register_histogram_vec(
29 "set_view_hash_runtime",
30 "SetView hash runtime",
31 &[],
32 exponential_bucket_latencies(5.0),
33 )
34 });
35}
36
37/// A [`View`] that supports inserting and removing values indexed by a key.
38#[derive(Debug)]
39pub struct ByteSetView<C> {
40 context: C,
41 delete_storage_first: bool,
42 updates: BTreeMap<Vec<u8>, Update<()>>,
43}
44
45impl<C: Context> View for ByteSetView<C> {
46 const NUM_INIT_KEYS: usize = 0;
47
48 type Context = C;
49
50 fn context(&self) -> &C {
51 &self.context
52 }
53
54 fn pre_load(_context: &C) -> Result<Vec<Vec<u8>>, ViewError> {
55 Ok(Vec::new())
56 }
57
58 fn post_load(context: C, _values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
59 Ok(Self {
60 context,
61 delete_storage_first: false,
62 updates: BTreeMap::new(),
63 })
64 }
65
66 async fn load(context: C) -> Result<Self, ViewError> {
67 Self::post_load(context, &[])
68 }
69
70 fn rollback(&mut self) {
71 self.delete_storage_first = false;
72 self.updates.clear();
73 }
74
75 async fn has_pending_changes(&self) -> bool {
76 if self.delete_storage_first {
77 return true;
78 }
79 !self.updates.is_empty()
80 }
81
82 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
83 let mut delete_view = false;
84 if self.delete_storage_first {
85 delete_view = true;
86 batch.delete_key_prefix(self.context.base_key().bytes.clone());
87 for (index, update) in mem::take(&mut self.updates) {
88 if let Update::Set(_) = update {
89 let key = self.context.base_key().base_index(&index);
90 batch.put_key_value_bytes(key, Vec::new());
91 delete_view = false;
92 }
93 }
94 } else {
95 for (index, update) in mem::take(&mut self.updates) {
96 let key = self.context.base_key().base_index(&index);
97 match update {
98 Update::Removed => batch.delete_key(key),
99 Update::Set(_) => batch.put_key_value_bytes(key, Vec::new()),
100 }
101 }
102 }
103 self.delete_storage_first = false;
104 Ok(delete_view)
105 }
106
107 fn clear(&mut self) {
108 self.delete_storage_first = true;
109 self.updates.clear();
110 }
111}
112
113impl<C: Context> ClonableView for ByteSetView<C> {
114 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
115 Ok(ByteSetView {
116 context: self.context.clone(),
117 delete_storage_first: self.delete_storage_first,
118 updates: self.updates.clone(),
119 })
120 }
121}
122
123impl<C: Context> ByteSetView<C> {
124 /// Insert a value. If already present then it has no effect.
125 /// ```rust
126 /// # tokio_test::block_on(async {
127 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
128 /// # use linera_views::views::View;
129 /// # let context = MemoryContext::new_for_testing(());
130 /// let mut set = ByteSetView::load(context).await.unwrap();
131 /// set.insert(vec![0, 1]);
132 /// assert_eq!(set.contains(&[0, 1]).await.unwrap(), true);
133 /// # })
134 /// ```
135 pub fn insert(&mut self, short_key: Vec<u8>) {
136 self.updates.insert(short_key, Update::Set(()));
137 }
138
139 /// Removes a value from the set. If absent then no effect.
140 /// ```rust
141 /// # tokio_test::block_on(async {
142 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
143 /// # use linera_views::views::View;
144 /// # let context = MemoryContext::new_for_testing(());
145 /// let mut set = ByteSetView::load(context).await.unwrap();
146 /// set.remove(vec![0, 1]);
147 /// assert_eq!(set.contains(&[0, 1]).await.unwrap(), false);
148 /// # })
149 /// ```
150 pub fn remove(&mut self, short_key: Vec<u8>) {
151 if self.delete_storage_first {
152 // Optimization: No need to mark `short_key` for deletion as we are going to remove all the keys at once.
153 self.updates.remove(&short_key);
154 } else {
155 self.updates.insert(short_key, Update::Removed);
156 }
157 }
158
159 /// Gets the extra data.
160 pub fn extra(&self) -> &C::Extra {
161 self.context.extra()
162 }
163}
164
165impl<C: Context> ByteSetView<C> {
166 /// Returns true if the given index exists in the set.
167 /// ```rust
168 /// # tokio_test::block_on(async {
169 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
170 /// # use linera_views::views::View;
171 /// # let context = MemoryContext::new_for_testing(());
172 /// let mut set = ByteSetView::load(context).await.unwrap();
173 /// set.insert(vec![0, 1]);
174 /// assert_eq!(set.contains(&[34]).await.unwrap(), false);
175 /// assert_eq!(set.contains(&[0, 1]).await.unwrap(), true);
176 /// # })
177 /// ```
178 pub async fn contains(&self, short_key: &[u8]) -> Result<bool, ViewError> {
179 if let Some(update) = self.updates.get(short_key) {
180 let value = match update {
181 Update::Removed => false,
182 Update::Set(()) => true,
183 };
184 return Ok(value);
185 }
186 if self.delete_storage_first {
187 return Ok(false);
188 }
189 let key = self.context.base_key().base_index(short_key);
190 Ok(self.context.store().contains_key(&key).await?)
191 }
192}
193
194impl<C: Context> ByteSetView<C> {
195 /// Returns the list of keys in the set. The order is lexicographic.
196 /// ```rust
197 /// # tokio_test::block_on(async {
198 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
199 /// # use linera_views::views::View;
200 /// # let context = MemoryContext::new_for_testing(());
201 /// let mut set = ByteSetView::load(context).await.unwrap();
202 /// set.insert(vec![0, 1]);
203 /// set.insert(vec![0, 2]);
204 /// assert_eq!(set.keys().await.unwrap(), vec![vec![0, 1], vec![0, 2]]);
205 /// # })
206 /// ```
207 pub async fn keys(&self) -> Result<Vec<Vec<u8>>, ViewError> {
208 let mut keys = Vec::new();
209 self.for_each_key(|key| {
210 keys.push(key.to_vec());
211 Ok(())
212 })
213 .await?;
214 Ok(keys)
215 }
216
217 /// Returns the number of entries in the set.
218 /// ```rust
219 /// # tokio_test::block_on(async {
220 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
221 /// # use linera_views::views::View;
222 /// # let context = MemoryContext::new_for_testing(());
223 /// let mut set = ByteSetView::load(context).await.unwrap();
224 /// set.insert(vec![0, 1]);
225 /// set.insert(vec![0, 2]);
226 /// assert_eq!(set.keys().await.unwrap(), vec![vec![0, 1], vec![0, 2]]);
227 /// # })
228 /// ```
229 pub async fn count(&self) -> Result<usize, ViewError> {
230 let mut count = 0;
231 self.for_each_key(|_key| {
232 count += 1;
233 Ok(())
234 })
235 .await?;
236 Ok(count)
237 }
238
239 /// Applies a function f on each index (aka key). Keys are visited in a
240 /// lexicographic order. If the function returns false, then the loop ends
241 /// prematurely.
242 /// ```rust
243 /// # tokio_test::block_on(async {
244 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
245 /// # use linera_views::views::View;
246 /// # let context = MemoryContext::new_for_testing(());
247 /// let mut set = ByteSetView::load(context).await.unwrap();
248 /// set.insert(vec![0, 1]);
249 /// set.insert(vec![0, 2]);
250 /// set.insert(vec![3]);
251 /// let mut count = 0;
252 /// set.for_each_key_while(|_key| {
253 /// count += 1;
254 /// Ok(count < 2)
255 /// })
256 /// .await
257 /// .unwrap();
258 /// assert_eq!(count, 2);
259 /// # })
260 /// ```
261 pub async fn for_each_key_while<F>(&self, mut f: F) -> Result<(), ViewError>
262 where
263 F: FnMut(&[u8]) -> Result<bool, ViewError> + Send,
264 {
265 let mut updates = self.updates.iter();
266 let mut update = updates.next();
267 if !self.delete_storage_first {
268 let base = &self.context.base_key().bytes;
269 for index in self.context.store().find_keys_by_prefix(base).await? {
270 loop {
271 match update {
272 Some((key, value)) if key <= &index => {
273 if let Update::Set(_) = value {
274 if !f(key)? {
275 return Ok(());
276 }
277 }
278 update = updates.next();
279 if key == &index {
280 break;
281 }
282 }
283 _ => {
284 if !f(&index)? {
285 return Ok(());
286 }
287 break;
288 }
289 }
290 }
291 }
292 }
293 while let Some((key, value)) = update {
294 if let Update::Set(_) = value {
295 if !f(key)? {
296 return Ok(());
297 }
298 }
299 update = updates.next();
300 }
301 Ok(())
302 }
303
304 /// Applies a function f on each serialized index (aka key). Keys are visited in a
305 /// lexicographic order.
306 /// ```rust
307 /// # tokio_test::block_on(async {
308 /// # use linera_views::{context::MemoryContext, set_view::ByteSetView};
309 /// # use linera_views::views::View;
310 /// # let context = MemoryContext::new_for_testing(());
311 /// let mut set = ByteSetView::load(context).await.unwrap();
312 /// set.insert(vec![0, 1]);
313 /// set.insert(vec![0, 2]);
314 /// set.insert(vec![3]);
315 /// let mut count = 0;
316 /// set.for_each_key(|_key| {
317 /// count += 1;
318 /// Ok(())
319 /// })
320 /// .await
321 /// .unwrap();
322 /// assert_eq!(count, 3);
323 /// # })
324 /// ```
325 pub async fn for_each_key<F>(&self, mut f: F) -> Result<(), ViewError>
326 where
327 F: FnMut(&[u8]) -> Result<(), ViewError> + Send,
328 {
329 self.for_each_key_while(|key| {
330 f(key)?;
331 Ok(true)
332 })
333 .await
334 }
335}
336
337impl<C: Context> HashableView for ByteSetView<C> {
338 type Hasher = sha3::Sha3_256;
339
340 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
341 self.hash().await
342 }
343
344 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
345 #[cfg(with_metrics)]
346 let _hash_latency = metrics::SET_VIEW_HASH_RUNTIME.measure_latency();
347 let mut hasher = sha3::Sha3_256::default();
348 let mut count = 0u32;
349 self.for_each_key(|key| {
350 count += 1;
351 hasher.update_with_bytes(key)?;
352 Ok(())
353 })
354 .await?;
355 hasher.update_with_bcs_bytes(&count)?;
356 Ok(hasher.finalize())
357 }
358}
359
360/// A [`View`] implementing the set functionality with the index `I` being any serializable type.
361#[derive(Debug)]
362pub struct SetView<C, I> {
363 set: ByteSetView<C>,
364 _phantom: PhantomData<I>,
365}
366
367impl<C: Context, I: Send + Sync + Serialize> View for SetView<C, I> {
368 const NUM_INIT_KEYS: usize = ByteSetView::<C>::NUM_INIT_KEYS;
369
370 type Context = C;
371
372 fn context(&self) -> &C {
373 self.set.context()
374 }
375
376 fn pre_load(context: &C) -> Result<Vec<Vec<u8>>, ViewError> {
377 ByteSetView::<C>::pre_load(context)
378 }
379
380 fn post_load(context: C, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
381 let set = ByteSetView::post_load(context, values)?;
382 Ok(Self {
383 set,
384 _phantom: PhantomData,
385 })
386 }
387
388 async fn load(context: C) -> Result<Self, ViewError> {
389 Self::post_load(context, &[])
390 }
391
392 fn rollback(&mut self) {
393 self.set.rollback()
394 }
395
396 async fn has_pending_changes(&self) -> bool {
397 self.set.has_pending_changes().await
398 }
399
400 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
401 self.set.flush(batch)
402 }
403
404 fn clear(&mut self) {
405 self.set.clear()
406 }
407}
408
409impl<C, I> ClonableView for SetView<C, I>
410where
411 C: Context,
412 I: Send + Sync + Serialize,
413{
414 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
415 Ok(SetView {
416 set: self.set.clone_unchecked()?,
417 _phantom: PhantomData,
418 })
419 }
420}
421
422impl<C: Context, I: Serialize> SetView<C, I> {
423 /// Inserts a value. If already present then no effect.
424 /// ```rust
425 /// # tokio_test::block_on(async {
426 /// # use linera_views::context::MemoryContext;
427 /// # use linera_views::set_view::SetView;
428 /// # use linera_views::views::View;
429 /// # let context = MemoryContext::new_for_testing(());
430 /// let mut set = SetView::<_, u32>::load(context).await.unwrap();
431 /// set.insert(&(34 as u32));
432 /// assert_eq!(set.indices().await.unwrap().len(), 1);
433 /// # })
434 /// ```
435 pub fn insert<Q>(&mut self, index: &Q) -> Result<(), ViewError>
436 where
437 I: Borrow<Q>,
438 Q: Serialize + ?Sized,
439 {
440 let short_key = BaseKey::derive_short_key(index)?;
441 self.set.insert(short_key);
442 Ok(())
443 }
444
445 /// Removes a value. If absent then nothing is done.
446 /// ```rust
447 /// # tokio_test::block_on(async {
448 /// # use linera_views::{context::MemoryContext, set_view::SetView};
449 /// # use linera_views::views::View;
450 /// # let context = MemoryContext::new_for_testing(());
451 /// let mut set = SetView::<_, u32>::load(context).await.unwrap();
452 /// set.remove(&(34 as u32));
453 /// assert_eq!(set.indices().await.unwrap().len(), 0);
454 /// # })
455 /// ```
456 pub fn remove<Q>(&mut self, index: &Q) -> Result<(), ViewError>
457 where
458 I: Borrow<Q>,
459 Q: Serialize + ?Sized,
460 {
461 let short_key = BaseKey::derive_short_key(index)?;
462 self.set.remove(short_key);
463 Ok(())
464 }
465
466 /// Obtains the extra data.
467 pub fn extra(&self) -> &C::Extra {
468 self.set.extra()
469 }
470}
471
472impl<C: Context, I: Serialize> SetView<C, I> {
473 /// Returns true if the given index exists in the set.
474 /// ```rust
475 /// # tokio_test::block_on(async {
476 /// # use linera_views::{context::MemoryContext, set_view::SetView};
477 /// # use linera_views::views::View;
478 /// # let context = MemoryContext::new_for_testing(());
479 /// let mut set: SetView<_, u32> = SetView::load(context).await.unwrap();
480 /// set.insert(&(34 as u32));
481 /// assert_eq!(set.contains(&(34 as u32)).await.unwrap(), true);
482 /// assert_eq!(set.contains(&(45 as u32)).await.unwrap(), false);
483 /// # })
484 /// ```
485 pub async fn contains<Q>(&self, index: &Q) -> Result<bool, ViewError>
486 where
487 I: Borrow<Q>,
488 Q: Serialize + ?Sized,
489 {
490 let short_key = BaseKey::derive_short_key(index)?;
491 self.set.contains(&short_key).await
492 }
493}
494
495impl<C: Context, I: Serialize + DeserializeOwned + Send> SetView<C, I> {
496 /// Returns the list of indices in the set. The order is determined by serialization.
497 /// ```rust
498 /// # tokio_test::block_on(async {
499 /// # use linera_views::{context::MemoryContext, set_view::SetView};
500 /// # use linera_views::views::View;
501 /// # let context = MemoryContext::new_for_testing(());
502 /// let mut set: SetView<_, u32> = SetView::load(context).await.unwrap();
503 /// set.insert(&(34 as u32));
504 /// assert_eq!(set.indices().await.unwrap(), vec![34 as u32]);
505 /// # })
506 /// ```
507 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
508 let mut indices = Vec::new();
509 self.for_each_index(|index| {
510 indices.push(index);
511 Ok(())
512 })
513 .await?;
514 Ok(indices)
515 }
516
517 /// Returns the number of entries in the set.
518 /// ```rust
519 /// # tokio_test::block_on(async {
520 /// # use linera_views::{context::MemoryContext, set_view::SetView};
521 /// # use linera_views::views::View;
522 /// # let context = MemoryContext::new_for_testing(());
523 /// let mut set: SetView<_, u32> = SetView::load(context).await.unwrap();
524 /// set.insert(&(34 as u32));
525 /// assert_eq!(set.count().await.unwrap(), 1);
526 /// # })
527 /// ```
528 pub async fn count(&self) -> Result<usize, ViewError> {
529 self.set.count().await
530 }
531
532 /// Applies a function f on each index. Indices are visited in an order
533 /// determined by the serialization. If the function returns false, then the
534 /// loop ends prematurely.
535 /// ```rust
536 /// # tokio_test::block_on(async {
537 /// # use linera_views::context::MemoryContext;
538 /// # use linera_views::set_view::SetView;
539 /// # use linera_views::views::View;
540 /// # let context = MemoryContext::new_for_testing(());
541 /// let mut set = SetView::<_, u32>::load(context).await.unwrap();
542 /// set.insert(&(34 as u32));
543 /// set.insert(&(37 as u32));
544 /// set.insert(&(42 as u32));
545 /// let mut count = 0;
546 /// set.for_each_index_while(|_key| {
547 /// count += 1;
548 /// Ok(count < 2)
549 /// })
550 /// .await
551 /// .unwrap();
552 /// assert_eq!(count, 2);
553 /// # })
554 /// ```
555 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
556 where
557 F: FnMut(I) -> Result<bool, ViewError> + Send,
558 {
559 self.set
560 .for_each_key_while(|key| {
561 let index = BaseKey::deserialize_value(key)?;
562 f(index)
563 })
564 .await?;
565 Ok(())
566 }
567
568 /// Applies a function f on each index. Indices are visited in an order
569 /// determined by the serialization.
570 /// ```rust
571 /// # tokio_test::block_on(async {
572 /// # use linera_views::context::MemoryContext;
573 /// # use linera_views::set_view::SetView;
574 /// # use linera_views::views::View;
575 /// # let context = MemoryContext::new_for_testing(());
576 /// let mut set = SetView::<_, u32>::load(context).await.unwrap();
577 /// set.insert(&(34 as u32));
578 /// set.insert(&(37 as u32));
579 /// set.insert(&(42 as u32));
580 /// let mut count = 0;
581 /// set.for_each_index(|_key| {
582 /// count += 1;
583 /// Ok(())
584 /// })
585 /// .await
586 /// .unwrap();
587 /// assert_eq!(count, 3);
588 /// # })
589 /// ```
590 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
591 where
592 F: FnMut(I) -> Result<(), ViewError> + Send,
593 {
594 self.set
595 .for_each_key(|key| {
596 let index = BaseKey::deserialize_value(key)?;
597 f(index)
598 })
599 .await?;
600 Ok(())
601 }
602}
603
604impl<C, I> HashableView for SetView<C, I>
605where
606 Self: View,
607 ByteSetView<C>: HashableView,
608{
609 type Hasher = <ByteSetView<C> as HashableView>::Hasher;
610
611 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
612 self.set.hash_mut().await
613 }
614
615 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
616 self.set.hash().await
617 }
618}
619
620/// A [`View`] implementing the set functionality with the index `I` being a type with a custom
621/// serialization format.
622#[derive(Debug)]
623pub struct CustomSetView<C, I> {
624 set: ByteSetView<C>,
625 _phantom: PhantomData<I>,
626}
627
628impl<C, I> View for CustomSetView<C, I>
629where
630 C: Context,
631 I: Send + Sync + CustomSerialize,
632{
633 const NUM_INIT_KEYS: usize = ByteSetView::<C>::NUM_INIT_KEYS;
634
635 type Context = C;
636
637 fn context(&self) -> &C {
638 self.set.context()
639 }
640
641 fn pre_load(context: &C) -> Result<Vec<Vec<u8>>, ViewError> {
642 ByteSetView::pre_load(context)
643 }
644
645 fn post_load(context: C, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
646 let set = ByteSetView::post_load(context, values)?;
647 Ok(Self {
648 set,
649 _phantom: PhantomData,
650 })
651 }
652
653 async fn load(context: C) -> Result<Self, ViewError> {
654 Self::post_load(context, &[])
655 }
656
657 fn rollback(&mut self) {
658 self.set.rollback()
659 }
660
661 async fn has_pending_changes(&self) -> bool {
662 self.set.has_pending_changes().await
663 }
664
665 fn flush(&mut self, batch: &mut Batch) -> Result<bool, ViewError> {
666 self.set.flush(batch)
667 }
668
669 fn clear(&mut self) {
670 self.set.clear()
671 }
672}
673
674impl<C, I> ClonableView for CustomSetView<C, I>
675where
676 C: Context,
677 I: Send + Sync + CustomSerialize,
678{
679 fn clone_unchecked(&mut self) -> Result<Self, ViewError> {
680 Ok(CustomSetView {
681 set: self.set.clone_unchecked()?,
682 _phantom: PhantomData,
683 })
684 }
685}
686
687impl<C: Context, I: CustomSerialize> CustomSetView<C, I> {
688 /// Inserts a value. If present then it has no effect.
689 /// ```rust
690 /// # tokio_test::block_on(async {
691 /// # use linera_views::context::MemoryContext;
692 /// # use linera_views::set_view::CustomSetView;
693 /// # use linera_views::views::View;
694 /// # let context = MemoryContext::new_for_testing(());
695 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
696 /// set.insert(&(34 as u128));
697 /// assert_eq!(set.indices().await.unwrap().len(), 1);
698 /// # })
699 /// ```
700 pub fn insert<Q>(&mut self, index: &Q) -> Result<(), ViewError>
701 where
702 I: Borrow<Q>,
703 Q: CustomSerialize,
704 {
705 let short_key = index.to_custom_bytes()?;
706 self.set.insert(short_key);
707 Ok(())
708 }
709
710 /// Removes a value. If absent then nothing is done.
711 /// ```rust
712 /// # tokio_test::block_on(async {
713 /// # use linera_views::context::MemoryContext;
714 /// # use linera_views::set_view::CustomSetView;
715 /// # use linera_views::views::View;
716 /// # let context = MemoryContext::new_for_testing(());
717 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
718 /// set.remove(&(34 as u128));
719 /// assert_eq!(set.indices().await.unwrap().len(), 0);
720 /// # })
721 /// ```
722 pub fn remove<Q>(&mut self, index: &Q) -> Result<(), ViewError>
723 where
724 I: Borrow<Q>,
725 Q: CustomSerialize,
726 {
727 let short_key = index.to_custom_bytes()?;
728 self.set.remove(short_key);
729 Ok(())
730 }
731
732 /// Obtains the extra data.
733 pub fn extra(&self) -> &C::Extra {
734 self.set.extra()
735 }
736}
737
738impl<C, I> CustomSetView<C, I>
739where
740 C: Context,
741 I: CustomSerialize,
742{
743 /// Returns true if the given index exists in the set.
744 /// ```rust
745 /// # tokio_test::block_on(async {
746 /// # use linera_views::context::MemoryContext;
747 /// # use linera_views::set_view::CustomSetView;
748 /// # use linera_views::views::View;
749 /// # let context = MemoryContext::new_for_testing(());
750 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
751 /// set.insert(&(34 as u128));
752 /// assert_eq!(set.contains(&(34 as u128)).await.unwrap(), true);
753 /// assert_eq!(set.contains(&(37 as u128)).await.unwrap(), false);
754 /// # })
755 /// ```
756 pub async fn contains<Q>(&self, index: &Q) -> Result<bool, ViewError>
757 where
758 I: Borrow<Q>,
759 Q: CustomSerialize,
760 {
761 let short_key = index.to_custom_bytes()?;
762 self.set.contains(&short_key).await
763 }
764}
765
766impl<C, I> CustomSetView<C, I>
767where
768 C: Context,
769 I: Sync + Clone + Send + CustomSerialize,
770{
771 /// Returns the list of indices in the set. The order is determined by the custom
772 /// serialization.
773 /// ```rust
774 /// # tokio_test::block_on(async {
775 /// # use linera_views::context::MemoryContext;
776 /// # use linera_views::set_view::CustomSetView;
777 /// # use linera_views::views::View;
778 /// # let context = MemoryContext::new_for_testing(());
779 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
780 /// set.insert(&(34 as u128));
781 /// set.insert(&(37 as u128));
782 /// assert_eq!(set.indices().await.unwrap(), vec![34 as u128, 37 as u128]);
783 /// # })
784 /// ```
785 pub async fn indices(&self) -> Result<Vec<I>, ViewError> {
786 let mut indices = Vec::new();
787 self.for_each_index(|index| {
788 indices.push(index);
789 Ok(())
790 })
791 .await?;
792 Ok(indices)
793 }
794
795 /// Returns the number of entries of the set.
796 /// ```rust
797 /// # tokio_test::block_on(async {
798 /// # use linera_views::context::MemoryContext;
799 /// # use linera_views::set_view::CustomSetView;
800 /// # use linera_views::views::View;
801 /// # let context = MemoryContext::new_for_testing(());
802 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
803 /// set.insert(&(34 as u128));
804 /// set.insert(&(37 as u128));
805 /// assert_eq!(set.count().await.unwrap(), 2);
806 /// # })
807 /// ```
808 pub async fn count(&self) -> Result<usize, ViewError> {
809 self.set.count().await
810 }
811
812 /// Applies a function f on each index. Indices are visited in an order
813 /// determined by the custom serialization. If the function does return
814 /// false, then the loop prematurely ends.
815 /// ```rust
816 /// # tokio_test::block_on(async {
817 /// # use linera_views::context::MemoryContext;
818 /// # use linera_views::set_view::CustomSetView;
819 /// # use linera_views::views::View;
820 /// # let context = MemoryContext::new_for_testing(());
821 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
822 /// set.insert(&(34 as u128));
823 /// set.insert(&(37 as u128));
824 /// set.insert(&(42 as u128));
825 /// let mut count = 0;
826 /// set.for_each_index_while(|_key| {
827 /// count += 1;
828 /// Ok(count < 5)
829 /// })
830 /// .await
831 /// .unwrap();
832 /// assert_eq!(count, 3);
833 /// # })
834 /// ```
835 pub async fn for_each_index_while<F>(&self, mut f: F) -> Result<(), ViewError>
836 where
837 F: FnMut(I) -> Result<bool, ViewError> + Send,
838 {
839 self.set
840 .for_each_key_while(|key| {
841 let index = I::from_custom_bytes(key)?;
842 f(index)
843 })
844 .await?;
845 Ok(())
846 }
847
848 /// Applies a function f on each index. Indices are visited in an order
849 /// determined by the custom serialization.
850 /// ```rust
851 /// # tokio_test::block_on(async {
852 /// # use linera_views::context::MemoryContext;
853 /// # use linera_views::set_view::CustomSetView;
854 /// # use linera_views::views::View;
855 /// # let context = MemoryContext::new_for_testing(());
856 /// let mut set = CustomSetView::<_, u128>::load(context).await.unwrap();
857 /// set.insert(&(34 as u128));
858 /// set.insert(&(37 as u128));
859 /// set.insert(&(42 as u128));
860 /// let mut count = 0;
861 /// set.for_each_index(|_key| {
862 /// count += 1;
863 /// Ok(())
864 /// })
865 /// .await
866 /// .unwrap();
867 /// assert_eq!(count, 3);
868 /// # })
869 /// ```
870 pub async fn for_each_index<F>(&self, mut f: F) -> Result<(), ViewError>
871 where
872 F: FnMut(I) -> Result<(), ViewError> + Send,
873 {
874 self.set
875 .for_each_key(|key| {
876 let index = I::from_custom_bytes(key)?;
877 f(index)
878 })
879 .await?;
880 Ok(())
881 }
882}
883
884impl<C: Context, I> HashableView for CustomSetView<C, I>
885where
886 Self: View,
887{
888 type Hasher = sha3::Sha3_256;
889
890 async fn hash_mut(&mut self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
891 self.set.hash_mut().await
892 }
893
894 async fn hash(&self) -> Result<<Self::Hasher as Hasher>::Output, ViewError> {
895 self.set.hash().await
896 }
897}
898
899/// Type wrapping `ByteSetView` while memoizing the hash.
900pub type HashedByteSetView<C> = WrappedHashableContainerView<C, ByteSetView<C>, HasherOutput>;
901
902/// Type wrapping `SetView` while memoizing the hash.
903pub type HashedSetView<C, I> = WrappedHashableContainerView<C, SetView<C, I>, HasherOutput>;
904
905/// Type wrapping `CustomSetView` while memoizing the hash.
906pub type HashedCustomSetView<C, I> =
907 WrappedHashableContainerView<C, CustomSetView<C, I>, HasherOutput>;
908
909#[cfg(with_graphql)]
910mod graphql {
911 use std::borrow::Cow;
912
913 use super::{CustomSetView, SetView};
914 use crate::context::Context;
915
916 impl<C: Context, I: async_graphql::OutputType> async_graphql::OutputType for SetView<C, I>
917 where
918 I: serde::ser::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync,
919 {
920 fn type_name() -> Cow<'static, str> {
921 format!("[{}]", I::qualified_type_name()).into()
922 }
923
924 fn qualified_type_name() -> String {
925 format!("[{}]!", I::qualified_type_name())
926 }
927
928 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
929 I::create_type_info(registry);
930 Self::qualified_type_name()
931 }
932
933 async fn resolve(
934 &self,
935 ctx: &async_graphql::ContextSelectionSet<'_>,
936 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
937 ) -> async_graphql::ServerResult<async_graphql::Value> {
938 let indices = self
939 .indices()
940 .await
941 .map_err(|e| async_graphql::Error::from(e).into_server_error(ctx.item.pos))?;
942 let indices_len = indices.len();
943 async_graphql::resolver_utils::resolve_list(ctx, field, indices, Some(indices_len))
944 .await
945 }
946 }
947
948 impl<C: Context, I: async_graphql::OutputType> async_graphql::OutputType for CustomSetView<C, I>
949 where
950 I: crate::common::CustomSerialize + Clone + Send + Sync,
951 {
952 fn type_name() -> Cow<'static, str> {
953 format!("[{}]", I::qualified_type_name()).into()
954 }
955
956 fn qualified_type_name() -> String {
957 format!("[{}]!", I::qualified_type_name())
958 }
959
960 fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
961 I::create_type_info(registry);
962 Self::qualified_type_name()
963 }
964
965 async fn resolve(
966 &self,
967 ctx: &async_graphql::ContextSelectionSet<'_>,
968 field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
969 ) -> async_graphql::ServerResult<async_graphql::Value> {
970 let indices = self
971 .indices()
972 .await
973 .map_err(|e| async_graphql::Error::from(e).into_server_error(ctx.item.pos))?;
974 let indices_len = indices.len();
975 async_graphql::resolver_utils::resolve_list(ctx, field, indices, Some(indices_len))
976 .await
977 }
978 }
979}