#![allow(deprecated)]
mod entry;
mod impls;
mod iter;
use std::borrow::Borrow;
use std::{fmt, mem};
use borsh::{BorshDeserialize, BorshSerialize};
use unc_sdk_macros::unc;
use crate::store::key::{Sha256, ToKey};
use crate::{env, IntoStorageKey};
pub use entry::{Entry, OccupiedEntry, VacantEntry};
pub use self::iter::{Drain, Iter, IterMut, Keys, Values, ValuesMut};
use super::free_list::FreeListIndex;
use super::{FreeList, LookupMap, ERR_INCONSISTENT_STATE, ERR_NOT_EXIST};
#[deprecated(
since = "2.0.0",
note = "Suboptimal iteration performance. See performance considerations doc for details."
)]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct UnorderedMap<K, V, H = Sha256>
where
K: BorshSerialize + Ord,
V: BorshSerialize,
H: ToKey,
{
#[borsh(bound(serialize = "", deserialize = ""))]
keys: FreeList<K>,
#[borsh(bound(serialize = "", deserialize = ""))]
values: LookupMap<K, ValueAndIndex<V>, H>,
}
#[unc(inside_uncsdk)]
struct ValueAndIndex<V> {
value: V,
key_index: FreeListIndex,
}
impl<K, V, H> Drop for UnorderedMap<K, V, H>
where
K: BorshSerialize + Ord,
V: BorshSerialize,
H: ToKey,
{
fn drop(&mut self) {
self.flush()
}
}
impl<K, V, H> fmt::Debug for UnorderedMap<K, V, H>
where
K: BorshSerialize + Ord + BorshDeserialize + fmt::Debug,
V: BorshSerialize,
H: ToKey,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UnorderedMap")
.field("keys", &self.keys)
.field("values", &self.values)
.finish()
}
}
impl<K, V> UnorderedMap<K, V, Sha256>
where
K: BorshSerialize + Ord,
V: BorshSerialize,
{
#[inline]
pub fn new<S>(prefix: S) -> Self
where
S: IntoStorageKey,
{
Self::with_hasher(prefix)
}
}
impl<K, V, H> UnorderedMap<K, V, H>
where
K: BorshSerialize + Ord,
V: BorshSerialize,
H: ToKey,
{
pub fn with_hasher<S>(prefix: S) -> Self
where
S: IntoStorageKey,
{
let mut vec_key = prefix.into_storage_key();
let map_key = [vec_key.as_slice(), b"m"].concat();
vec_key.push(b'v');
Self { keys: FreeList::new(vec_key), values: LookupMap::with_hasher(map_key) }
}
pub fn len(&self) -> u32 {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
}
pub fn clear(&mut self)
where
K: BorshDeserialize + Clone,
V: BorshDeserialize,
{
for k in self.keys.drain() {
self.values.set(k, None);
}
}
pub fn iter(&self) -> Iter<K, V, H>
where
K: BorshDeserialize,
{
Iter::new(self)
}
pub fn iter_mut(&mut self) -> IterMut<K, V, H>
where
K: BorshDeserialize,
{
IterMut::new(self)
}
pub fn keys(&self) -> Keys<K>
where
K: BorshDeserialize,
{
Keys::new(self)
}
pub fn values(&self) -> Values<K, V, H>
where
K: BorshDeserialize,
{
Values::new(self)
}
pub fn values_mut(&mut self) -> ValuesMut<K, V, H>
where
K: BorshDeserialize,
{
ValuesMut::new(self)
}
pub fn drain(&mut self) -> Drain<K, V, H>
where
K: BorshDeserialize,
{
Drain::new(self)
}
}
impl<K, V, H> UnorderedMap<K, V, H>
where
K: BorshSerialize + Ord,
V: BorshSerialize + BorshDeserialize,
H: ToKey,
{
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: BorshSerialize + ToOwned<Owned = K>,
{
self.values.get(k).map(|v| &v.value)
}
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: BorshSerialize + ToOwned<Owned = K>,
{
self.values.get_mut(k).map(|v| &mut v.value)
}
pub fn insert(&mut self, k: K, value: V) -> Option<V>
where
K: Clone + BorshDeserialize,
{
let entry = self.values.get_mut_inner(&k);
if let Some(existing) = entry.value_mut() {
return Some(mem::replace(&mut existing.value, value));
}
let key_index = self.keys.insert(k);
entry.replace(Some(ValueAndIndex { value, key_index }));
None
}
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: BorshSerialize + ToOwned<Owned = K> + Ord,
{
self.values.contains_key(k)
}
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q> + BorshDeserialize,
Q: BorshSerialize + ToOwned<Owned = K>,
{
self.remove_entry(k).map(|(_, v)| v)
}
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
where
K: Borrow<Q> + BorshDeserialize,
Q: BorshSerialize + ToOwned<Owned = K>,
{
let old_value = self.values.remove(k)?;
let key = self
.keys
.remove(old_value.key_index)
.unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE));
Some((key, old_value.value))
}
pub fn entry(&mut self, key: K) -> Entry<K, V>
where
K: Clone,
{
Entry::new(self.values.entry(key), &mut self.keys)
}
}
impl<K, V, H> UnorderedMap<K, V, H>
where
K: BorshSerialize + Ord,
V: BorshSerialize,
H: ToKey,
{
pub fn flush(&mut self) {
self.keys.flush();
self.values.flush();
}
}
impl<K, V, H> UnorderedMap<K, V, H>
where
K: BorshSerialize + BorshDeserialize + Ord + Clone,
V: BorshSerialize + BorshDeserialize,
H: ToKey,
{
pub fn defrag(&mut self) {
self.keys.defrag(|key, new_index| {
if let Some(existing) = self.values.get_mut(key) {
existing.key_index = FreeListIndex(new_index);
}
});
}
}
#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
use super::UnorderedMap;
use crate::test_utils::test_env::setup_free;
use arbitrary::{Arbitrary, Unstructured};
use borsh::{to_vec, BorshDeserialize};
use rand::RngCore;
use rand::SeedableRng;
use std::collections::HashMap;
#[test]
fn basic_functionality() {
let mut map = UnorderedMap::new(b"b");
assert!(map.is_empty());
assert!(map.insert("test".to_string(), 5u8).is_none());
assert_eq!(map.get("test"), Some(&5));
assert_eq!(map.len(), 1);
*map.get_mut("test").unwrap() = 6;
assert_eq!(map["test"], 6);
assert_eq!(map.remove("test"), Some(6));
assert_eq!(map.len(), 0);
}
#[test]
fn entry_api() {
let mut map = UnorderedMap::new(b"b");
{
let test_entry = map.entry("test".to_string());
assert_eq!(test_entry.key(), "test");
let entry_ref = test_entry.or_insert(8u8);
*entry_ref += 1;
}
assert_eq!(map["test"], 9);
let value = map.entry("test".to_string()).and_modify(|v| *v += 3).or_default();
assert_eq!(*value, 12);
}
#[test]
fn map_iterator() {
let mut map = UnorderedMap::new(b"b");
map.insert(0u8, 0u8);
map.insert(1, 1);
map.insert(2, 2);
map.insert(3, 3);
map.remove(&1);
let iter = map.iter();
assert_eq!(iter.len(), 3);
assert_eq!(iter.collect::<Vec<_>>(), [(&0, &0), (&2, &2), (&3, &3)]);
let iter = map.iter_mut().rev();
assert_eq!(iter.collect::<Vec<_>>(), [(&3, &mut 3), (&2, &mut 2), (&0, &mut 0)]);
let mut iter = map.iter();
assert_eq!(iter.nth(2), Some((&3, &3)));
assert_eq!(iter.next(), None);
map.values_mut().for_each(|v| {
*v *= 2;
});
assert_eq!(map.values().collect::<Vec<_>>(), [&0, &4, &6]);
assert_eq!(map.keys().collect::<Vec<_>>(), [&0, &2, &3]);
}
#[derive(Arbitrary, Debug)]
enum Op {
Insert(u8, u8),
Remove(u8),
Flush,
Restore,
Get(u8),
}
#[test]
fn arbitrary() {
setup_free();
let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
let mut buf = vec![0; 4096];
for _ in 0..512 {
crate::mock::with_mocked_blockchain(|b| b.take_storage());
rng.fill_bytes(&mut buf);
let mut um = UnorderedMap::new(b"l");
let mut hm = HashMap::new();
let u = Unstructured::new(&buf);
if let Ok(ops) = Vec::<Op>::arbitrary_take_rest(u) {
for op in ops {
match op {
Op::Insert(k, v) => {
let r1 = um.insert(k, v);
let r2 = hm.insert(k, v);
assert_eq!(r1, r2)
}
Op::Remove(k) => {
let r1 = um.remove(&k);
let r2 = hm.remove(&k);
assert_eq!(r1, r2)
}
Op::Flush => {
um.flush();
}
Op::Restore => {
let serialized = to_vec(&um).unwrap();
um = UnorderedMap::deserialize(&mut serialized.as_slice()).unwrap();
}
Op::Get(k) => {
let r1 = um.get(&k);
let r2 = hm.get(&k);
assert_eq!(r1, r2)
}
}
}
}
}
}
#[test]
fn defrag() {
let mut map = UnorderedMap::new(b"b");
let all_indices = 0..=8;
for i in all_indices {
map.insert(i, i);
}
let removed = [2, 4, 6];
let existing = [0, 1, 3, 5, 7, 8];
for id in removed {
map.remove(&id);
}
map.defrag();
for i in removed {
assert_eq!(map.get(&i), None);
}
for i in existing {
assert_eq!(map.get(&i), Some(&i));
}
assert_eq!(map.remove_entry(&7).unwrap(), (7, 7));
assert_eq!(map.remove_entry(&8).unwrap(), (8, 8));
assert_eq!(map.remove_entry(&1).unwrap(), (1, 1));
assert_eq!(map.remove_entry(&3).unwrap(), (3, 3));
}
}