mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 10:01:17 +00:00
Add translate API for storage values (#3947)
* Add translate item. * fix * doc * fix doc * A test added. * Apply suggestions from code review Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * address suggestion
This commit is contained in:
committed by
Bastian Köcher
parent
a73334f769
commit
073040a053
@@ -30,3 +30,52 @@ pub use linked_map::{StorageLinkedMap, Enumerator, Linkage};
|
||||
pub use map::StorageMap;
|
||||
pub use double_map::StorageDoubleMap;
|
||||
pub use value::StorageValue;
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
mod tests {
|
||||
use runtime_io::TestExternalities;
|
||||
use codec::Encode;
|
||||
use crate::storage::{unhashed, generator::StorageValue};
|
||||
|
||||
struct Runtime {}
|
||||
pub trait Trait {
|
||||
type Origin;
|
||||
type BlockNumber;
|
||||
}
|
||||
|
||||
impl Trait for Runtime {
|
||||
type Origin = u32;
|
||||
type BlockNumber = u32;
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
|
||||
}
|
||||
|
||||
crate::decl_storage! {
|
||||
trait Store for Module<T: Trait> as Runtime {
|
||||
Value get(fn value) config(): (u64, u64);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_translate_works() {
|
||||
let t = GenesisConfig::default().build_storage().unwrap();
|
||||
TestExternalities::new(t).execute_with(|| {
|
||||
// put the old value `1111u32` in the storage.
|
||||
let key = Value::storage_value_final_key();
|
||||
unhashed::put_raw(&key, &1111u32.encode());
|
||||
|
||||
// translate
|
||||
let translate_fn = |old: Option<u32>| -> Option<(u64, u64)> {
|
||||
old.map(|o| (o.into(), (o*2).into()))
|
||||
};
|
||||
let _ = Value::translate(translate_fn);
|
||||
|
||||
// new storage should be `(1111, 1111 * 2)`
|
||||
assert_eq!(Value::get(), (1111, 2222));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use rstd::prelude::*;
|
||||
use codec::{FullCodec, Encode, EncodeAppend, EncodeLike};
|
||||
use codec::{FullCodec, Encode, EncodeAppend, EncodeLike, Decode};
|
||||
use crate::{storage::{self, unhashed}, hash::{Twox128, StorageHasher}, traits::Len};
|
||||
|
||||
/// Generator for `StorageValue` used by `decl_storage`.
|
||||
@@ -60,6 +60,23 @@ impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G {
|
||||
G::from_optional_value_to_query(value)
|
||||
}
|
||||
|
||||
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()> {
|
||||
let key = Self::storage_value_final_key();
|
||||
|
||||
// attempt to get the length directly.
|
||||
let maybe_old = match unhashed::get_raw(&key) {
|
||||
Some(old_data) => Some(O::decode(&mut &old_data[..]).map_err(|_| ())?),
|
||||
None => None,
|
||||
};
|
||||
let maybe_new = f(maybe_old);
|
||||
if let Some(new) = maybe_new.as_ref() {
|
||||
new.using_encoded(|d| unhashed::put_raw(&key, d));
|
||||
} else {
|
||||
unhashed::kill(&key);
|
||||
}
|
||||
Ok(maybe_new)
|
||||
}
|
||||
|
||||
fn put<Arg: EncodeLike<T>>(val: Arg) {
|
||||
unhashed::put(&Self::storage_value_final_key(), &val)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Stuff to do with the runtime's storage.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike};
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode};
|
||||
use crate::traits::Len;
|
||||
|
||||
#[macro_use]
|
||||
@@ -41,6 +41,28 @@ pub trait StorageValue<T: FullCodec> {
|
||||
/// Load the value from the provided storage instance.
|
||||
fn get() -> Self::Query;
|
||||
|
||||
/// Translate a value from some previous type (`O`) to the current type.
|
||||
///
|
||||
/// `f: F` is the translation function.
|
||||
///
|
||||
/// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along
|
||||
/// with the new value if it could.
|
||||
///
|
||||
/// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default
|
||||
/// value of the original type.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This function must be used with care, before being updated the storage still contains the
|
||||
/// old type, thus other calls (such as `get`) will fail at decoding it.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// This would typically be called inside the module implementation of on_initialize, while
|
||||
/// ensuring **no usage of this storage are made before the call to `on_initialize`**. (More
|
||||
/// precisely prior initialized modules doesn't make use of this storage).
|
||||
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()>;
|
||||
|
||||
/// Store a value under this key into the provided storage instance.
|
||||
fn put<Arg: EncodeLike<T>>(val: Arg);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user