use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse::Parser, parse_macro_input, DeriveInput};
fn merge_variants(left: TokenStream, right: TokenStream) -> TokenStream {
use syn::Data::Enum;
use syn::DataEnum;
let mut left: DeriveInput = parse_macro_input!(left);
let right: DeriveInput = parse_macro_input!(right);
if let (
Enum(DataEnum { variants, .. }),
Enum(DataEnum {
variants: to_add, ..
}),
) = (&mut left.data, right.data)
{
variants.extend(to_add);
quote! { #left }.into()
} else {
syn::Error::new(left.ident.span(), "variants may only be added for enums")
.to_compile_error()
.into()
}
}
#[proc_macro_attribute]
pub fn andr_exec(_args: TokenStream, input: TokenStream) -> TokenStream {
#[allow(unused_mut)]
let mut merged = merge_variants(
input,
quote! {
enum Right {
#[serde(rename="amp_receive")]
AMPReceive(::andromeda_std::amp::messages::AMPPkt),
UpdateOwner {
address: String,
},
UpdateOperators {
operators: Vec<String>,
},
UpdateAppContract {
address: String,
},
Deposit {
recipient: Option<::andromeda_std::amp::AndrAddr>,
msg: Option<::cosmwasm_std::Binary>,
},
SetPermission {
actor: ::andromeda_std::amp::AndrAddr,
action: String,
permission: ::andromeda_std::ado_base::permissioning::Permission,
},
RemovePermission {
action: String,
actor: ::andromeda_std::amp::AndrAddr,
},
PermissionAction {
action: String
},
}
}
.into(),
);
#[cfg(feature = "modules")]
{
merged = merge_variants(
merged,
quote! {
enum Right {
RegisterModule {
module: ::andromeda_std::ado_base::Module,
},
DeregisterModule {
module_idx: ::cosmwasm_std::Uint64,
},
AlterModule {
module_idx: ::cosmwasm_std::Uint64,
module: ::andromeda_std::ado_base::Module,
},
}
}
.into(),
)
}
#[cfg(feature = "withdraw")]
{
merged = merge_variants(
merged,
quote! {
enum Right {
Withdraw {
recipient: Option<::andromeda_std::amp::Recipient>,
tokens_to_withdraw: Option<Vec<::andromeda_std::common::withdraw::Withdrawal>>,
},
}
}
.into(),
)
}
let input = parse_macro_input!(merged);
TokenStream::from(andr_exec_derive(input).into_token_stream())
}
fn andr_exec_derive(input: DeriveInput) -> DeriveInput {
use syn::parse_quote;
match input.data {
syn::Data::Enum(_) => parse_quote! {
#[derive(::andromeda_std::AsRefStr)]
#input
},
_ => panic!("unions are not supported"),
}
}
#[proc_macro_attribute]
pub fn andr_instantiate(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as DeriveInput);
match &mut ast.data {
syn::Data::Struct(ref mut struct_data) => {
if let syn::Fields::Named(fields) = &mut struct_data.fields {
fields.named.push(
syn::Field::parse_named
.parse2(quote! { pub kernel_address: String })
.unwrap(),
);
fields.named.push(
syn::Field::parse_named
.parse2(quote! { pub owner: Option<String> })
.unwrap(),
);
}
quote! {
#ast
}
.into()
}
_ => panic!("Macro only works with structs"),
}
}
#[proc_macro_attribute]
pub fn andr_instantiate_modules(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as DeriveInput);
match &mut ast.data {
syn::Data::Struct(ref mut struct_data) => {
if let syn::Fields::Named(fields) = &mut struct_data.fields {
fields.named.push(
syn::Field::parse_named
.parse2(
quote! { pub modules: Option<Vec<::andromeda_std::ado_base::Module>> },
)
.unwrap(),
);
}
quote! {
#ast
}
.into()
}
_ => panic!("Macro only works with structs"),
}
}
#[proc_macro_attribute]
pub fn andr_query(_metadata: TokenStream, input: TokenStream) -> TokenStream {
#[allow(unused_mut)]
let mut merged = merge_variants(
input,
quote! {
enum Right {
#[returns(andromeda_std::ado_base::ownership::ContractOwnerResponse)]
Owner {},
#[returns(andromeda_std::ado_base::operators::OperatorsResponse)]
Operators {},
#[returns(andromeda_std::ado_base::ado_type::TypeResponse)]
Type {},
#[returns(andromeda_std::ado_base::kernel_address::KernelAddressResponse)]
KernelAddress {},
#[returns(andromeda_std::ado_base::ownership::PublisherResponse)]
OriginalPublisher {},
#[returns(andromeda_std::ado_base::block_height::BlockHeightResponse)]
BlockHeightUponCreation {},
#[returns(andromeda_std::ado_base::operators::IsOperatorResponse)]
IsOperator { address: String },
#[returns(andromeda_std::ado_base::version::VersionResponse)]
Version {},
#[returns(::cosmwasm_std::BalanceResponse)]
Balance {
address: ::andromeda_std::amp::AndrAddr,
},
#[returns(Vec<::andromeda_std::ado_base::permissioning::PermissionInfo>)]
Permissions { actor: String, limit: Option<u32>, start_after: Option<String> },
#[returns(Vec<String>)]
PermissionedActions { },
}
}
.into(),
);
#[cfg(feature = "modules")]
{
merged = merge_variants(
merged,
quote! {
enum Right {
#[returns(andromeda_std::ado_base::Module)]
Module { id: ::cosmwasm_std::Uint64 },
#[returns(Vec<String>)]
ModuleIds {},
}
}
.into(),
);
}
#[cfg(feature = "module_hooks")]
{
merged = merge_variants(
merged,
quote! {
enum Right {
#[returns(::cosmwasm_std::Binary)]
AndrHook(::andromeda_std::ado_base::hooks::AndromedaHook),
}
}
.into(),
);
}
merged
}