#[cfg(feature = "iterator")]
use cosmwasm_std::{Order, KV};
use cosmwasm_std::{ReadonlyStorage, StdResult, Storage};
#[cfg(feature = "iterator")]
use crate::namespace_helpers::range_with_prefix;
use crate::namespace_helpers::{
get_with_prefix, key_prefix, key_prefix_nested, remove_with_prefix, set_with_prefix,
};
pub fn prefixed_read<'a, T: ReadonlyStorage>(
prefix: &[u8],
storage: &'a T,
) -> ReadonlyPrefixedStorage<'a, T> {
ReadonlyPrefixedStorage::new(prefix, storage)
}
pub fn prefixed<'a, T: Storage>(prefix: &[u8], storage: &'a mut T) -> PrefixedStorage<'a, T> {
PrefixedStorage::new(prefix, storage)
}
pub struct ReadonlyPrefixedStorage<'a, T: ReadonlyStorage> {
prefix: Vec<u8>,
storage: &'a T,
}
impl<'a, T: ReadonlyStorage> ReadonlyPrefixedStorage<'a, T> {
pub fn new(namespace: &[u8], storage: &'a T) -> Self {
ReadonlyPrefixedStorage {
prefix: key_prefix(namespace),
storage,
}
}
pub fn multilevel(namespaces: &[&[u8]], storage: &'a T) -> Self {
ReadonlyPrefixedStorage {
prefix: key_prefix_nested(namespaces),
storage,
}
}
}
impl<'a, T: ReadonlyStorage> ReadonlyStorage for ReadonlyPrefixedStorage<'a, T> {
fn get(&self, key: &[u8]) -> StdResult<Option<Vec<u8>>> {
get_with_prefix(self.storage, &self.prefix, key)
}
#[cfg(feature = "iterator")]
fn range<'b>(
&'b self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> StdResult<Box<dyn Iterator<Item = StdResult<KV>> + 'b>> {
range_with_prefix(self.storage, &self.prefix, start, end, order)
}
}
pub struct PrefixedStorage<'a, T: Storage> {
prefix: Vec<u8>,
storage: &'a mut T,
}
impl<'a, T: Storage> PrefixedStorage<'a, T> {
pub fn new(namespace: &[u8], storage: &'a mut T) -> Self {
PrefixedStorage {
prefix: key_prefix(namespace),
storage,
}
}
pub fn multilevel(namespaces: &[&[u8]], storage: &'a mut T) -> Self {
PrefixedStorage {
prefix: key_prefix_nested(namespaces),
storage,
}
}
}
impl<'a, T: Storage> ReadonlyStorage for PrefixedStorage<'a, T> {
fn get(&self, key: &[u8]) -> StdResult<Option<Vec<u8>>> {
get_with_prefix(self.storage, &self.prefix, key)
}
#[cfg(feature = "iterator")]
fn range<'b>(
&'b self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> StdResult<Box<dyn Iterator<Item = StdResult<KV>> + 'b>> {
range_with_prefix(self.storage, &self.prefix, start, end, order)
}
}
impl<'a, T: Storage> Storage for PrefixedStorage<'a, T> {
fn set(&mut self, key: &[u8], value: &[u8]) -> StdResult<()> {
set_with_prefix(self.storage, &self.prefix, key, value)
}
fn remove(&mut self, key: &[u8]) -> StdResult<()> {
remove_with_prefix(self.storage, &self.prefix, key)
}
}
#[cfg(test)]
mod test {
use super::*;
use cosmwasm_std::testing::MockStorage;
#[test]
fn prefix_safe() {
let mut storage = MockStorage::new();
let mut foo = PrefixedStorage::new(b"foo", &mut storage);
foo.set(b"bar", b"gotcha").unwrap();
assert_eq!(Some(b"gotcha".to_vec()), foo.get(b"bar").unwrap());
let rfoo = ReadonlyPrefixedStorage::new(b"foo", &storage);
assert_eq!(Some(b"gotcha".to_vec()), rfoo.get(b"bar").unwrap());
let fo = ReadonlyPrefixedStorage::new(b"fo", &storage);
assert_eq!(None, fo.get(b"obar").unwrap());
}
#[test]
fn multi_level() {
let mut storage = MockStorage::new();
let mut foo = PrefixedStorage::new(b"foo", &mut storage);
let mut bar = PrefixedStorage::new(b"bar", &mut foo);
bar.set(b"baz", b"winner").unwrap();
let loader = ReadonlyPrefixedStorage::multilevel(&[b"foo", b"bar"], &storage);
assert_eq!(Some(b"winner".to_vec()), loader.get(b"baz").unwrap());
let mut foobar = PrefixedStorage::multilevel(&[b"foo", b"bar"], &mut storage);
foobar.set(b"second", b"time").unwrap();
let a = ReadonlyPrefixedStorage::new(b"foo", &storage);
let b = ReadonlyPrefixedStorage::new(b"bar", &a);
assert_eq!(Some(b"time".to_vec()), b.get(b"second").unwrap());
}
}