use codec::{Decode, Encode};
use impl_trait_for_tuples::impl_for_tuples;
use sp_runtime::RuntimeDebug;
use sp_std::prelude::*;
pub trait PalletInfo {
fn index<P: 'static>() -> Option<usize>;
fn name<P: 'static>() -> Option<&'static str>;
fn module_name<P: 'static>() -> Option<&'static str>;
fn crate_version<P: 'static>() -> Option<CrateVersion>;
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
pub struct PalletInfoData {
pub index: usize,
pub name: &'static str,
pub module_name: &'static str,
pub crate_version: CrateVersion,
}
pub trait PalletInfoAccess {
fn index() -> usize;
fn name() -> &'static str;
fn module_name() -> &'static str;
fn crate_version() -> CrateVersion;
}
pub trait PalletsInfoAccess {
fn count() -> usize {
Self::infos().len()
}
fn infos() -> Vec<PalletInfoData>;
}
#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
impl PalletsInfoAccess for Tuple {
fn infos() -> Vec<PalletInfoData> {
let mut res = vec![];
for_tuples!( #( res.extend(Tuple::infos()); )* );
res
}
}
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug)]
pub struct CallMetadata {
pub function_name: &'static str,
pub pallet_name: &'static str,
}
pub trait GetCallName {
fn get_call_names() -> &'static [&'static str];
fn get_call_name(&self) -> &'static str;
}
pub trait GetCallIndex {
fn get_call_indices() -> &'static [u8];
fn get_call_index(&self) -> u8;
}
pub trait GetCallMetadata {
fn get_module_names() -> &'static [&'static str];
fn get_call_names(module: &str) -> &'static [&'static str];
fn get_call_metadata(&self) -> CallMetadata;
}
#[derive(Debug, Eq, PartialEq, Encode, Decode, Clone, Copy, Default)]
pub struct CrateVersion {
pub major: u16,
pub minor: u8,
pub patch: u8,
}
impl CrateVersion {
pub const fn new(major: u16, minor: u8, patch: u8) -> Self {
Self { major, minor, patch }
}
}
impl sp_std::cmp::Ord for CrateVersion {
fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering {
self.major
.cmp(&other.major)
.then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch)))
}
}
impl sp_std::cmp::PartialOrd for CrateVersion {
fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> {
Some(<Self as Ord>::cmp(self, other))
}
}
pub const STORAGE_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__STORAGE_VERSION__:";
#[derive(Debug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, PartialOrd, Default)]
pub struct StorageVersion(u16);
impl StorageVersion {
pub const fn new(version: u16) -> Self {
Self(version)
}
pub fn storage_key<P: PalletInfoAccess>() -> [u8; 32] {
let pallet_name = P::name();
crate::storage::storage_prefix(pallet_name.as_bytes(), STORAGE_VERSION_STORAGE_KEY_POSTFIX)
}
pub fn put<P: PalletInfoAccess>(&self) {
let key = Self::storage_key::<P>();
crate::storage::unhashed::put(&key, self);
}
pub fn get<P: PalletInfoAccess>() -> Self {
let key = Self::storage_key::<P>();
crate::storage::unhashed::get_or_default(&key)
}
}
impl PartialEq<u16> for StorageVersion {
fn eq(&self, other: &u16) -> bool {
self.0 == *other
}
}
impl PartialOrd<u16> for StorageVersion {
fn partial_cmp(&self, other: &u16) -> Option<sp_std::cmp::Ordering> {
Some(self.0.cmp(other))
}
}
pub trait GetStorageVersion {
fn current_storage_version() -> StorageVersion;
fn on_chain_storage_version() -> StorageVersion;
}
#[cfg(test)]
mod tests {
use super::*;
struct Pallet1;
impl PalletInfoAccess for Pallet1 {
fn index() -> usize {
1
}
fn name() -> &'static str {
"Pallet1"
}
fn module_name() -> &'static str {
"pallet1"
}
fn crate_version() -> CrateVersion {
CrateVersion::new(1, 0, 0)
}
}
struct Pallet2;
impl PalletInfoAccess for Pallet2 {
fn index() -> usize {
2
}
fn name() -> &'static str {
"Pallet2"
}
fn module_name() -> &'static str {
"pallet2"
}
fn crate_version() -> CrateVersion {
CrateVersion::new(1, 0, 0)
}
}
#[test]
fn check_storage_version_ordering() {
let version = StorageVersion::new(1);
assert!(version == StorageVersion::new(1));
assert!(version < StorageVersion::new(2));
assert!(version < StorageVersion::new(3));
let version = StorageVersion::new(2);
assert!(version < StorageVersion::new(3));
assert!(version > StorageVersion::new(1));
assert!(version < StorageVersion::new(5));
}
}