Implement InspectEnumerable for Uniques (#9117)

* implement InspectEnumerable in pallet_uniques

* use `iter_keys` and `iter_key_prefix`

* return an iterator instead of constructing a vec

* update comments

* additional warning about storage reads

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Alexander Popiak
2021-07-01 23:34:17 +02:00
committed by GitHub
parent ae3c3045df
commit c30ece2bd8
3 changed files with 45 additions and 19 deletions
@@ -61,14 +61,12 @@ pub trait Inspect<AccountId> {
/// Interface for enumerating assets in existence or owned by a given account over a collection
/// of NFTs.
///
/// WARNING: These may be a heavy operations. Do not use when execution time is limited.
pub trait InspectEnumerable<AccountId>: Inspect<AccountId> {
/// Returns the instances of an asset `class` in existence.
fn instances() -> Vec<Self::InstanceId>;
/// Returns an iterator of the instances of an asset `class` in existence.
fn instances() -> Box<dyn Iterator<Item = Self::InstanceId>>;
/// Returns the asset instances of all classes owned by `who`.
fn owned(who: &AccountId) -> Vec<Self::InstanceId>;
/// Returns an iterator of the asset instances of all classes owned by `who`.
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>>;
}
/// Trait for providing an interface for NFT-like assets which may be minted, burned and/or have
@@ -148,10 +146,10 @@ impl<
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
AccountId,
> InspectEnumerable<AccountId> for ItemOf<F, A, AccountId> {
fn instances() -> Vec<Self::InstanceId> {
fn instances() -> Box<dyn Iterator<Item = Self::InstanceId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::instances(&A::get())
}
fn owned(who: &AccountId) -> Vec<Self::InstanceId> {
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::owned_in_class(&A::get(), who)
}
}
@@ -95,20 +95,18 @@ pub trait Inspect<AccountId> {
/// Interface for enumerating assets in existence or owned by a given account over many collections
/// of NFTs.
///
/// WARNING: These may be a heavy operations. Do not use when execution time is limited.
pub trait InspectEnumerable<AccountId>: Inspect<AccountId> {
/// Returns the asset classes in existence.
fn classes() -> Vec<Self::ClassId>;
/// Returns an iterator of the asset classes in existence.
fn classes() -> Box<dyn Iterator<Item = Self::ClassId>>;
/// Returns the instances of an asset `class` in existence.
fn instances(class: &Self::ClassId) -> Vec<Self::InstanceId>;
/// Returns an iterator of the instances of an asset `class` in existence.
fn instances(class: &Self::ClassId) -> Box<dyn Iterator<Item = Self::InstanceId>>;
/// Returns the asset instances of all classes owned by `who`.
fn owned(who: &AccountId) -> Vec<(Self::ClassId, Self::InstanceId)>;
/// Returns an iterator of the asset instances of all classes owned by `who`.
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = (Self::ClassId, Self::InstanceId)>>;
/// Returns the asset instances of `class` owned by `who`.
fn owned_in_class(class: &Self::ClassId, who: &AccountId) -> Vec<Self::InstanceId>;
/// Returns an iterator of the asset instances of `class` owned by `who`.
fn owned_in_class(class: &Self::ClassId, who: &AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>>;
}
/// Trait for providing an interface for multiple classes of NFT-like assets which may be minted,
@@ -19,7 +19,7 @@
use super::*;
use sp_std::convert::TryFrom;
use frame_support::traits::tokens::nonfungibles::{Inspect, Mutate, Transfer};
use frame_support::traits::tokens::nonfungibles::{Inspect, InspectEnumerable, Mutate, Transfer};
use frame_support::BoundedSlice;
use sp_runtime::DispatchResult;
@@ -106,3 +106,33 @@ impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
Self::do_transfer(class.clone(), instance.clone(), destination.clone(), |_, _| Ok(()))
}
}
impl<T: Config<I>, I: 'static> InspectEnumerable<T::AccountId> for Pallet<T, I> {
/// Returns an iterator of the asset classes in existence.
///
/// NOTE: iterating this list invokes a storage read per item.
fn classes() -> Box<dyn Iterator<Item = Self::ClassId>> {
Box::new(ClassMetadataOf::<T, I>::iter_keys())
}
/// Returns an iterator of the instances of an asset `class` in existence.
///
/// NOTE: iterating this list invokes a storage read per item.
fn instances(class: &Self::ClassId) -> Box<dyn Iterator<Item = Self::InstanceId>> {
Box::new(InstanceMetadataOf::<T, I>::iter_key_prefix(class))
}
/// Returns an iterator of the asset instances of all classes owned by `who`.
///
/// NOTE: iterating this list invokes a storage read per item.
fn owned(who: &T::AccountId) -> Box<dyn Iterator<Item = (Self::ClassId, Self::InstanceId)>> {
Box::new(Account::<T, I>::iter_key_prefix((who,)))
}
/// Returns an iterator of the asset instances of `class` owned by `who`.
///
/// NOTE: iterating this list invokes a storage read per item.
fn owned_in_class(class: &Self::ClassId, who: &T::AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>> {
Box::new(Account::<T, I>::iter_key_prefix((who, class)))
}
}