Use optimized append and len storage methods in SRML. (#3071)

* expose len from codec to storage.

* refactor runtime with len and append.

* Undo example.

* Remove imports.

* Bump codec.

* Optionify.

* Make decode_len counscious.

* Refactor.

* Update srml/support/src/storage/hashed/generator.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/support/src/storage/hashed/generator.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/support/src/storage/hashed/generator.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/support/src/storage/hashed/generator.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Fix merge.

* fix some docs.

* Add NoDefault trait.

* Bump.

* Final nits.

* Update srml/support/src/traits.rs

* new approach toward len.

* re-create lock file.

* Fix build errors and Option handling.

* More test fix

* Use default for append as well.

* Fix runtime.

* Add support for linked_map

* More tweaks from review.

* Fix style

* Change api for none-values

* Bump.
This commit is contained in:
Kian Paimani
2019-08-27 19:39:05 +02:00
committed by Bastian Köcher
parent 99a7492dbf
commit 095c7de7ff
13 changed files with 573 additions and 179 deletions
+2 -1
View File
@@ -62,7 +62,8 @@ mod double_map;
pub mod traits;
pub use self::storage::{
StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap, AppendableStorageMap
StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap, AppendableStorageMap,
DecodeLengthStorageMap,
};
pub use self::hashable::Hashable;
pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType};
@@ -14,12 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Abstract storage to use on HashedStorage trait
//! Abstract storage to use on HashedStorage trait. Please refer to the
//! [top level docs](../../index.html) for more detailed documentation about storage traits and functions.
use crate::codec::{self, Encode};
use crate::rstd::prelude::{Vec, Box};
use crate::rstd::{prelude::{Vec, Box}, iter::FromIterator};
#[cfg(feature = "std")]
use crate::storage::unhashed::generator::UnhashedStorage;
use crate::traits::{StorageDefault, Len};
use runtime_io::{twox_64, twox_128, blake2_128, twox_256, blake2_256};
pub trait StorageHasher: 'static {
@@ -164,6 +166,9 @@ impl<H: StorageHasher> HashedStorage<H> for sr_primitives::StorageOverlay {
pub trait StorageValue<T: codec::Codec> {
/// The type that get/take returns.
type Query;
/// Something that can provide the default value of this storage type.
type Default: StorageDefault<T>;
/// Get the storage key.
fn key() -> &'static [u8];
@@ -202,24 +207,75 @@ pub trait StorageValue<T: codec::Codec> {
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<S: HashedStorage<Twox128>, I: codec::Encode>(
items: &[I], storage: &mut S
) -> Result<(), &'static str> where T: codec::EncodeAppend<Item=I> {
fn append<'a, S, I, R>(
items: R,
storage: &mut S,
) -> Result<(), &'static str> where
S: HashedStorage<Twox128>,
I: 'a + codec::Encode,
T: codec::EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I>,
R::IntoIter: ExactSizeIterator,
{
let new_val = <T as codec::EncodeAppend>::append(
storage.get_raw(Self::key()).unwrap_or_default(),
// if the key exists, directly append to it.
storage.get_raw(Self::key()).unwrap_or_else(|| {
// otherwise, try and read a proper __provided__ default.
Self::Default::default().map(|v| v.encode())
// or just use the Rust's `default()` value.
.unwrap_or_default()
}),
items,
).map_err(|_| "Could not append given item")?;
storage.put_raw(Self::key(), &new_val);
Ok(())
}
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
/// old (presumably corrupt) value is replaced with the given `items`.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append_or_put<'a, S, I, R>(
items: R,
storage: &mut S,
) where
S: HashedStorage<Twox128>,
I: 'a + codec::Encode + Clone,
T: codec::EncodeAppend<Item=I> + FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
Self::append(items.clone(), storage)
.unwrap_or_else(|_| Self::put(&items.into_iter().cloned().collect(), storage));
}
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` 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<S: HashedStorage<Twox128>>(storage: &mut S) -> Result<usize, &'static str>
where T: codec::DecodeLength, T: Len
{
// attempt to get the length directly.
if let Some(k) = storage.get_raw(Self::key()) {
<T as codec::DecodeLength>::len(&k).map_err(|e| e.what())
} else {
Ok(Self::Default::default().map(|v| v.len()).unwrap_or(0))
}
}
}
/// A strongly-typed map in storage.
pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
/// The type that get/take returns.
type Query;
/// Hasher type
type Hasher: StorageHasher;
/// Something that can provide the default value of this storage type.
type Default: StorageDefault<V>;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8];
@@ -295,16 +351,69 @@ pub trait EnumerableStorageMap<K: codec::Codec, V: codec::Codec>: StorageMap<K,
pub trait AppendableStorageMap<K: codec::Codec, V: codec::Codec>: StorageMap<K, V> {
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<S: HashedStorage<Self::Hasher>, I: codec::Encode>(
key : &K, items: &[I], storage: &mut S
) -> Result<(), &'static str> where V: codec::EncodeAppend<Item=I> {
/// `V` is required to implement `codec::EncodeAppend`.
fn append<'a, S, I, R>(
key : &K,
items: R,
storage: &mut S,
) -> Result<(), &'static str> where
S: HashedStorage<Self::Hasher>,
I: 'a + codec::Encode,
V: codec::EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
let k = Self::key_for(key);
let new_val = <V as codec::EncodeAppend>::append(
storage.get_raw(&k[..]).unwrap_or_default(),
storage.get_raw(&k[..]).unwrap_or_else(|| {
// otherwise, try and read a proper __provided__ default.
Self::Default::default().map(|v| v.encode())
// or just use the default value.
.unwrap_or_default()
}),
items,
).map_err(|_| "Could not append given item")?;
storage.put_raw(&k[..], &new_val);
Ok(())
}
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
/// old (presumably corrupt) value is replaced with the given `items`.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append_or_insert<'a, S, I, R>(
key : &K,
items: R,
storage: &mut S,
) where
S: HashedStorage<Self::Hasher>,
I: 'a + codec::Encode + Clone,
V: codec::EncodeAppend<Item=I> + crate::rstd::iter::FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
Self::append(key, items.clone(), storage)
.unwrap_or_else(|_| Self::insert(key, &items.into_iter().cloned().collect(), storage));
}
}
/// A storage map with a decodable length.
pub trait DecodeLengthStorageMap<K: codec::Codec, V: codec::Codec>: StorageMap<K, V> {
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` 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<S: HashedStorage<Self::Hasher>>(key: &K, storage: &mut S) -> Result<usize, &'static str>
where V: codec::DecodeLength, V: Len
{
let k = Self::key_for(key);
if let Some(v) = storage.get_raw(&k[..]) {
<V as codec::DecodeLength>::len(&v).map_err(|e| e.what())
} else {
Ok(Self::Default::default().map(|v| v.len()).unwrap_or(0))
}
}
}
+125 -9
View File
@@ -17,10 +17,11 @@
//! Stuff to do with the runtime's storage.
use crate::rstd::prelude::*;
use crate::rstd::borrow::Borrow;
use crate::rstd::{borrow::Borrow, iter::FromIterator};
use codec::{Codec, Encode, Decode, KeyedVec, EncodeAppend};
use hashed::generator::{HashedStorage, StorageHasher};
use unhashed::generator::UnhashedStorage;
use crate::traits::{StorageDefault, Len};
#[macro_use]
pub mod storage_items;
@@ -107,6 +108,8 @@ impl UnhashedStorage for RuntimeStorage {
pub trait StorageValue<T: Codec> {
/// The type that get/take return.
type Query;
/// Something that can provide the default value of this storage type.
type Default: StorageDefault<T>;
/// Get the storage key.
fn key() -> &'static [u8];
@@ -136,12 +139,39 @@ pub trait StorageValue<T: Codec> {
/// Append the given item to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<I: Encode>(items: &[I]) -> Result<(), &'static str>
where T: EncodeAppend<Item=I>;
fn append<'a, I, R>(items: R) -> Result<(), &'static str> where
I: 'a + Encode,
T: EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I>,
R::IntoIter: ExactSizeIterator;
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `Codec::EncodeAppend`.
///
/// Upon any failure, it replaces `items` as the new value (assuming that the previous stored
/// data is simply corrupt and no longer usable).
///
/// ### WARNING
///
/// use with care; if your use-case is not _exactly_ as what this function is doing,
/// you should use append and sensibly handle failure within the runtime code if it happens.
fn append_or_put<'a, I, R>(items: R) where
I: 'a + Encode + Clone,
T: EncodeAppend<Item=I> + FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
fn decode_len() -> Result<usize, &'static str>
where T: codec::DecodeLength, T: Len;
}
impl<T: Codec, U> StorageValue<T> for U where U: hashed::generator::StorageValue<T> {
type Query = U::Query;
type Default = U::Default;
fn key() -> &'static [u8] {
<U as hashed::generator::StorageValue<T>>::key()
@@ -167,17 +197,35 @@ impl<T: Codec, U> StorageValue<T> for U where U: hashed::generator::StorageValue
fn take() -> Self::Query {
U::take(&mut RuntimeStorage)
}
fn append<I: Encode>(items: &[I]) -> Result<(), &'static str>
where T: EncodeAppend<Item=I>
fn append<'a, I, R>(items: R) -> Result<(), &'static str> where
I: 'a + Encode,
T: EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I>,
R::IntoIter: ExactSizeIterator,
{
U::append(items, &mut RuntimeStorage)
}
fn append_or_put<'a, I, R>(items: R) where
I: 'a + Encode + Clone,
T: EncodeAppend<Item=I> + FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
U::append_or_put(items, &mut RuntimeStorage)
}
fn decode_len() -> Result<usize, &'static str>
where T: codec::DecodeLength, T: Len
{
U::decode_len(&mut RuntimeStorage)
}
}
/// A strongly-typed map in storage.
pub trait StorageMap<K: Codec, V: Codec> {
/// The type that get/take return.
type Query;
/// Something that can provide the default value of this storage type.
type Default: StorageDefault<V>;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8];
@@ -213,6 +261,7 @@ pub trait StorageMap<K: Codec, V: Codec> {
impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: hashed::generator::StorageMap<K, V> {
type Query = U::Query;
type Default = U::Default;
fn prefix() -> &'static [u8] {
<U as hashed::generator::StorageMap<K, V>>::prefix()
@@ -260,18 +309,85 @@ pub trait AppendableStorageMap<K: Codec, V: Codec>: StorageMap<K, V> {
/// Append the given item to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<KeyArg: Borrow<K>, I: Encode>(key: KeyArg, items: &[I]) -> Result<(), &'static str>
where V: EncodeAppend<Item=I>;
fn append<'a, KeyArg, I, R>(
key: KeyArg,
items: R,
) -> Result<(), &'static str> where
KeyArg: Borrow<K>,
I: 'a + codec::Encode,
V: EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator;
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
///
/// Upon any failure, it replaces `items` as the new value (assuming that the previous stored
/// data is simply corrupt and no longer usable).
///
/// WARNING: use with care; if your use-case is not _exactly_ as what this function is doing,
/// you should use append and sensibly handle failure within the runtime code if it happens.
fn append_or_insert<'a, KeyArg, I, R>(
key: KeyArg,
items: R,
) where
KeyArg: Borrow<K>,
I: 'a + codec::Encode + Clone,
V: codec::EncodeAppend<Item=I> + FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator;
}
impl<K: Codec, V: Codec, U> AppendableStorageMap<K, V> for U
where U: hashed::generator::AppendableStorageMap<K, V>
{
fn append<KeyArg: Borrow<K>, I: Encode>(key: KeyArg, items: &[I]) -> Result<(), &'static str>
where V: EncodeAppend<Item=I>
fn append<'a, KeyArg, I, R>(
key: KeyArg,
items: R,
) -> Result<(), &'static str> where
KeyArg: Borrow<K>,
I: 'a + codec::Encode,
V: EncodeAppend<Item=I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
U::append(key.borrow(), items, &mut RuntimeStorage)
}
fn append_or_insert<'a, KeyArg, I, R>(
key: KeyArg,
items: R,
) where
KeyArg: Borrow<K>,
I: 'a + codec::Encode + Clone,
V: codec::EncodeAppend<Item=I> + FromIterator<I>,
R: IntoIterator<Item=&'a I> + Clone,
R::IntoIter: ExactSizeIterator,
{
U::append_or_insert(key.borrow(), items, &mut RuntimeStorage)
}
}
/// A storage map with a decodable length.
pub trait DecodeLengthStorageMap<K: Codec, V: Codec>: StorageMap<K, V> {
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
///
/// Has the same logic as [`StorageValue`](trait.StorageValue.html).
fn decode_len<KeyArg: Borrow<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength, V: Len;
}
impl <K: Codec, V: Codec, U> DecodeLengthStorageMap<K, V> for U
where U: hashed::generator::DecodeLengthStorageMap<K, V>
{
fn decode_len<KeyArg: Borrow<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength, V: Len
{
U::decode_len(key.borrow(), &mut RuntimeStorage)
}
}
/// A storage map that can be enumerated.
@@ -172,6 +172,7 @@ macro_rules! __storage_items_internal {
impl $crate::storage::hashed::generator::StorageValue<$ty> for $name {
type Query = $gettype;
type Default = ();
/// Get the storage key.
fn key() -> &'static [u8] {
@@ -221,8 +222,8 @@ macro_rules! __storage_items_internal {
impl $crate::storage::hashed::generator::StorageMap<$kty, $ty> for $name {
type Query = $gettype;
type Hasher = $crate::Blake2_256;
type Default = ();
/// Get the prefix key in storage.
fn prefix() -> &'static [u8] {
@@ -795,18 +796,41 @@ mod test3 {
#[cfg(test)]
#[allow(dead_code)]
mod test_map_vec_append {
mod test_append_and_len {
use crate::storage::{AppendableStorageMap, DecodeLengthStorageMap, StorageMap, StorageValue};
use runtime_io::{with_externalities, TestExternalities};
use codec::{Encode, Decode};
pub trait Trait {
type Origin;
type BlockNumber;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
struct NoDef(u32);
crate::decl_storage! {
trait Store for Module<T: Trait> as Test {
NoDefault: Option<NoDef>;
JustVec: Vec<u32>;
JustVecWithDefault: Vec<u32> = vec![6, 9];
OptionVec: Option<Vec<u32>>;
OptionVecWithDefault: Option<Vec<u32>> = Some(vec![6, 9]);
MapVec: map u32 => Vec<u32>;
MapVecWithDefault: map u32 => Vec<u32> = vec![6, 9];
OptionMapVec: map u32 => Option<Vec<u32>>;
OptionMapVecWithDefault: map u32 => Option<Vec<u32>> = Some(vec![6, 9]);
LinkedMapVec: linked_map u32 => Vec<u32>;
LinkedMapVecWithDefault: linked_map u32 => Vec<u32> = vec![6, 9];
OptionLinkedMapVec: linked_map u32 => Option<Vec<u32>>;
OptionLinkedMapVecWithDefault: linked_map u32 => Option<Vec<u32>> = Some(vec![6, 9]);
}
}
@@ -818,20 +842,115 @@ mod test_map_vec_append {
}
#[test]
fn append_works() {
use crate::storage::{AppendableStorageMap, StorageMap, StorageValue};
use runtime_io::{with_externalities, TestExternalities};
fn default_for_option() {
with_externalities(&mut TestExternalities::default(), || {
let _ = MapVec::append(1, &[1, 2, 3]);
let _ = MapVec::append(1, &[4, 5]);
assert_eq!(OptionVecWithDefault::get(), Some(vec![6, 9]));
assert_eq!(OptionVec::get(), None);
assert_eq!(JustVec::get(), vec![]);
});
}
#[test]
fn append_works() {
with_externalities(&mut TestExternalities::default(), || {
let _ = MapVec::append(1, [1, 2, 3].iter());
let _ = MapVec::append(1, [4, 5].iter());
assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]);
let _ = JustVec::append(&[1, 2, 3]);
let _ = JustVec::append(&[4, 5]);
let _ = JustVec::append([1, 2, 3].iter());
let _ = JustVec::append([4, 5].iter());
assert_eq!(JustVec::get(), vec![1, 2, 3, 4, 5]);
});
}
#[test]
fn append_works_for_default() {
with_externalities(&mut TestExternalities::default(), || {
assert_eq!(JustVecWithDefault::get(), vec![6, 9]);
let _ = JustVecWithDefault::append([1].iter());
assert_eq!(JustVecWithDefault::get(), vec![6, 9, 1]);
assert_eq!(MapVecWithDefault::get(0), vec![6, 9]);
let _ = MapVecWithDefault::append(0, [1].iter());
assert_eq!(MapVecWithDefault::get(0), vec![6, 9, 1]);
assert_eq!(OptionVec::get(), None);
let _ = OptionVec::append([1].iter());
assert_eq!(OptionVec::get(), Some(vec![1]));
});
}
#[test]
fn append_or_put_works() {
with_externalities(&mut TestExternalities::default(), || {
let _ = MapVec::append_or_insert(1, [1, 2, 3].iter());
let _ = MapVec::append_or_insert(1, [4, 5].iter());
assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]);
let _ = JustVec::append_or_put([1, 2, 3].iter());
let _ = JustVec::append_or_put([4, 5].iter());
assert_eq!(JustVec::get(), vec![1, 2, 3, 4, 5]);
});
}
#[test]
fn len_works() {
with_externalities(&mut TestExternalities::default(), || {
JustVec::put(&vec![1, 2, 3, 4]);
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]);
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);
});
}
#[test]
fn len_works_for_default() {
with_externalities(&mut TestExternalities::default(), || {
// vec
assert_eq!(JustVec::get(), vec![]);
assert_eq!(JustVec::decode_len(), Ok(0));
assert_eq!(JustVecWithDefault::get(), vec![6, 9]);
assert_eq!(JustVecWithDefault::decode_len(), Ok(2));
assert_eq!(OptionVec::get(), None);
assert_eq!(OptionVec::decode_len(), Ok(0));
assert_eq!(OptionVecWithDefault::get(), Some(vec![6, 9]));
assert_eq!(OptionVecWithDefault::decode_len(), Ok(2));
// map
assert_eq!(MapVec::get(0), vec![]);
assert_eq!(MapVec::decode_len(0), Ok(0));
assert_eq!(MapVecWithDefault::get(0), vec![6, 9]);
assert_eq!(MapVecWithDefault::decode_len(0), Ok(2));
assert_eq!(OptionMapVec::get(0), None);
assert_eq!(OptionMapVec::decode_len(0), Ok(0));
assert_eq!(OptionMapVecWithDefault::get(0), Some(vec![6, 9]));
assert_eq!(OptionMapVecWithDefault::decode_len(0), Ok(2));
// linked map
assert_eq!(LinkedMapVec::get(0), vec![]);
assert_eq!(LinkedMapVec::decode_len(0), Ok(0));
assert_eq!(LinkedMapVecWithDefault::get(0), vec![6, 9]);
assert_eq!(LinkedMapVecWithDefault::decode_len(0), Ok(2));
assert_eq!(OptionLinkedMapVec::get(0), None);
assert_eq!(OptionLinkedMapVec::decode_len(0), Ok(0));
assert_eq!(OptionLinkedMapVecWithDefault::get(0), Some(vec![6, 9]));
assert_eq!(OptionLinkedMapVecWithDefault::decode_len(0), Ok(2));
});
}
}
+22
View File
@@ -26,6 +26,28 @@ use crate::sr_primitives::ConsensusEngineId;
use super::for_each_tuple;
/// A trait that can return the default value of a storage item. This must only ever be implemented
/// for a special delegator struct for each storage item
pub trait StorageDefault<V>: Sized {
/// Return the default value of type `V`. `None`, if `V` does not have a proper default value.
fn default() -> Option<V>;
}
// FIXME #1466 This is needed for `storage_items!`. Should be removed once it is deprecated.
impl<T: Default> StorageDefault<T> for () { fn default() -> Option<T> { Some(Default::default()) } }
/// Anything that can have a `::len()` method.
pub trait Len {
/// Return the length of data type.
fn len(&self) -> usize;
}
impl<T: IntoIterator + Clone,> Len for T where <T as IntoIterator>::IntoIter: ExactSizeIterator {
fn len(&self) -> usize {
self.clone().into_iter().len()
}
}
/// A trait for querying a single fixed value from a type.
pub trait Get<T> {
/// Return a constant value.