#[cfg(feature = "iterator")]
use cosmwasm_std::{Order, KV};
use cosmwasm_std::{ReadonlyStorage, StdResult, Storage};
pub(crate) fn get_with_prefix<S: ReadonlyStorage>(
storage: &S,
namespace: &[u8],
key: &[u8],
) -> StdResult<Option<Vec<u8>>> {
storage.get(&concat(namespace, key))
}
pub(crate) fn set_with_prefix<S: Storage>(
storage: &mut S,
namespace: &[u8],
key: &[u8],
value: &[u8],
) -> StdResult<()> {
storage.set(&concat(namespace, key), value)
}
pub(crate) fn remove_with_prefix<S: Storage>(
storage: &mut S,
namespace: &[u8],
key: &[u8],
) -> StdResult<()> {
storage.remove(&concat(namespace, key))
}
#[inline]
fn concat(namespace: &[u8], key: &[u8]) -> Vec<u8> {
let mut k = namespace.to_vec();
k.extend_from_slice(key);
k
}
#[cfg(feature = "iterator")]
pub(crate) fn range_with_prefix<'a, S: ReadonlyStorage>(
storage: &'a S,
namespace: &[u8],
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> StdResult<Box<dyn Iterator<Item = StdResult<KV>> + 'a>> {
let start = match start {
Some(s) => concat(namespace, s),
None => namespace.to_vec(),
};
let end = match end {
Some(e) => concat(namespace, e),
None => namespace_upper_bound(namespace),
};
let base_iterator = storage.range(Some(&start), Some(&end), order)?;
let prefix = namespace.to_vec();
let mapped = base_iterator.map(move |item| match item {
Ok((k, v)) => Ok((trim(&prefix, &k), v)),
Err(e) => Err(e),
});
Ok(Box::new(mapped))
}
pub(crate) fn key_prefix(namespace: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(namespace.len() + 2);
extend_with_prefix(&mut out, namespace);
out
}
pub(crate) fn key_prefix_nested(namespaces: &[&[u8]]) -> Vec<u8> {
let mut size = namespaces.len();
for &namespace in namespaces {
size += namespace.len() + 2;
}
let mut out = Vec::with_capacity(size);
for &namespace in namespaces {
extend_with_prefix(&mut out, namespace);
}
out
}
fn extend_with_prefix(out: &mut Vec<u8>, namespace: &[u8]) {
out.extend_from_slice(&key_len(namespace));
out.extend_from_slice(namespace);
}
fn key_len(prefix: &[u8]) -> [u8; 2] {
if prefix.len() > 0xFFFF {
panic!("only supports namespaces up to length 0xFFFF")
}
let length_bytes = (prefix.len() as u64).to_be_bytes();
[length_bytes[6], length_bytes[7]]
}
#[cfg(feature = "iterator")]
#[inline]
fn trim(namespace: &[u8], key: &[u8]) -> Vec<u8> {
key[namespace.len()..].to_vec()
}
#[cfg(feature = "iterator")]
fn namespace_upper_bound(input: &[u8]) -> Vec<u8> {
let mut copy = input.to_vec();
for i in (0..input.len()).rev() {
if copy[i] == 255 {
copy[i] = 0;
} else {
copy[i] += 1;
break;
}
}
copy
}
#[cfg(test)]
mod test {
use super::*;
use cosmwasm_std::testing::MockStorage;
#[test]
fn key_prefix_works() {
assert_eq!(key_prefix(b""), b"\x00\x00");
assert_eq!(key_prefix(b"a"), b"\x00\x01a");
assert_eq!(key_prefix(b"ab"), b"\x00\x02ab");
assert_eq!(key_prefix(b"abc"), b"\x00\x03abc");
}
#[test]
fn key_prefix_works_for_long_prefix() {
let long_namespace1 = vec![0; 256];
let prefix1 = key_prefix(&long_namespace1);
assert_eq!(prefix1.len(), 256 + 2);
assert_eq!(&prefix1[0..2], b"\x01\x00");
let long_namespace2 = vec![0; 30000];
let prefix2 = key_prefix(&long_namespace2);
assert_eq!(prefix2.len(), 30000 + 2);
assert_eq!(&prefix2[0..2], b"\x75\x30");
let long_namespace3 = vec![0; 0xFFFF];
let prefix3 = key_prefix(&long_namespace3);
assert_eq!(prefix3.len(), 0xFFFF + 2);
assert_eq!(&prefix3[0..2], b"\xFF\xFF");
}
#[test]
#[should_panic(expected = "only supports namespaces up to length 0xFFFF")]
fn key_prefix_panics_for_too_long_prefix() {
let limit = 0xFFFF;
let long_namespace = vec![0; limit + 1];
key_prefix(&long_namespace);
}
#[test]
fn key_prefix_nested_works() {
assert_eq!(key_prefix_nested(&[]), b"");
assert_eq!(key_prefix_nested(&[b""]), b"\x00\x00");
assert_eq!(key_prefix_nested(&[b"", b""]), b"\x00\x00\x00\x00");
assert_eq!(key_prefix_nested(&[b"a"]), b"\x00\x01a");
assert_eq!(key_prefix_nested(&[b"a", b"ab"]), b"\x00\x01a\x00\x02ab");
assert_eq!(
key_prefix_nested(&[b"a", b"ab", b"abc"]),
b"\x00\x01a\x00\x02ab\x00\x03abc"
);
}
#[test]
fn prefix_get_set() {
let mut storage = MockStorage::new();
let prefix = key_prefix(b"foo");
set_with_prefix(&mut storage, &prefix, b"bar", b"gotcha").unwrap();
let rfoo = get_with_prefix(&storage, &prefix, b"bar").unwrap();
assert_eq!(Some(b"gotcha".to_vec()), rfoo);
let other_prefix = key_prefix(b"fo");
let collision = get_with_prefix(&storage, &other_prefix, b"obar").unwrap();
assert_eq!(None, collision);
}
#[test]
#[cfg(feature = "iterator")]
fn test_range() {
let mut storage = MockStorage::new();
let prefix = key_prefix(b"foo");
let other_prefix = key_prefix(b"food");
set_with_prefix(&mut storage, &prefix, b"bar", b"none").unwrap();
set_with_prefix(&mut storage, &prefix, b"snowy", b"day").unwrap();
set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy").unwrap();
let mut iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending).unwrap();
let first = iter.next().unwrap().unwrap();
assert_eq!(first, (b"snowy".to_vec(), b"day".to_vec()));
let second = iter.next().unwrap().unwrap();
assert_eq!(second, (b"bar".to_vec(), b"none".to_vec()));
assert!(iter.next().is_none());
let iter = storage.range(None, None, Order::Ascending).unwrap();
assert_eq!(3, iter.count());
let mut iter = storage.range(None, None, Order::Ascending).unwrap();
let first = iter.next().unwrap().unwrap();
let expected_key = concat(&prefix, b"bar");
assert_eq!(first, (expected_key, b"none".to_vec()));
}
#[test]
#[cfg(feature = "iterator")]
fn test_range_with_prefix_wrapover() {
let mut storage = MockStorage::new();
let prefix = key_prefix(b"f\xff\xff");
let other_prefix = key_prefix(b"f\xff\x44");
set_with_prefix(&mut storage, &prefix, b"bar", b"none").unwrap();
set_with_prefix(&mut storage, &prefix, b"snowy", b"day").unwrap();
set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy").unwrap();
let iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending).unwrap();
let elements: Vec<KV> = iter.filter_map(StdResult::ok).collect();
assert_eq!(
elements,
vec![
(b"snowy".to_vec(), b"day".to_vec()),
(b"bar".to_vec(), b"none".to_vec()),
]
);
}
#[test]
#[cfg(feature = "iterator")]
fn test_range_with_start_end_set() {
let mut storage = MockStorage::new();
let prefix = key_prefix(b"f\xff\xff");
let other_prefix = key_prefix(b"f\xff\x44");
set_with_prefix(&mut storage, &prefix, b"bar", b"none").unwrap();
set_with_prefix(&mut storage, &prefix, b"snowy", b"day").unwrap();
set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy").unwrap();
let res: Vec<KV> =
range_with_prefix(&storage, &prefix, Some(b"b"), Some(b"c"), Order::Ascending)
.unwrap()
.filter_map(StdResult::ok)
.collect();
assert_eq!(res.len(), 1);
assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec()));
let res: Vec<KV> = range_with_prefix(
&storage,
&prefix,
Some(b"bas"),
Some(b"sno"),
Order::Ascending,
)
.unwrap()
.filter_map(StdResult::ok)
.collect();
assert_eq!(res.len(), 0);
let res: Vec<KV> =
range_with_prefix(&storage, &prefix, Some(b"ant"), None, Order::Ascending)
.unwrap()
.filter_map(StdResult::ok)
.collect();
assert_eq!(res.len(), 2);
assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec()));
assert_eq!(res[1], (b"snowy".to_vec(), b"day".to_vec()));
}
#[test]
#[cfg(feature = "iterator")]
fn test_namespace_upper_bound() {
assert_eq!(namespace_upper_bound(b"bob"), b"boc".to_vec());
assert_eq!(namespace_upper_bound(b"fo\xfe"), b"fo\xff".to_vec());
assert_eq!(namespace_upper_bound(b"fo\xff"), b"fp\x00".to_vec());
assert_eq!(
namespace_upper_bound(b"fo\xff\xff\xff"),
b"fp\x00\x00\x00".to_vec()
);
assert_eq!(namespace_upper_bound(b"\xffabc"), b"\xffabd".to_vec());
}
}