//! The module defines primitives that allow iterating of the storage. use crate::{ blueprint::BlueprintInspect, codec::{ Decode, Encode, Encoder, }, kv_store::{ KVItem, KeyValueInspect, }, structured_storage::TableWithBlueprint, }; use fuel_vm_private::fuel_storage::Mappable; use std::{ collections::BTreeMap, sync::Arc, }; // TODO: BoxedIter to be used until RPITIT lands in stable rust. /// A boxed variant of the iterator that can be used as a return type of the traits. pub struct BoxedIter<'a, T> { iter: Box + 'a>, } impl<'a, T> Iterator for BoxedIter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.iter.next() } } /// The traits simplifies conversion into `BoxedIter`. pub trait IntoBoxedIter<'a, T> { /// Converts `Self` iterator into `BoxedIter`. fn into_boxed(self) -> BoxedIter<'a, T>; } impl<'a, T, I> IntoBoxedIter<'a, T> for I where I: Iterator + 'a, { fn into_boxed(self) -> BoxedIter<'a, T> { BoxedIter { iter: Box::new(self), } } } /// A enum for iterating across the database #[derive(Copy, Clone, Debug, PartialOrd, Eq, PartialEq)] pub enum IterDirection { /// Iterate forward Forward, /// Iterate backward Reverse, } impl Default for IterDirection { fn default() -> Self { Self::Forward } } /// A trait for iterating over the storage of [`KeyValueInspect`]. #[impl_tools::autoimpl(for &T, &mut T, Box, Arc)] pub trait IterableStore: KeyValueInspect { /// Returns an iterator over the values in the storage. fn iter_store( &self, column: Self::Column, prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, ) -> BoxedIter; } /// A trait for iterating over the `Mappable` table. pub trait IterableTable where M: Mappable, { /// Returns an iterator over the all entries in the table with a prefix after a specific start key. fn iter_table

( &self, prefix: Option

, start: Option<&M::Key>, direction: Option, ) -> BoxedIter> where P: AsRef<[u8]>; } impl IterableTable for S where M: TableWithBlueprint, M::Blueprint: BlueprintInspect, S: IterableStore, { fn iter_table

( &self, prefix: Option

, start: Option<&M::Key>, direction: Option, ) -> BoxedIter> where P: AsRef<[u8]>, { let encoder = start.map(|start| { >::KeyCodec::encode(start) }); let start = encoder.as_ref().map(|encoder| encoder.as_bytes()); IterableStore::iter_store( self, M::column(), prefix.as_ref().map(|p| p.as_ref()), start.as_ref().map(|cow| cow.as_ref()), direction.unwrap_or_default(), ) .map(|val| { val.and_then(|(key, value)| { let key = >::KeyCodec::decode( key.as_slice(), ) .map_err(|e| crate::Error::Codec(anyhow::anyhow!(e)))?; let value = >::ValueCodec::decode( value.as_slice(), ) .map_err(|e| crate::Error::Codec(anyhow::anyhow!(e)))?; Ok((key, value)) }) }) .into_boxed() } } /// A helper trait to provide a user-friendly API over table iteration. pub trait IteratorOverTable { /// Returns an iterator over the all entries in the table. fn iter_all( &self, direction: Option, ) -> BoxedIter> where M: Mappable, Self: IterableTable, { self.iter_all_filtered::(None, None, direction) } /// Returns an iterator over the all entries in the table with the specified prefix. fn iter_all_by_prefix( &self, prefix: Option

, ) -> BoxedIter> where M: Mappable, P: AsRef<[u8]>, Self: IterableTable, { self.iter_all_filtered::(prefix, None, None) } /// Returns an iterator over the all entries in the table after a specific start key. fn iter_all_by_start( &self, start: Option<&M::Key>, direction: Option, ) -> BoxedIter> where M: Mappable, Self: IterableTable, { self.iter_all_filtered::(None, start, direction) } /// Returns an iterator over the all entries in the table with a prefix after a specific start key. fn iter_all_filtered( &self, prefix: Option

, start: Option<&M::Key>, direction: Option, ) -> BoxedIter> where M: Mappable, P: AsRef<[u8]>, Self: IterableTable, { self.iter_table(prefix, start, direction) } } impl IteratorOverTable for S {} /// Returns an iterator over the values in the `BTreeMap`. pub fn iterator<'a, V>( tree: &'a BTreeMap, V>, prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, ) -> impl Iterator, &'a V)> + 'a { match (prefix, start) { (None, None) => { if direction == IterDirection::Forward { tree.iter().into_boxed() } else { tree.iter().rev().into_boxed() } } (Some(prefix), None) => { let prefix = prefix.to_vec(); if direction == IterDirection::Forward { tree.range(prefix.clone()..) .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) .into_boxed() } else { let mut vec: Vec<_> = tree .range(prefix.clone()..) .into_boxed() .take_while(|(key, _)| key.starts_with(prefix.as_slice())) .collect(); vec.reverse(); vec.into_iter().into_boxed() } } (None, Some(start)) => { if direction == IterDirection::Forward { tree.range(start.to_vec()..).into_boxed() } else { tree.range(..=start.to_vec()).rev().into_boxed() } } (Some(prefix), Some(start)) => { let prefix = prefix.to_vec(); if direction == IterDirection::Forward { tree.range(start.to_vec()..) .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) .into_boxed() } else { tree.range(..=start.to_vec()) .rev() .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) .into_boxed() } } } }