use alloc::{vec, vec::Vec};
use codec::{Decode, Encode};
use core::ops::Add;
use impl_trait_for_tuples::impl_for_tuples;
use Debug;
pub trait PalletInfo {
fn index<P: 'static>() -> Option<usize>;
fn name<P: 'static>() -> Option<&'static str>;
fn name_hash<P: 'static>() -> Option<[u8; 16]>;
fn module_name<P: 'static>() -> Option<&'static str>;
fn crate_version<P: 'static>() -> Option<CrateVersion>;
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
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 name_hash() -> [u8; 16];
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, Debug)]
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 Ord for CrateVersion {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.major
.cmp(&other.major)
.then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch)))
}
}
impl PartialOrd for CrateVersion {
fn partial_cmp(&self, other: &Self) -> Option<core::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)
}
pub fn exists<P: PalletInfoAccess>() -> bool {
let key = Self::storage_key::<P>();
crate::storage::unhashed::exists(&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<core::cmp::Ordering> {
Some(self.0.cmp(other))
}
}
impl Add<u16> for StorageVersion {
type Output = StorageVersion;
fn add(self, rhs: u16) -> Self::Output {
Self::new(self.0 + rhs)
}
}
#[derive(Debug, Default)]
pub struct NoStorageVersionSet;
pub trait GetStorageVersion {
type InCodeStorageVersion;
#[deprecated(
note = "This method has been renamed to `in_code_storage_version` and will be removed after March 2024."
)]
fn current_storage_version() -> Self::InCodeStorageVersion {
Self::in_code_storage_version()
}
fn in_code_storage_version() -> Self::InCodeStorageVersion;
fn on_chain_storage_version() -> StorageVersion;
}
#[cfg(test)]
mod tests {
use super::*;
use subsoil_crypto_hashing::twox_128;
#[allow(dead_code)]
struct Pallet1;
impl PalletInfoAccess for Pallet1 {
fn index() -> usize {
1
}
fn name() -> &'static str {
"Pallet1"
}
fn name_hash() -> [u8; 16] {
twox_128(Self::name().as_bytes())
}
fn module_name() -> &'static str {
"pallet1"
}
fn crate_version() -> CrateVersion {
CrateVersion::new(1, 0, 0)
}
}
#[allow(dead_code)]
struct Pallet2;
impl PalletInfoAccess for Pallet2 {
fn index() -> usize {
2
}
fn name() -> &'static str {
"Pallet2"
}
fn name_hash() -> [u8; 16] {
twox_128(Self::name().as_bytes())
}
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));
}
}