Add swap and decode_len to DoubleMap finishing #3749 (#4264)

* Add `swap` and `decode_len` to `DoubleMap`

*  Add tests to `swap` and `decode_len` for `DoubleMap` (WIP)

* Address review comments

* Remove function that is not in scope

* fix test

* better naming
This commit is contained in:
thiolliere
2019-12-02 13:01:29 +01:00
committed by Bastian Köcher
parent 810ac845b5
commit 22c00ff424
5 changed files with 109 additions and 2 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
spec_version: 197,
impl_version: 197,
impl_version: 198,
apis: RUNTIME_API_VERSIONS,
};
+30
View File
@@ -292,6 +292,36 @@ mod tests {
});
}
#[test]
fn double_map_swap_works() {
new_test_ext().execute_with(|| {
DataDM::insert(0, 1, 1);
DataDM::insert(1, 0, 2);
DataDM::insert(1, 1, 3);
let get_all = || vec![
DataDM::get(0, 1),
DataDM::get(1, 0),
DataDM::get(1, 1),
DataDM::get(2, 0),
DataDM::get(2, 1),
];
assert_eq!(get_all(), vec![1, 2, 3, 0, 0]);
// Two existing
DataDM::swap(0, 1, 1, 0);
assert_eq!(get_all(), vec![2, 1, 3, 0, 0]);
// Left existing
DataDM::swap(1, 0, 2, 0);
assert_eq!(get_all(), vec![2, 0, 3, 1, 0]);
// Right existing
DataDM::swap(2, 1, 1, 1);
assert_eq!(get_all(), vec![2, 0, 0, 1, 3]);
});
}
#[test]
fn linked_map_basic_insert_remove_should_work() {
new_test_ext().execute_with(|| {
@@ -17,7 +17,7 @@
use rstd::prelude::*;
use rstd::borrow::Borrow;
use codec::{Ref, FullCodec, FullEncode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
/// Generator for `StorageDoubleMap` used by `decl_storage`.
///
@@ -137,6 +137,29 @@ where
G::from_optional_value_to_query(value)
}
fn swap<XKArg1, XKArg2, YKArg1, YKArg2>(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2)
where
XKArg1: EncodeLike<K1>,
XKArg2: EncodeLike<K2>,
YKArg1: EncodeLike<K1>,
YKArg2: EncodeLike<K2>
{
let final_x_key = Self::storage_double_map_final_key(x_k1, x_k2);
let final_y_key = Self::storage_double_map_final_key(y_k1, y_k2);
let v1 = unhashed::get_raw(&final_x_key);
if let Some(val) = unhashed::get_raw(&final_y_key) {
unhashed::put_raw(&final_x_key, &val);
} else {
unhashed::kill(&final_x_key)
}
if let Some(val) = v1 {
unhashed::put_raw(&final_y_key, &val);
} else {
unhashed::kill(&final_y_key)
}
}
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
where
KArg1: EncodeLike<K1>,
@@ -225,4 +248,21 @@ where
Self::append(Ref::from(&k1), Ref::from(&k2), items.clone())
.unwrap_or_else(|_| Self::insert(k1, k2, items));
}
fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Result<usize, &'static str>
where KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
V: codec::DecodeLength + Len,
{
let final_key = Self::storage_double_map_final_key(key1, key2);
if let Some(v) = unhashed::get_raw(&final_key) {
<V as codec::DecodeLength>::len(&v).map_err(|e| e.what())
} else {
let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None))
.map(|v| v.len())
.unwrap_or(0);
Ok(len)
}
}
}
@@ -284,6 +284,14 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
/// Swap the values of two key-pairs.
fn swap<XKArg1, XKArg2, YKArg1, YKArg2>(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2)
where
XKArg1: EncodeLike<K1>,
XKArg2: EncodeLike<K2>,
YKArg1: EncodeLike<K1>,
YKArg2: EncodeLike<K2>;
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
where
KArg1: EncodeLike<K1>,
@@ -330,4 +338,17 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
Items::IntoIter: ExactSizeIterator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `V` is required to implement `Codec::DecodeLength`.
///
/// Note that `0` is returned as the default value if no encoded value exists at the given key.
/// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()`
/// function for this purpose.
fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Result<usize, &'static str>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
V: codec::DecodeLength + Len;
}
@@ -521,6 +521,10 @@ mod test_append_and_len {
MapVecWithDefault: map u32 => Vec<u32> = vec![6, 9];
OptionMapVec: map u32 => Option<Vec<u32>>;
DoubleMapVec: double_map u32, blake2_256(u32) => Vec<u32>;
DoubleMapVecWithDefault: double_map u32, blake2_256(u32) => Vec<u32> = vec![6, 9];
OptionDoubleMapVec: double_map u32, blake2_256(u32) => Option<Vec<u32>>;
LinkedMapVec: linked_map u32 => Vec<u32>;
LinkedMapVecWithDefault: linked_map u32 => Vec<u32> = vec![6, 9];
OptionLinkedMapVec: linked_map u32 => Option<Vec<u32>>;
@@ -596,11 +600,13 @@ mod test_append_and_len {
OptionVec::put(&vec![1, 2, 3, 4, 5]);
MapVec::insert(1, &vec![1, 2, 3, 4, 5, 6]);
LinkedMapVec::insert(2, &vec![1, 2, 3]);
DoubleMapVec::insert(0, 1, &vec![1, 2]);
assert_eq!(JustVec::decode_len().unwrap(), 4);
assert_eq!(OptionVec::decode_len().unwrap(), 5);
assert_eq!(MapVec::decode_len(1).unwrap(), 6);
assert_eq!(LinkedMapVec::decode_len(2).unwrap(), 3);
assert_eq!(DoubleMapVec::decode_len(0, 1).unwrap(), 2);
});
}
@@ -636,6 +642,16 @@ mod test_append_and_len {
assert_eq!(OptionLinkedMapVec::get(0), None);
assert_eq!(OptionLinkedMapVec::decode_len(0), Ok(0));
// Double map
assert_eq!(DoubleMapVec::get(0, 0), vec![]);
assert_eq!(DoubleMapVec::decode_len(0, 1), Ok(0));
assert_eq!(DoubleMapVecWithDefault::get(0, 0), vec![6, 9]);
assert_eq!(DoubleMapVecWithDefault::decode_len(0, 1), Ok(2));
assert_eq!(OptionDoubleMapVec::get(0, 0), None);
assert_eq!(OptionDoubleMapVec::decode_len(0, 1), Ok(0));
});
}
}