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,
};
pub struct BoxedIter<'a, T> {
iter: Box<dyn Iterator<Item = T> + 'a>,
}
impl<'a, T> Iterator for BoxedIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
pub trait IntoBoxedIter<'a, T> {
fn into_boxed(self) -> BoxedIter<'a, T>;
}
impl<'a, T, I> IntoBoxedIter<'a, T> for I
where
I: Iterator<Item = T> + 'a,
{
fn into_boxed(self) -> BoxedIter<'a, T> {
BoxedIter {
iter: Box::new(self),
}
}
}
#[derive(Copy, Clone, Debug, PartialOrd, Eq, PartialEq)]
pub enum IterDirection {
Forward,
Reverse,
}
impl Default for IterDirection {
fn default() -> Self {
Self::Forward
}
}
#[impl_tools::autoimpl(for<T: trait> &T, &mut T, Box<T>, Arc<T>)]
pub trait IterableStore: KeyValueInspect {
fn iter_store(
&self,
column: Self::Column,
prefix: Option<&[u8]>,
start: Option<&[u8]>,
direction: IterDirection,
) -> BoxedIter<KVItem>;
}
pub trait IterableTable<M>
where
M: Mappable,
{
fn iter_table<P>(
&self,
prefix: Option<P>,
start: Option<&M::Key>,
direction: Option<IterDirection>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
P: AsRef<[u8]>;
}
impl<Column, M, S> IterableTable<M> for S
where
M: TableWithBlueprint<Column = Column>,
M::Blueprint: BlueprintInspect<M, S>,
S: IterableStore<Column = Column>,
{
fn iter_table<P>(
&self,
prefix: Option<P>,
start: Option<&M::Key>,
direction: Option<IterDirection>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
P: AsRef<[u8]>,
{
let encoder = start.map(|start| {
<M::Blueprint as BlueprintInspect<M, Self>>::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 = <M::Blueprint as BlueprintInspect<M, Self>>::KeyCodec::decode(
key.as_slice(),
)
.map_err(|e| crate::Error::Codec(anyhow::anyhow!(e)))?;
let value =
<M::Blueprint as BlueprintInspect<M, Self>>::ValueCodec::decode(
value.as_slice(),
)
.map_err(|e| crate::Error::Codec(anyhow::anyhow!(e)))?;
Ok((key, value))
})
})
.into_boxed()
}
}
pub trait IteratorOverTable {
fn iter_all<M>(
&self,
direction: Option<IterDirection>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
M: Mappable,
Self: IterableTable<M>,
{
self.iter_all_filtered::<M, [u8; 0]>(None, None, direction)
}
fn iter_all_by_prefix<M, P>(
&self,
prefix: Option<P>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
M: Mappable,
P: AsRef<[u8]>,
Self: IterableTable<M>,
{
self.iter_all_filtered::<M, P>(prefix, None, None)
}
fn iter_all_by_start<M>(
&self,
start: Option<&M::Key>,
direction: Option<IterDirection>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
M: Mappable,
Self: IterableTable<M>,
{
self.iter_all_filtered::<M, [u8; 0]>(None, start, direction)
}
fn iter_all_filtered<M, P>(
&self,
prefix: Option<P>,
start: Option<&M::Key>,
direction: Option<IterDirection>,
) -> BoxedIter<super::Result<(M::OwnedKey, M::OwnedValue)>>
where
M: Mappable,
P: AsRef<[u8]>,
Self: IterableTable<M>,
{
self.iter_table(prefix, start, direction)
}
}
impl<S> IteratorOverTable for S {}
pub fn iterator<'a, V>(
tree: &'a BTreeMap<Vec<u8>, V>,
prefix: Option<&[u8]>,
start: Option<&[u8]>,
direction: IterDirection,
) -> impl Iterator<Item = (&'a Vec<u8>, &'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()
}
}
}
}