feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit 286de54384
6841 changed files with 1848356 additions and 0 deletions
@@ -0,0 +1,456 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
//! Derive macro for creating XCMs with a builder pattern
use inflector::Inflector;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::{
Data, DataEnum, DeriveInput, Error, Expr, ExprLit, Field, Fields, GenericArgument, Ident, Lit,
Meta, MetaNameValue, PathArguments, Result, Type, TypePath, Variant,
};
pub fn derive(input: DeriveInput) -> Result<TokenStream2> {
let data_enum = match &input.data {
Data::Enum(data_enum) => data_enum,
_ => return Err(Error::new_spanned(&input, "Expected the `Instruction` enum")),
};
let builder_raw_impl = generate_builder_raw_impl(&input.ident, data_enum)?;
let builder_impl = generate_builder_impl(&input.ident, data_enum)?;
let builder_unpaid_impl = generate_builder_unpaid_impl(&input.ident, data_enum)?;
let output = quote! {
/// A trait for types that track state inside the XcmBuilder
pub trait XcmBuilderState {}
/// Access to all the instructions
pub enum AnythingGoes {}
/// You need to pay for execution
pub enum PaymentRequired {}
/// The holding register was loaded, now to buy execution
pub enum LoadedHolding {}
/// Need to explicitly state it won't pay for fees
pub enum ExplicitUnpaidRequired {}
impl XcmBuilderState for AnythingGoes {}
impl XcmBuilderState for PaymentRequired {}
impl XcmBuilderState for LoadedHolding {}
impl XcmBuilderState for ExplicitUnpaidRequired {}
/// Type used to build XCM programs
pub struct XcmBuilder<Call, S: XcmBuilderState> {
pub(crate) instructions: Vec<Instruction<Call>>,
pub state: core::marker::PhantomData<S>,
}
impl<Call> Xcm<Call> {
pub fn builder() -> XcmBuilder<Call, PaymentRequired> {
XcmBuilder::<Call, PaymentRequired> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
pub fn builder_unpaid() -> XcmBuilder<Call, ExplicitUnpaidRequired> {
XcmBuilder::<Call, ExplicitUnpaidRequired> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
pub fn builder_unsafe() -> XcmBuilder<Call, AnythingGoes> {
XcmBuilder::<Call, AnythingGoes> {
instructions: Vec::new(),
state: core::marker::PhantomData,
}
}
}
#builder_impl
#builder_unpaid_impl
#builder_raw_impl
};
Ok(output)
}
fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2> {
let methods = data_enum
.variants
.iter()
.map(|variant| convert_variant_to_method(name, variant, None))
.collect::<Result<Vec<_>>>()?;
let output = quote! {
impl<Call> XcmBuilder<Call, AnythingGoes> {
#(#methods)*
pub fn build(self) -> Xcm<Call> {
Xcm(self.instructions)
}
}
};
Ok(output)
}
fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2> {
// We first require an instruction that load the holding register
let load_holding_variants = data_enum
.variants
.iter()
.map(|variant| {
let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta {
Meta::List(ref list) => list.path.is_ident("builder"),
_ => false,
});
let builder_attr = match maybe_builder_attr {
Some(builder) => builder.clone(),
None => return Ok(None), /* It's not going to be an instruction that loads the
* holding register */
};
let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") };
let inner_ident: Ident = syn::parse2(list.tokens.clone()).map_err(|_| {
Error::new_spanned(
&builder_attr,
"Expected `builder(loads_holding)` or `builder(pays_fees)`",
)
})?;
let loads_holding_ident: Ident = syn::parse_quote!(loads_holding);
let pays_fees_ident: Ident = syn::parse_quote!(pays_fees);
if inner_ident == loads_holding_ident {
Ok(Some(variant))
} else if inner_ident == pays_fees_ident {
Ok(None)
} else {
Err(Error::new_spanned(
&builder_attr,
"Expected `builder(loads_holding)` or `builder(pays_fees)`",
))
}
})
.collect::<Result<Vec<_>>>()?;
let load_holding_methods = load_holding_variants
.into_iter()
.flatten()
.map(|variant| {
let method = convert_variant_to_method(
name,
variant,
Some(quote! { XcmBuilder<Call, LoadedHolding> }),
)?;
Ok(method)
})
.collect::<Result<Vec<_>>>()?;
let first_impl = quote! {
impl<Call> XcmBuilder<Call, PaymentRequired> {
#(#load_holding_methods)*
}
};
// Some operations are allowed after the holding register is loaded
let allowed_after_load_holding_methods: Vec<TokenStream2> = data_enum
.variants
.iter()
.filter(|variant| variant.ident == "ClearOrigin" || variant.ident == "SetHints")
.map(|variant| {
let method = convert_variant_to_method(name, variant, None)?;
Ok(method)
})
.collect::<Result<Vec<_>>>()?;
// Then we require fees to be paid
let pay_fees_variants = data_enum
.variants
.iter()
.map(|variant| {
let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta {
Meta::List(ref list) => list.path.is_ident("builder"),
_ => false,
});
let builder_attr = match maybe_builder_attr {
Some(builder) => builder.clone(),
None => return Ok(None), /* It's not going to be an instruction that pays fees */
};
let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") };
let inner_ident: Ident = syn::parse2(list.tokens.clone()).map_err(|_| {
Error::new_spanned(
&builder_attr,
"Expected `builder(loads_holding)` or `builder(pays_fees)`",
)
})?;
let ident_to_match: Ident = syn::parse_quote!(pays_fees);
if inner_ident == ident_to_match {
Ok(Some(variant))
} else {
Ok(None) // Must have been `loads_holding` instead.
}
})
.collect::<Result<Vec<_>>>()?;
let pay_fees_methods = pay_fees_variants
.into_iter()
.flatten()
.map(|variant| {
let method = convert_variant_to_method(
name,
variant,
Some(quote! { XcmBuilder<Call, AnythingGoes> }),
)?;
Ok(method)
})
.collect::<Result<Vec<_>>>()?;
let second_impl = quote! {
impl<Call> XcmBuilder<Call, LoadedHolding> {
#(#allowed_after_load_holding_methods)*
#(#pay_fees_methods)*
}
};
let output = quote! {
#first_impl
#second_impl
};
Ok(output)
}
fn generate_builder_unpaid_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2> {
let unpaid_execution_variant = data_enum
.variants
.iter()
.find(|variant| variant.ident == "UnpaidExecution")
.ok_or(Error::new_spanned(&data_enum.variants, "No UnpaidExecution instruction"))?;
let method = convert_variant_to_method(
name,
&unpaid_execution_variant,
Some(quote! { XcmBuilder<Call, AnythingGoes> }),
)?;
Ok(quote! {
impl<Call> XcmBuilder<Call, ExplicitUnpaidRequired> {
#method
}
})
}
// Small helper enum to differentiate between fields that use a `BoundedVec`
// and the rest.
enum BoundedOrNormal {
Normal(Field),
Bounded(Field),
}
// Have to call with `XcmBuilder<Call, LoadedHolding>` in allowed_after_load_holding_methods.
fn convert_variant_to_method(
name: &Ident,
variant: &Variant,
maybe_return_type: Option<TokenStream2>,
) -> Result<TokenStream2> {
let variant_name = &variant.ident;
let method_name_string = &variant_name.to_string().to_snake_case();
let method_name = syn::Ident::new(method_name_string, variant_name.span());
let docs = get_doc_comments(variant);
let method = match &variant.fields {
Fields::Unit =>
if let Some(return_type) = maybe_return_type {
quote! {
pub fn #method_name(self) -> #return_type {
let mut new_instructions = self.instructions;
new_instructions.push(#name::<Call>::#variant_name);
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
} else {
quote! {
pub fn #method_name(mut self) -> Self {
self.instructions.push(#name::<Call>::#variant_name);
self
}
}
},
Fields::Unnamed(fields) => {
let arg_names: Vec<_> = fields
.unnamed
.iter()
.enumerate()
.map(|(index, _)| format_ident!("arg{}", index))
.collect();
let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect();
if let Some(return_type) = maybe_return_type {
quote! {
pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> #return_type {
let mut new_instructions = self.instructions;
#(let #arg_names = #arg_names.into();)*
new_instructions.push(#name::<Call>::#variant_name(#(#arg_names),*));
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
} else {
quote! {
pub fn #method_name(mut self, #(#arg_names: impl Into<#arg_types>),*) -> Self {
#(let #arg_names = #arg_names.into();)*
self.instructions.push(#name::<Call>::#variant_name(#(#arg_names),*));
self
}
}
}
},
Fields::Named(fields) => {
let fields: Vec<_> = fields
.named
.iter()
.map(|field| {
if let Type::Path(TypePath { path, .. }) = &field.ty {
for segment in &path.segments {
if segment.ident == format_ident!("BoundedVec") {
return BoundedOrNormal::Bounded(field.clone());
}
}
BoundedOrNormal::Normal(field.clone())
} else {
BoundedOrNormal::Normal(field.clone())
}
})
.collect();
let arg_names: Vec<_> = fields
.iter()
.map(|field| match field {
BoundedOrNormal::Bounded(field) => &field.ident,
BoundedOrNormal::Normal(field) => &field.ident,
})
.collect();
let arg_types: Vec<_> = fields
.iter()
.map(|field| match field {
BoundedOrNormal::Bounded(field) => {
let inner_type =
extract_generic_argument(&field.ty, 0, "BoundedVec's inner type")?;
Ok(quote! {
Vec<#inner_type>
})
},
BoundedOrNormal::Normal(field) => {
let inner_type = &field.ty;
Ok(quote! {
impl Into<#inner_type>
})
},
})
.collect::<Result<Vec<_>>>()?;
let bounded_names: Vec<_> = fields
.iter()
.filter_map(|field| match field {
BoundedOrNormal::Bounded(field) => Some(&field.ident),
BoundedOrNormal::Normal(_) => None,
})
.collect();
let normal_names: Vec<_> = fields
.iter()
.filter_map(|field| match field {
BoundedOrNormal::Normal(field) => Some(&field.ident),
BoundedOrNormal::Bounded(_) => None,
})
.collect();
let comma_in_the_middle = if normal_names.is_empty() {
quote! {}
} else {
quote! {,}
};
if let Some(return_type) = maybe_return_type {
quote! {
pub fn #method_name(self, #(#arg_names: #arg_types),*) -> #return_type {
let mut new_instructions = self.instructions;
#(let #normal_names = #normal_names.into();)*
#(let #bounded_names = BoundedVec::truncate_from(#bounded_names);)*
new_instructions.push(#name::<Call>::#variant_name { #(#normal_names),* #comma_in_the_middle #(#bounded_names),* });
XcmBuilder {
instructions: new_instructions,
state: core::marker::PhantomData,
}
}
}
} else {
quote! {
pub fn #method_name(mut self, #(#arg_names: #arg_types),*) -> Self {
#(let #normal_names = #normal_names.into();)*
#(let #bounded_names = BoundedVec::truncate_from(#bounded_names);)*
self.instructions.push(#name::<Call>::#variant_name { #(#normal_names),* #comma_in_the_middle #(#bounded_names),* });
self
}
}
}
},
};
Ok(quote! {
#(#docs)*
#method
})
}
fn get_doc_comments(variant: &Variant) -> Vec<TokenStream2> {
variant
.attrs
.iter()
.filter_map(|attr| match &attr.meta {
Meta::NameValue(MetaNameValue {
value: Expr::Lit(ExprLit { lit: Lit::Str(literal), .. }),
..
}) if attr.path().is_ident("doc") => Some(literal.value()),
_ => None,
})
.map(|doc| syn::parse_str::<TokenStream2>(&format!("/// {}", doc)).unwrap())
.collect()
}
fn extract_generic_argument<'a>(
field_ty: &'a Type,
index: usize,
expected_msg: &str,
) -> Result<&'a Ident> {
if let Type::Path(type_path) = field_ty {
if let Some(segment) = type_path.path.segments.last() {
if let PathArguments::AngleBracketed(angle_brackets) = &segment.arguments {
let args: Vec<_> = angle_brackets.args.iter().collect();
if let Some(GenericArgument::Type(Type::Path(TypePath { path, .. }))) =
args.get(index)
{
return path.get_ident().ok_or_else(|| {
Error::new_spanned(
path,
format!("Expected an identifier for {}", expected_msg),
)
});
}
return Err(Error::new_spanned(
angle_brackets,
format!("Expected a generic argument at index {} for {}", index, expected_msg),
));
}
return Err(Error::new_spanned(
&segment.arguments,
format!("Expected angle-bracketed arguments for {}", expected_msg),
));
}
return Err(Error::new_spanned(
&type_path.path,
format!("Expected at least one path segment for {}", expected_msg),
));
}
Err(Error::new_spanned(field_ty, format!("Expected a path type for {}", expected_msg)))
}
@@ -0,0 +1,38 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
//! Simple derive macro for getting the number of variants in an enum.
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::{Data, DeriveInput, Error, Result};
pub fn derive(input: DeriveInput) -> Result<TokenStream2> {
let data_enum = match &input.data {
Data::Enum(data_enum) => data_enum,
_ => return Err(Error::new_spanned(&input, "Expected an enum.")),
};
let ident = format_ident!("{}NumVariants", input.ident);
let number_of_variants: usize = data_enum.variants.iter().count();
Ok(quote! {
pub struct #ident;
impl ::frame_support::traits::Get<u32> for #ident {
fn get() -> u32 {
#number_of_variants as u32
}
}
})
}
+97
View File
@@ -0,0 +1,97 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
//! Procedural macros used in XCM.
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
mod builder_pattern;
mod enum_variants;
mod v3;
mod v4;
mod v5;
mod weight_info;
#[proc_macro_derive(XcmWeightInfoTrait)]
pub fn derive_xcm_weight_info(item: TokenStream) -> TokenStream {
weight_info::derive(item)
}
#[proc_macro]
pub fn impl_conversion_functions_for_multilocation_v3(input: TokenStream) -> TokenStream {
v3::multilocation::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro]
pub fn impl_conversion_functions_for_junctions_v3(input: TokenStream) -> TokenStream {
v3::junctions::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro]
pub fn impl_conversion_functions_for_location_v4(input: TokenStream) -> TokenStream {
v4::location::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro]
pub fn impl_conversion_functions_for_junctions_v4(input: TokenStream) -> TokenStream {
v4::junctions::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro]
pub fn impl_conversion_functions_for_junctions_v5(input: TokenStream) -> TokenStream {
v5::junctions::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro]
pub fn impl_conversion_functions_for_location_v5(input: TokenStream) -> TokenStream {
v5::location::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
/// This is called on the `Instruction` enum, not on the `Xcm` struct,
/// and allows for the following syntax for building XCMs:
/// let message = Xcm::builder()
/// .withdraw_asset(assets)
/// .buy_execution(fees, weight_limit)
/// .deposit_asset(assets, beneficiary)
/// .build();
#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive_builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
builder_pattern::derive(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro_derive(NumVariants)]
pub fn derive_num_variants(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
enum_variants::derive(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
+195
View File
@@ -0,0 +1,195 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Result, Token};
const MAX_JUNCTIONS: usize = 8;
pub mod multilocation {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
let from_tuples = generate_conversion_from_tuples(8, 8);
Ok(quote! {
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
let mut from_tuples = (0..=max_junctions)
.map(|num_junctions| {
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let array_size = num_junctions;
let interior = if num_junctions == 0 {
quote!(Junctions::Here)
} else {
quote! {
[#(#idents .into()),*].into()
}
};
let mut from_tuple = quote! {
impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for MultiLocation {
fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
MultiLocation { parents, interior: #interior }
}
}
impl From<[Junction; #array_size]> for MultiLocation {
fn from(j: [Junction; #array_size]) -> Self {
let [#(#idents),*] = j;
MultiLocation { parents: 0, interior: #interior }
}
}
};
let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
let parents =
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for MultiLocation {
fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
Self { parents: #cur_parents as u8, interior: #interior }
}
}
}
});
from_tuple.extend(from_parent_tuples);
from_tuple
})
.collect::<TokenStream>();
let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl From<( #(#parents,)* Junctions )> for MultiLocation {
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
MultiLocation { parents: #cur_parents as u8, interior: junctions }
}
}
}
});
from_tuples.extend(from_parent_junctions_tuples);
quote! {
impl From<(Ancestor, Junctions)> for MultiLocation {
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
MultiLocation { parents, interior }
}
}
impl From<Junction> for MultiLocation {
fn from(x: Junction) -> Self {
MultiLocation { parents: 0, interior: [x].into() }
}
}
#from_tuples
}
}
}
pub mod junctions {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
let from_v4 = generate_conversion_from_v4();
let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
Ok(quote! {
#from_v4
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
(1..=max_junctions)
.map(|num_junctions| {
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
quote! {
impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
[#(#idents .into()),*].into()
}
}
}
})
.collect()
}
fn generate_conversion_from_v4() -> TokenStream {
let match_variants = (0..8u8)
.map(|current_number| {
let number_ancestors = current_number + 1;
let variant = format_ident!("X{}", number_ancestors);
let idents =
(0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let convert = idents
.iter()
.map(|ident| {
quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
})
.collect::<Vec<_>>();
quote! {
crate::v4::Junctions::#variant( junctions ) => {
let [#(#idents),*] = &*junctions;
#(#convert);*
[#(#idents),*].into()
},
}
})
.collect::<TokenStream>();
quote! {
impl core::convert::TryFrom<crate::v4::Junctions> for Junctions {
type Error = ();
fn try_from(mut new: crate::v4::Junctions) -> core::result::Result<Self, Self::Error> {
use Junctions::*;
Ok(match new {
crate::v4::Junctions::Here => Here,
#match_variants
})
}
}
}
}
}
+237
View File
@@ -0,0 +1,237 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Result, Token};
const MAX_JUNCTIONS: usize = 8;
pub mod location {
use super::*;
/// Generates conversion functions from other types to the `Location` type:
/// - [PalletInstance(50), GeneralIndex(1984)].into()
/// - (Parent, Teyrchain(1000), AccountId32 { .. }).into()
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
let from_tuples = generate_conversion_from_tuples(8, 8);
Ok(quote! {
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
let mut from_tuples = (0..=max_junctions)
.map(|num_junctions| {
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let array_size = num_junctions;
let interior = if num_junctions == 0 {
quote!(Junctions::Here)
} else {
let variant = format_ident!("X{}", num_junctions);
quote! {
Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
}
};
let mut from_tuple = quote! {
impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
Location { parents, interior: #interior }
}
}
impl From<[Junction; #array_size]> for Location {
fn from(j: [Junction; #array_size]) -> Self {
let [#(#idents),*] = j;
Location { parents: 0, interior: #interior }
}
}
};
let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
let parents =
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
Self { parents: #cur_parents as u8, interior: #interior }
}
}
}
});
from_tuple.extend(from_parent_tuples);
from_tuple
})
.collect::<TokenStream>();
let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl From<( #(#parents,)* Junctions )> for Location {
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
Location { parents: #cur_parents as u8, interior: junctions }
}
}
}
});
from_tuples.extend(from_parent_junctions_tuples);
quote! {
impl From<(Ancestor, Junctions)> for Location {
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
Location { parents, interior }
}
}
impl From<Junction> for Location {
fn from(x: Junction) -> Self {
Location { parents: 0, interior: [x].into() }
}
}
#from_tuples
}
}
}
pub mod junctions {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS);
let from_v5 = generate_conversion_from_v5(MAX_JUNCTIONS);
let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
Ok(quote! {
#from_v3
#from_v5
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
(1..=max_junctions)
.map(|num_junctions| {
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
quote! {
impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
[#(#idents .into()),*].into()
}
}
}
})
.collect()
}
fn generate_conversion_from_v3(max_junctions: usize) -> TokenStream {
let match_variants = (0..max_junctions)
.map(|cur_num| {
let num_ancestors = cur_num + 1;
let variant = format_ident!("X{}", num_ancestors);
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let convert = idents
.iter()
.map(|ident| {
quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
})
.collect::<Vec<_>>();
quote! {
crate::v3::Junctions::#variant( #(#idents),* ) => {
#(#convert);*;
let junctions: Junctions = [#(#idents),*].into();
junctions
},
}
})
.collect::<TokenStream>();
quote! {
impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
type Error = ();
fn try_from(mut old: crate::v3::Junctions) -> core::result::Result<Self, ()> {
Ok(match old {
crate::v3::Junctions::Here => Junctions::Here,
#match_variants
})
}
}
}
}
fn generate_conversion_from_v5(max_junctions: usize) -> TokenStream {
let match_variants = (0..max_junctions)
.map(|current_number| {
let number_ancestors = current_number + 1;
let variant = format_ident!("X{}", number_ancestors);
let idents =
(0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let convert = idents
.iter()
.map(|ident| {
quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
})
.collect::<Vec<_>>();
quote! {
crate::v5::Junctions::#variant( junctions ) => {
let [#(#idents),*] = &*junctions;
#(#convert);*
[#(#idents),*].into()
},
}
})
.collect::<TokenStream>();
quote! {
impl core::convert::TryFrom<crate::v5::Junctions> for Junctions {
type Error = ();
fn try_from(mut new: crate::v5::Junctions) -> core::result::Result<Self, Self::Error> {
use Junctions::*;
Ok(match new {
crate::v5::Junctions::Here => Here,
#match_variants
})
}
}
}
}
}
+198
View File
@@ -0,0 +1,198 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Result, Token};
const MAX_JUNCTIONS: usize = 8;
pub mod location {
use super::*;
/// Generates conversion functions from other types to the `Location` type:
/// - [PalletInstance(50), GeneralIndex(1984)].into()
/// - (Parent, Teyrchain(1000), AccountId32 { .. }).into()
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
let from_tuples = generate_conversion_from_tuples(8, 8);
Ok(quote! {
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
let mut from_tuples = (0..=max_junctions)
.map(|num_junctions| {
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let array_size = num_junctions;
let interior = if num_junctions == 0 {
quote!(Junctions::Here)
} else {
let variant = format_ident!("X{}", num_junctions);
quote! {
Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
}
};
let mut from_tuple = quote! {
impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
Location { parents, interior: #interior }
}
}
impl From<[Junction; #array_size]> for Location {
fn from(j: [Junction; #array_size]) -> Self {
let [#(#idents),*] = j;
Location { parents: 0, interior: #interior }
}
}
};
let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
let parents =
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
Self { parents: #cur_parents as u8, interior: #interior }
}
}
}
});
from_tuple.extend(from_parent_tuples);
from_tuple
})
.collect::<TokenStream>();
let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl From<( #(#parents,)* Junctions )> for Location {
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
Location { parents: #cur_parents as u8, interior: junctions }
}
}
}
});
from_tuples.extend(from_parent_junctions_tuples);
quote! {
impl From<(Ancestor, Junctions)> for Location {
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
Location { parents, interior }
}
}
impl From<Junction> for Location {
fn from(x: Junction) -> Self {
Location { parents: 0, interior: [x].into() }
}
}
#from_tuples
}
}
}
pub mod junctions {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"));
}
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
let from_v4 = generate_conversion_from_v4(MAX_JUNCTIONS);
let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
Ok(quote! {
#from_v4
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
(1..=max_junctions)
.map(|num_junctions| {
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
quote! {
impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
[#(#idents .into()),*].into()
}
}
}
})
.collect()
}
fn generate_conversion_from_v4(max_junctions: usize) -> TokenStream {
let match_variants = (0..max_junctions)
.map(|cur_num| {
let num_ancestors = cur_num + 1;
let variant = format_ident!("X{}", num_ancestors);
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let convert = idents
.iter()
.enumerate()
.map(|(index, ident)| {
quote! { let #ident = core::convert::TryInto::try_into(slice[#index].clone())?; }
})
.collect::<Vec<_>>();
quote! {
crate::v4::Junctions::#variant( arc ) => {
let slice = &arc[..];
#(#convert);*;
let junctions: Junctions = [#(#idents),*].into();
junctions
},
}
})
.collect::<TokenStream>();
quote! {
impl core::convert::TryFrom<crate::v4::Junctions> for Junctions {
type Error = ();
fn try_from(mut old: crate::v4::Junctions) -> core::result::Result<Self, ()> {
Ok(match old {
crate::v4::Junctions::Here => Junctions::Here,
#match_variants
})
}
}
}
}
}
+67
View File
@@ -0,0 +1,67 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
use inflector::Inflector;
use quote::format_ident;
pub fn derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: syn::DeriveInput = match syn::parse(item) {
Ok(input) => input,
Err(e) => return e.into_compile_error().into(),
};
let syn::DeriveInput { generics, data, .. } = input;
match data {
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
let methods = variants.into_iter().map(|syn::Variant { ident, fields, .. }| {
let snake_cased_ident = format_ident!("{}", ident.to_string().to_snake_case());
let ref_fields =
fields.into_iter().enumerate().map(|(idx, syn::Field { ident, ty, .. })| {
let field_name = ident.unwrap_or_else(|| format_ident!("_{}", idx));
let field_ty = match ty {
syn::Type::Reference(r) => {
// If the type is already a reference, do nothing
quote::quote!(#r)
},
t => {
// Otherwise, make it a reference
quote::quote!(&#t)
},
};
quote::quote!(#field_name: #field_ty,)
});
quote::quote!(fn #snake_cased_ident( #(#ref_fields)* ) -> Weight;)
});
let res = quote::quote! {
pub trait XcmWeightInfo #generics {
#(#methods)*
}
};
res.into()
},
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
let msg = "structs are not supported by 'derive(XcmWeightInfo)'";
syn::Error::new(struct_token.span, msg).into_compile_error().into()
},
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
let msg = "unions are not supported by 'derive(XcmWeightInfo)'";
syn::Error::new(union_token.span, msg).into_compile_error().into()
},
}
}