#![cfg(feature = "iterator")]
use serde::de::DeserializeOwned;
use serde::Serialize;
use cosmwasm_std::{from_slice, Order, Record, StdError, StdResult, Storage};
use crate::bound::PrefixBound;
use crate::de::KeyDeserialize;
use crate::helpers::namespaces_with_key;
use crate::iter_helpers::deserialize_kv;
use crate::map::Map;
use crate::prefix::namespaced_prefix_range;
use crate::{Bound, Index, Prefix, Prefixer, PrimaryKey};
use std::marker::PhantomData;
pub struct MultiIndex<'a, IK, T, PK> {
index: fn(&[u8], &T) -> IK,
idx_namespace: &'a [u8],
idx_map: Map<'a, Vec<u8>, u32>,
pk_namespace: &'a [u8],
phantom: PhantomData<PK>,
}
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
{
pub const fn new(
idx_fn: fn(&[u8], &T) -> IK,
pk_namespace: &'a str,
idx_namespace: &'a str,
) -> Self {
MultiIndex {
index: idx_fn,
idx_namespace: idx_namespace.as_bytes(),
idx_map: Map::new(idx_namespace),
pk_namespace: pk_namespace.as_bytes(),
phantom: PhantomData,
}
}
}
fn deserialize_multi_v<T: DeserializeOwned>(
store: &dyn Storage,
pk_namespace: &[u8],
kv: Record,
) -> StdResult<Record<T>> {
let (key, pk_len) = kv;
let pk_len = from_slice::<u32>(pk_len.as_slice())?;
let offset = key.len() - pk_len as usize;
let pk = &key[offset..];
let full_key = namespaces_with_key(&[pk_namespace], pk);
let v = store
.get(&full_key)
.ok_or_else(|| StdError::generic_err("pk not found"))?;
let v = from_slice::<T>(&v)?;
Ok((pk.to_vec(), v))
}
fn deserialize_multi_kv<K: KeyDeserialize, T: DeserializeOwned>(
store: &dyn Storage,
pk_namespace: &[u8],
kv: Record,
) -> StdResult<(K::Output, T)> {
let (key, pk_len) = kv;
let pk_len = from_slice::<u32>(pk_len.as_slice())?;
let offset = key.len() - pk_len as usize;
let pk = &key[offset..];
let full_key = namespaces_with_key(&[pk_namespace], pk);
let v = store
.get(&full_key)
.ok_or_else(|| StdError::generic_err("pk not found"))?;
let v = from_slice::<T>(&v)?;
Ok((K::from_slice(pk)?, v))
}
impl<'a, IK, T, PK> Index<T> for MultiIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a>,
{
fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> {
let idx = (self.index)(pk, data).joined_extra_key(pk);
self.idx_map.save(store, idx, &(pk.len() as u32))
}
fn remove(&self, store: &mut dyn Storage, pk: &[u8], old_data: &T) -> StdResult<()> {
let idx = (self.index)(pk, old_data).joined_extra_key(pk);
self.idx_map.remove(store, idx);
Ok(())
}
}
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a> + Prefixer<'a>,
{
fn no_prefix_raw(&self) -> Prefix<Vec<u8>, T, (IK, PK)> {
Prefix::with_deserialization_functions(
self.idx_namespace,
&[],
self.pk_namespace,
deserialize_multi_v,
deserialize_multi_v,
)
}
}
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
PK: PrimaryKey<'a> + KeyDeserialize,
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a> + Prefixer<'a>,
{
pub fn index_key(&self, k: IK) -> Vec<u8> {
k.joined_extra_key(b"")
}
#[cfg(test)]
pub fn count(&self, store: &dyn Storage, p: IK) -> usize {
let prefix = self.prefix(p);
prefix.keys_raw(store, None, None, Order::Ascending).count()
}
#[cfg(test)]
pub fn all_pks(&self, store: &dyn Storage, p: IK) -> Vec<Vec<u8>> {
let prefix = self.prefix(p);
prefix
.keys_raw(store, None, None, Order::Ascending)
.collect::<Vec<Vec<u8>>>()
}
#[cfg(test)]
pub fn all_items(&self, store: &dyn Storage, p: IK) -> StdResult<Vec<Record<T>>> {
let prefix = self.prefix(p);
prefix
.range_raw(store, None, None, Order::Ascending)
.collect()
}
}
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize,
PK: PrimaryKey<'a> + KeyDeserialize,
{
pub fn range_raw<'c>(
&'c self,
store: &'c dyn Storage,
min: Option<Bound<'a, (IK, PK)>>,
max: Option<Bound<'a, (IK, PK)>>,
order: Order,
) -> Box<dyn Iterator<Item = StdResult<Record<T>>> + 'c>
where
T: 'c,
{
self.no_prefix_raw().range_raw(store, min, max, order)
}
pub fn keys_raw<'c>(
&'c self,
store: &'c dyn Storage,
min: Option<Bound<'a, (IK, PK)>>,
max: Option<Bound<'a, (IK, PK)>>,
order: Order,
) -> Box<dyn Iterator<Item = Vec<u8>> + 'c> {
self.no_prefix_raw().keys_raw(store, min, max, order)
}
pub fn prefix_range_raw<'c>(
&'c self,
store: &'c dyn Storage,
min: Option<PrefixBound<'a, IK>>,
max: Option<PrefixBound<'a, IK>>,
order: cosmwasm_std::Order,
) -> Box<dyn Iterator<Item = StdResult<cosmwasm_std::Record<T>>> + 'c>
where
T: 'c,
'a: 'c,
{
let mapped = namespaced_prefix_range(store, self.idx_namespace, min, max, order)
.map(move |kv| (deserialize_multi_v)(store, self.pk_namespace, kv));
Box::new(mapped)
}
}
#[cfg(feature = "iterator")]
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
PK: PrimaryKey<'a> + KeyDeserialize,
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a> + Prefixer<'a>,
{
pub fn prefix(&self, p: IK) -> Prefix<PK, T, PK> {
Prefix::with_deserialization_functions(
self.idx_namespace,
&p.prefix(),
self.pk_namespace,
deserialize_multi_kv::<PK, T>,
deserialize_multi_v,
)
}
pub fn sub_prefix(&self, p: IK::Prefix) -> Prefix<PK, T, (IK::Suffix, PK)> {
Prefix::with_deserialization_functions(
self.idx_namespace,
&p.prefix(),
self.pk_namespace,
deserialize_multi_kv::<PK, T>,
deserialize_multi_v,
)
}
}
#[cfg(feature = "iterator")]
impl<'a, IK, T, PK> MultiIndex<'a, IK, T, PK>
where
PK: PrimaryKey<'a> + KeyDeserialize,
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a> + KeyDeserialize + Prefixer<'a>,
{
pub fn prefix_range<'c>(
&self,
store: &'c dyn Storage,
min: Option<PrefixBound<'a, IK>>,
max: Option<PrefixBound<'a, IK>>,
order: cosmwasm_std::Order,
) -> Box<dyn Iterator<Item = StdResult<(PK::Output, T)>> + 'c>
where
T: 'c,
'a: 'c,
IK: 'c,
PK: 'c,
PK::Output: 'static,
{
let mapped = namespaced_prefix_range(store, self.idx_namespace, min, max, order)
.map(deserialize_kv::<PK, T>);
Box::new(mapped)
}
pub fn range<'c>(
&self,
store: &'c dyn Storage,
min: Option<Bound<'a, (IK, PK)>>,
max: Option<Bound<'a, (IK, PK)>>,
order: cosmwasm_std::Order,
) -> Box<dyn Iterator<Item = StdResult<(PK::Output, T)>> + 'c>
where
T: 'c,
PK::Output: 'static,
{
self.no_prefix().range(store, min, max, order)
}
pub fn keys<'c>(
&self,
store: &'c dyn Storage,
min: Option<Bound<'a, (IK, PK)>>,
max: Option<Bound<'a, (IK, PK)>>,
order: cosmwasm_std::Order,
) -> Box<dyn Iterator<Item = StdResult<PK::Output>> + 'c>
where
T: 'c,
PK::Output: 'static,
{
self.no_prefix().keys(store, min, max, order)
}
fn no_prefix(&self) -> Prefix<PK, T, (IK, PK)> {
Prefix::with_deserialization_functions(
self.idx_namespace,
&[],
self.pk_namespace,
deserialize_multi_kv::<PK, T>,
deserialize_multi_v,
)
}
}