use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemImpl};
fn get_default_methods(trait_name: &str) -> Vec<syn::ImplItem> {
match trait_name {
"MessageClientV4Interface" => vec![
syn::parse_quote! {
fn only_message_owner(env: &soroban_sdk::Env) {
vialabs_stellar_common::message_client_v4::Base::only_message_owner(env)
}
},
syn::parse_quote! {
fn set_message_owner(env: &soroban_sdk::Env, owner: soroban_sdk::Address) {
vialabs_stellar_common::message_client_v4::Base::set_message_owner(env, owner)
}
},
syn::parse_quote! {
fn get_message_owner(env: &soroban_sdk::Env) -> soroban_sdk::Address {
vialabs_stellar_common::message_client_v4::Base::get_message_owner(env)
}
},
syn::parse_quote! {
fn set_message_gateway(env: &soroban_sdk::Env, contract_address: soroban_sdk::Address) {
vialabs_stellar_common::message_client_v4::Base::set_message_gateway(env, contract_address)
}
},
syn::parse_quote! {
fn get_message_gateway(env: &soroban_sdk::Env) -> soroban_sdk::Address {
vialabs_stellar_common::message_client_v4::Base::get_message_gateway(env)
}
},
syn::parse_quote! {
fn set_message_endpoints(env: &soroban_sdk::Env, chains: soroban_sdk::Vec<u64>, endpoints: soroban_sdk::Vec<soroban_sdk::Bytes>) {
vialabs_stellar_common::message_client_v4::Base::set_message_endpoints(env, chains, endpoints)
}
},
syn::parse_quote! {
fn get_endpoint_by_chain_id(env: &soroban_sdk::Env, chain_id: u64) -> soroban_sdk::Bytes {
vialabs_stellar_common::message_client_v4::Base::get_endpoint_by_chain_id(env, chain_id)
}
},
syn::parse_quote! {
fn message_send(env: &soroban_sdk::Env, destination_chain: u64, chain_data: soroban_sdk::Bytes, confirmations: u32) -> u128 {
vialabs_stellar_common::message_client_v4::Base::message_send(env, destination_chain, chain_data, confirmations)
}
},
syn::parse_quote! {
fn validate_chain_sender(env: &soroban_sdk::Env, source_chain_id: u64, sender: soroban_sdk::Bytes) {
vialabs_stellar_common::message_client_v4::Base::validate_chain_sender(env, source_chain_id, sender)
}
},
syn::parse_quote! {
fn message_process_from_gateway(env: &soroban_sdk::Env, message: vialabs_stellar_common::message_client_v4::ProcessFromGatewayRequest) {
vialabs_stellar_common::message_client_v4::Base::validate_chain_sender(env, message.source_chain_id.clone(), message.sender.clone());
vialabs_stellar_common::message_client_v4::Base::message_process_from_gateway(env, message)
}
},
],
not_supported => {
panic!("Trait {not_supported} is not supported by #[default_impl]")
}
}
}
fn generate_default_impl(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemImpl);
let trait_name = match &input.trait_ {
Some((_, path, _)) => path.segments.last().unwrap().ident.to_string(),
None => panic!("#[default_impl] must be used on a trait implementation"),
};
let mut user_methods = std::collections::HashSet::new();
for item in &input.items {
if let syn::ImplItem::Fn(method) = item {
user_methods.insert(method.sig.ident.to_string());
}
}
let mut default_methods = get_default_methods(&trait_name);
default_methods.retain(|item| {
if let syn::ImplItem::Fn(method) = item {
!user_methods.contains(&method.sig.ident.to_string())
} else {
true
}
});
let mut existing_items = input.items.clone();
existing_items.extend(default_methods);
let new_impl = ItemImpl {
items: existing_items,
..input
};
let expanded = {
quote! { #new_impl }
};
TokenStream::from(quote! { #expanded })
}
#[proc_macro_attribute]
pub fn default_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
assert!(attrs.is_empty(), "This macro does not accept any arguments");
generate_default_impl(item)
}