#
pezkuwi_sdk_docs/reference_docs/
frame_storage_derives.rs

    1//! # Frame storage derives
    2//!
    3//! > **Note:**
    4//! >
    5//! > In all examples, a few lines of boilerplate have been hidden from each snippet for
    6//! > conciseness.
    7//!
    8//! Let's begin by starting to store a `NewType` in a storage item:
    9//!
    10//! ```compile_fail
    11//! #[pezframe::pezpallet]
    12//! pub mod pezpallet {
    13//! 	# use pezframe::prelude::*;
    14//! 	# #[pezpallet::config]
    15//! 	# pub trait Config: pezframe_system::Config {}
    16//! 	# #[pezpallet::pezpallet]
    17//! 	# pub struct Pezpallet<T>(_);
    18//! 	pub struct NewType(u32);
    19//
    20//! 	#[pezpallet::storage]
    21//! 	pub type Something<T> = StorageValue<_, NewType>;
    22//! }
    23//! ```
    24//!
    25//! This raises a number of compiler errors, like:
    26//! ```text
    27//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
    28//! `pezframe::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
    29//! StorageInfoTrait`
    30//! ```
    31//!
    32//! This implies the following set of traits that need to be derived for a type to be stored in
    33//! `frame` storage:
    34//! ```rust
    35//! #[pezframe::pezpallet]
    36//! pub mod pezpallet {
    37//! 	# use pezframe::prelude::*;
    38//! 	# #[pezpallet::config]
    39//! 	# pub trait Config: pezframe_system::Config {}
    40//! 	# #[pezpallet::pezpallet]
    41//! 	# pub struct Pezpallet<T>(_);
    42//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
    43//! 	pub struct NewType(u32);
    44//!
    45//! 	#[pezpallet::storage]
    46//! 	pub type Something<T> = StorageValue<_, NewType>;
    47//! }
    48//! ```
    49//!
    50//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
    51//! storage, such as [`pezframe::prelude::BlockNumberFor`]:
    52//! ```compile_fail
    53//! #[pezframe::pezpallet]
    54//! pub mod pezpallet {
    55//! 	# use pezframe::prelude::*;
    56//! 	# #[pezpallet::config]
    57//! 	# pub trait Config: pezframe_system::Config {}
    58//! 	# #[pezpallet::pezpallet]
    59//! 	# pub struct Pezpallet<T>(_);
    60//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
    61//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
    62//!
    63//! 	#[pezpallet::storage]
    64//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>>;
    65//! }
    66//! ```
    67//!
    68//! Surprisingly, this will also raise a number of errors, like:
    69//! ```text
    70//! the trait `TypeInfo` is not implemented for `T`, which is required
    71//! by`pezframe_support::pezpallet_prelude::StorageValue<pezpallet_2::_GeneratedPrefixForStorageSomething<T>,
    72//! pezpallet_2::NewType<T>>:StorageEntryMetadataBuilder
    73//! ```
    74//!
    75//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
    76//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
    77//! in the example above.
    78//!
    79//! If you expand an instance of the derive, you will find something along the lines of:
    80//! `impl<T> TypeInfo for NewType<T> where T: TypeInfo { ... }`. This is the reason why the
    81//! `TypeInfo` trait is required for `T`.
    82//!
    83//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]`
    84//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
    85//! `T`.
    86//! ```rust
    87//! #[pezframe::pezpallet]
    88//! pub mod pezpallet {
    89//! 	# use pezframe::prelude::*;
    90//! 	# #[pezpallet::config]
    91//! 	# pub trait Config: pezframe_system::Config {}
    92//! 	# #[pezpallet::pezpallet]
    93//! 	# pub struct Pezpallet<T>(_);
    94//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
    95//! 	#[scale_info(skip_type_params(T))]
    96//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
    97//!
    98//! 	#[pezpallet::storage]
    99//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>>;
    100//! }
    101//! ```
    102//!
    103//! Next, let's say we wish to store `NewType` as [`pezframe::prelude::ValueQuery`], which means it
    104//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
    105//! right?
    106//! ```compile_fail
    107//! #[pezframe::pezpallet]
    108//! pub mod pezpallet {
    109//! 	# use pezframe::prelude::*;
    110//! 	# #[pezpallet::config]
    111//! 	# pub trait Config: pezframe_system::Config {}
    112//! 	# #[pezpallet::pezpallet]
    113//! 	# pub struct Pezpallet<T>(_);
    114//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
    115//! 	#[scale_info(skip_type_params(T))]
    116//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
    117//!
    118//! 	#[pezpallet::storage]
    119//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
    120//! }
    121//! ```
    122//!
    123//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
    124//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
    125//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
    126//! `BlockNumberFor<T>` should indeed implement `Default`, but `T` implementing `Default` is rather
    127//! meaningless.
    128//!
    129//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
    130//! work nicely on top of structs that are generic over `T: Config`. These macros are:
    131//!
    132//! - [`pezframe::prelude::DefaultNoBound`]
    133//! - [`pezframe::prelude::DebugNoBound`]
    134//! - [`pezframe::prelude::PartialEqNoBound`]
    135//! - [`pezframe::prelude::EqNoBound`]
    136//! - [`pezframe::prelude::CloneNoBound`]
    137//! - [`pezframe::prelude::PartialOrdNoBound`]
    138//! - [`pezframe::prelude::OrdNoBound`]
    139//!
    140//! The above traits are almost certainly needed for your tests - to print your type, assert equality
    141//! or clone it.
    142//!
    143//! We can fix the following example by using [`pezframe::prelude::DefaultNoBound`].
    144//! ```rust
    145//! #[pezframe::pezpallet]
    146//! pub mod pezpallet {
    147//! 	# use pezframe::prelude::*;
    148//! 	# #[pezpallet::config]
    149//! 	# pub trait Config: pezframe_system::Config {}
    150//! 	# #[pezpallet::pezpallet]
    151//! 	# pub struct Pezpallet<T>(_);
    152//! 	#[derive(
    153//! 		codec::Encode,
    154//! 		codec::Decode,
    155//! 		codec::MaxEncodedLen,
    156//! 		scale_info::TypeInfo,
    157//! 		DefaultNoBound
    158//!		)]
    159//! 	#[scale_info(skip_type_params(T))]
    160//! 	pub struct NewType<T:Config>(BlockNumberFor<T>);
    161//!
    162//! 	#[pezpallet::storage]
    163//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
    164//! }
    165//! ```
    166//!
    167//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
    168//! is subject to the same trait requirements. The following does not work:
    169//! ```compile_fail
    170//! #[pezframe::pezpallet]
    171//! pub mod pezpallet {
    172//! 	use pezframe::prelude::*;
    173//! 	#[pezpallet::config]
    174//! 	pub trait Config: pezframe_system::Config {
    175//! 		type CustomType;
    176//! 	}
    177//! 	#[pezpallet::pezpallet]
    178//! 	pub struct Pezpallet<T>(_);
    179//! 	#[pezpallet::storage]
    180//! 	pub type Something<T: Config> = StorageValue<_, T::CustomType>;
    181//! }
    182//! ```
    183//!
    184//! But adding the right trait bounds will fix it.
    185//! ```rust
    186//! #[pezframe::pezpallet]
    187//! pub mod pezpallet {
    188//! 	use pezframe::prelude::*;
    189//! 	#[pezpallet::config]
    190//! 	pub trait Config: pezframe_system::Config {
    191//! 		type CustomType: codec::FullCodec
    192//! 			+ codec::MaxEncodedLen
    193//! 			+ scale_info::TypeInfo
    194//! 			+ Debug
    195//! 			+ Default;
    196//! 	}
    197//! 	#[pezpallet::pezpallet]
    198//! 	pub struct Pezpallet<T>(_);
    199//! 	#[pezpallet::storage]
    200//! 	pub type Something<T: Config> = StorageValue<_, T::CustomType>;
    201//! }
    202//! ```