diff --git a/sylvia-derive/src/interfaces.rs b/sylvia-derive/src/interfaces.rs index 3cd104de..cf6e7887 100644 --- a/sylvia-derive/src/interfaces.rs +++ b/sylvia-derive/src/interfaces.rs @@ -1,7 +1,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use syn::spanned::Spanned; -use syn::{ItemImpl, Type}; +use syn::{ItemImpl, Path, Type}; use crate::crate_module; use crate::parser::attributes::msg::MsgType; @@ -133,4 +133,12 @@ impl Interfaces { } }).collect() } + + pub fn variants_names(&self) -> impl Iterator { + self.interfaces.iter().map(|interface| &interface.variant) + } + + pub fn variants_modules(&self) -> impl Iterator { + self.interfaces.iter().map(|interface| &interface.module) + } } diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs index cb70e542..e2a33979 100644 --- a/sylvia-derive/src/message.rs +++ b/sylvia-derive/src/message.rs @@ -952,6 +952,9 @@ impl<'a> GlueMessage<'a> { } }; + let modules_names = interfaces.variants_modules(); + let variants_names = interfaces.variants_names(); + quote! { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(#sylvia ::serde::Serialize, Clone, Debug, PartialEq)] @@ -1058,6 +1061,22 @@ impl<'a> GlueMessage<'a> { Err(D::Error::custom(err_msg)) } } + + impl #bracketed_wrapper_generics From<<#contract as #sylvia ::types::ContractApi>:: #enum_accessor> + for #contract_enum_name #bracketed_wrapper_generics #full_where_clause { + fn from(a: <#contract as #sylvia ::types::ContractApi>:: #enum_accessor ) -> Self { + Self:: #contract_name (a) + } + } + + #( + impl #bracketed_wrapper_generics From<<#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor> + for #contract_enum_name #bracketed_wrapper_generics #full_where_clause { + fn from(a: <#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor ) -> Self { + Self:: #variants_names (a) + } + } + )* } } } diff --git a/sylvia/tests/interface_impl.rs b/sylvia/tests/interface_impl.rs new file mode 100644 index 00000000..6bd6615d --- /dev/null +++ b/sylvia/tests/interface_impl.rs @@ -0,0 +1,137 @@ +use cosmwasm_std::{Response, StdError, StdResult}; +use sylvia::contract; +use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, SudoCtx}; + +mod interface1 { + use cosmwasm_std::{Response, StdError, StdResult}; + use sylvia::interface; + use sylvia::types::{ExecCtx, QueryCtx, SudoCtx}; + + #[interface] + #[sv::custom(msg=cosmwasm_std::Empty, query=cosmwasm_std::Empty)] + pub trait SylviaInterface1 { + type Error: From; + + #[sv::msg(exec)] + fn interface1_method_exec(&self, _ctx: ExecCtx) -> StdResult; + + #[sv::msg(query)] + fn interface1_method_query(&self, _ctx: QueryCtx) -> StdResult; + + #[sv::msg(sudo)] + fn interface1_method_sudo(&self, _ctx: SudoCtx) -> StdResult; + } +} + +mod interface2 { + use cosmwasm_std::{Response, StdError, StdResult}; + use sylvia::interface; + use sylvia::types::{ExecCtx, QueryCtx, SudoCtx}; + + #[interface] + #[sv::custom(msg=cosmwasm_std::Empty, query=cosmwasm_std::Empty)] + pub trait SylviaInterface2 { + type Error: From; + + #[sv::msg(exec)] + fn interface2_method_exec(&self, _ctx: ExecCtx) -> StdResult; + + #[sv::msg(query)] + fn interface2_method_query(&self, _ctx: QueryCtx) -> StdResult; + + #[sv::msg(sudo)] + fn interface2_method_sudo(&self, _ctx: SudoCtx) -> StdResult; + } +} + +pub struct Contract; + +#[contract] +#[sv::messages(interface1)] +#[sv::messages(interface2)] +impl Contract { + pub fn new() -> Self { + Self + } + + #[sv::msg(instantiate)] + fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult { + Ok(Response::new()) + } + + #[sv::msg(exec)] + fn contract_method_exec(&self, _ctx: ExecCtx) -> StdResult { + Ok(Response::new()) + } + + #[sv::msg(query)] + fn contract_method_query(&self, _ctx: QueryCtx) -> StdResult { + Ok(Response::new()) + } + + #[sv::msg(sudo)] + fn contract_method_sudo(&self, _ctx: SudoCtx) -> StdResult { + Ok(Response::new()) + } +} + +impl interface1::SylviaInterface1 for Contract { + type Error = StdError; + + fn interface1_method_exec(&self, _ctx: ExecCtx) -> StdResult { + Ok(Response::new()) + } + + fn interface1_method_query(&self, _ctx: QueryCtx) -> StdResult { + Ok(Response::new()) + } + + fn interface1_method_sudo(&self, _ctx: SudoCtx) -> StdResult { + Ok(Response::new()) + } +} + +impl interface2::SylviaInterface2 for Contract { + type Error = StdError; + + fn interface2_method_exec(&self, _ctx: ExecCtx) -> StdResult { + Ok(Response::new()) + } + + fn interface2_method_query(&self, _ctx: QueryCtx) -> StdResult { + Ok(Response::new()) + } + + fn interface2_method_sudo(&self, _ctx: SudoCtx) -> StdResult { + Ok(Response::new()) + } +} + +impl Default for Contract { + fn default() -> Self { + Self::new() + } +} + +#[test] +fn check_from_trait_implementations() { + let _ = + sv::ContractExecMsg::from(interface1::sv::SylviaInterface1ExecMsg::Interface1MethodExec {}); + let _ = sv::ContractQueryMsg::from( + interface1::sv::SylviaInterface1QueryMsg::Interface1MethodQuery {}, + ); + let _ = + sv::ContractSudoMsg::from(interface1::sv::SylviaInterface1SudoMsg::Interface1MethodSudo {}); + + let _ = + sv::ContractExecMsg::from(interface2::sv::SylviaInterface2ExecMsg::Interface2MethodExec {}); + let _ = sv::ContractQueryMsg::from( + interface2::sv::SylviaInterface2QueryMsg::Interface2MethodQuery {}, + ); + let _ = + sv::ContractSudoMsg::from(interface2::sv::SylviaInterface2SudoMsg::Interface2MethodSudo {}); + + let _ = sv::ContractExecMsg::from(sv::ExecMsg::ContractMethodExec {}); + let _ = sv::ContractQueryMsg::from(sv::QueryMsg::ContractMethodQuery {}); + let _ = sv::ContractSudoMsg::from(sv::SudoMsg::ContractMethodSudo {}); +}