diff --git a/Cargo.lock b/Cargo.lock index 48c579c3..2f59e532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,7 +236,7 @@ dependencies = [ "cw-storage-plus", "cw-utils", "derivative", - "itertools", + "itertools 0.11.0", "prost", "schemars", "serde", @@ -478,6 +478,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.5" @@ -624,7 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.39", @@ -864,6 +873,7 @@ name = "sylvia-derive" version = "0.9.1" dependencies = [ "convert_case", + "itertools 0.12.0", "proc-macro-crate", "proc-macro-error", "proc-macro2", diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 4a2b8298..a1f543b3 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -274,7 +274,7 @@ dependencies = [ "cw-storage-plus", "cw-utils", "derivative", - "itertools", + "itertools 0.11.0", "prost", "schemars", "serde", @@ -700,6 +700,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -856,7 +865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.39", @@ -1093,6 +1102,7 @@ name = "sylvia-derive" version = "0.9.1" dependencies = [ "convert_case", + "itertools 0.12.0", "proc-macro-crate", "proc-macro-error", "proc-macro2", diff --git a/examples/contracts/generic_contract/src/bin/schema.rs b/examples/contracts/generic_contract/src/bin/schema.rs index db8d7541..4f265745 100644 --- a/examples/contracts/generic_contract/src/bin/schema.rs +++ b/examples/contracts/generic_contract/src/bin/schema.rs @@ -7,7 +7,7 @@ fn main() { write_api! { instantiate: InstantiateMsg, - execute: ContractExecMsg, - query: ContractQueryMsg, + execute: ContractExecMsg, + query: ContractQueryMsg, } } diff --git a/examples/contracts/generic_contract/src/contract.rs b/examples/contracts/generic_contract/src/contract.rs index 12f605f9..d60b95cb 100644 --- a/examples/contracts/generic_contract/src/contract.rs +++ b/examples/contracts/generic_contract/src/contract.rs @@ -3,46 +3,43 @@ use cw_storage_plus::Item; use serde::de::DeserializeOwned; use serde::Deserialize; use sylvia::types::{ - CustomMsg, ExecCtx, InstantiateCtx, MigrateCtx, QueryCtx, ReplyCtx, SvCustomMsg, + CustomMsg, CustomQuery, ExecCtx, InstantiateCtx, MigrateCtx, QueryCtx, ReplyCtx, SvCustomMsg, }; use sylvia::{contract, schemars}; -#[cfg(not(feature = "library"))] -use sylvia::entry_points; +// #[cfg(not(feature = "library"))] +// use sylvia::entry_points; -pub struct GenericContract< - InstantiateParam, - ExecParam, - QueryParam, - MigrateParam, - RetType, - FieldType, -> { - _field: Item<'static, FieldType>, +pub struct GenericContract +{ + _field: Item<'static, FieldT>, _phantom: std::marker::PhantomData<( - InstantiateParam, - ExecParam, - QueryParam, - MigrateParam, - RetType, + InstantiateT, + ExecT, + QueryT, + MigrateT, + CustomMsgT, + CustomQueryT, )>, } -#[cfg_attr(not(feature = "library"), entry_points(generics))] +// #[cfg_attr(not(feature = "library"), entry_points(generics))] +// #[sylvia::entry_points(generics)] #[contract] -#[messages(cw1 as Cw1: custom(msg))] -#[messages(generic as Generic: custom(msg))] -#[messages(custom_and_generic as CustomAndGeneric)] -#[sv::custom(msg=SvCustomMsg)] -impl - GenericContract +// #[messages(cw1 as Cw1: custom(msg, query))] +#[messages(generic as Generic: custom(msg, query))] +// #[messages(custom_and_generic as CustomAndGeneric)] +#[sv::custom(msg=CustomMsgT, query=CustomQueryT)] +impl + GenericContract where - for<'msg_de> InstantiateParam: CustomMsg + Deserialize<'msg_de> + 'msg_de, - ExecParam: CustomMsg + DeserializeOwned + 'static, - QueryParam: CustomMsg + DeserializeOwned + 'static, - MigrateParam: CustomMsg + DeserializeOwned + 'static, - RetType: CustomMsg + DeserializeOwned + 'static, - FieldType: 'static, + for<'msg_de> InstantiateT: CustomMsg + Deserialize<'msg_de> + 'msg_de, + ExecT: CustomMsg + DeserializeOwned + 'static, + QueryT: CustomMsg + DeserializeOwned + 'static, + MigrateT: CustomMsg + DeserializeOwned + 'static, + CustomMsgT: CustomMsg + DeserializeOwned + 'static, + CustomQueryT: CustomQuery + 'static, + FieldT: 'static, { pub const fn new() -> Self { Self { @@ -54,42 +51,42 @@ where #[msg(instantiate)] pub fn instantiate( &self, - _ctx: InstantiateCtx, - _msg: InstantiateParam, - ) -> StdResult> { + _ctx: InstantiateCtx, + _msg: InstantiateT, + ) -> StdResult> { Ok(Response::new()) } #[msg(exec)] pub fn contract_execute( &self, - _ctx: ExecCtx, - _msg: ExecParam, - ) -> StdResult> { + _ctx: ExecCtx, + _msg: ExecT, + ) -> StdResult> { Ok(Response::new()) } #[msg(query)] - pub fn contract_query( - &self, - _ctx: QueryCtx, - _msg: QueryParam, - ) -> StdResult> { - Ok(Response::new()) + pub fn contract_query(&self, _ctx: QueryCtx, _msg: QueryT) -> StdResult { + Ok(String::default()) } #[msg(migrate)] pub fn migrate( &self, - _ctx: MigrateCtx, - _msg: MigrateParam, - ) -> StdResult> { + _ctx: MigrateCtx, + _msg: MigrateT, + ) -> StdResult> { Ok(Response::new()) } #[allow(dead_code)] #[msg(reply)] - fn reply(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult> { + fn reply( + &self, + _ctx: ReplyCtx, + _reply: Reply, + ) -> StdResult> { Ok(Response::new()) } } @@ -98,17 +95,18 @@ where mod tests { use super::sv::multitest_utils::CodeId; use sylvia::multitest::App; - use sylvia::types::SvCustomMsg; + use sylvia::types::{SvCustomMsg, SvCustomQuery}; #[test] fn generic_contract() { - let app = App::>::custom(|_, _, _| {}); + let app = App::>::custom(|_, _, _| {}); let code_id: CodeId< SvCustomMsg, SvCustomMsg, SvCustomMsg, super::SvCustomMsg, super::SvCustomMsg, + SvCustomQuery, String, _, > = CodeId::store_code(&app); diff --git a/examples/contracts/generic_contract/src/custom_and_generic.rs b/examples/contracts/generic_contract/src/custom_and_generic.rs index 2dfadcd0..396eaddb 100644 --- a/examples/contracts/generic_contract/src/custom_and_generic.rs +++ b/examples/contracts/generic_contract/src/custom_and_generic.rs @@ -1,79 +1,89 @@ -use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; -use custom_and_generic::CustomAndGeneric; -use sylvia::contract; -use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg}; - -#[contract(module = crate::contract)] -#[messages(custom_and_generic as CustomAndGeneric)] -#[sv::custom(msg=sylvia::types::SvCustomMsg)] -impl - CustomAndGeneric - for crate::contract::GenericContract< - InstantiateParam, - ExecParam, - QueryParam, - MigrateParam, - RetType, - FieldType, - > -{ - type Error = StdError; - - #[msg(exec)] - fn custom_generic_execute( - &self, - _ctx: ExecCtx, - _msgs: Vec>, - ) -> StdResult> { - Ok(Response::new()) - } - - #[msg(query)] - fn custom_generic_query( - &self, - _ctx: QueryCtx, - _msg: sylvia::types::SvCustomMsg, - ) -> StdResult { - Ok(SvCustomMsg {}) - } -} - -#[cfg(test)] -mod tests { - use super::sv::test_utils::CustomAndGeneric; - use crate::contract::sv::multitest_utils::CodeId; - use sylvia::{multitest::App, types::SvCustomMsg}; - - #[test] - fn proxy_methods() { - let app = App::>::custom(|_, _, _| {}); - let code_id = CodeId::< - SvCustomMsg, - sylvia::types::SvCustomMsg, - SvCustomMsg, - SvCustomMsg, - sylvia::types::SvCustomMsg, - String, - _, - >::store_code(&app); - - let owner = "owner"; - - let contract = code_id - .instantiate(SvCustomMsg {}) - .with_label("GenericContract") - .with_admin(owner) - .call(owner) - .unwrap(); - - contract - .custom_and_generic_proxy() - .custom_generic_execute(vec![]) - .call(owner) - .unwrap(); - contract - .custom_and_generic_proxy() - .custom_generic_query(SvCustomMsg {}) - .unwrap(); - } -} +// use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; +// use custom_and_generic::CustomAndGeneric; +// use sylvia::contract; +// use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg, SvCustomQuery}; +// +// #[contract(module = crate::contract)] +// #[messages(custom_and_generic as CustomAndGeneric)] +// #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)] +// impl +// CustomAndGeneric< +// SvCustomMsg, +// SvCustomMsg, +// sylvia::types::SvCustomQuery, +// sylvia::types::SvCustomMsg, +// > +// for crate::contract::GenericContract< +// InstantiateParam, +// ExecParam, +// QueryParam, +// MigrateParam, +// RetType, +// CtxQuery, +// FieldType, +// > +// { +// type Error = StdError; +// +// #[msg(exec)] +// fn custom_generic_execute( +// &self, +// _ctx: ExecCtx, +// _msgs: Vec>, +// ) -> StdResult> { +// Ok(Response::new()) +// } +// +// #[msg(query)] +// fn custom_generic_query( +// &self, +// _ctx: QueryCtx, +// _msg: sylvia::types::SvCustomMsg, +// ) -> StdResult { +// Ok(SvCustomMsg {}) +// } +// } +// +// #[cfg(test)] +// mod tests { +// use super::sv::test_utils::CustomAndGeneric; +// use crate::contract::sv::multitest_utils::CodeId; +// use sylvia::{ +// multitest::App, +// types::{SvCustomMsg, SvCustomQuery}, +// }; +// +// #[test] +// fn proxy_methods() { +// let app = App::>::custom(|_, _, _| {}); +// let code_id = CodeId::< +// SvCustomMsg, +// sylvia::types::SvCustomMsg, +// SvCustomMsg, +// SvCustomMsg, +// SvCustomMsg, +// SvCustomQuery, +// String, +// _, +// >::store_code(&app); +// +// let owner = "owner"; +// +// let contract = code_id +// .instantiate(SvCustomMsg {}) +// .with_label("GenericContract") +// .with_admin(owner) +// .call(owner) +// .unwrap(); +// +// contract +// .custom_and_generic_proxy() +// .custom_generic_execute(vec![]) +// .call(owner) +// .unwrap(); +// contract +// .custom_and_generic_proxy() +// .custom_generic_query(SvCustomMsg {}) +// .unwrap(); +// } +// } diff --git a/examples/contracts/generic_contract/src/cw1.rs b/examples/contracts/generic_contract/src/cw1.rs index 410bd13d..91b61b92 100644 --- a/examples/contracts/generic_contract/src/cw1.rs +++ b/examples/contracts/generic_contract/src/cw1.rs @@ -1,72 +1,77 @@ -use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; -use cw1::{CanExecuteResp, Cw1}; -use sylvia::contract; -use sylvia::types::{ExecCtx, QueryCtx}; - -#[contract(module = crate::contract)] -#[messages(cw1 as Cw1)] -#[sv::custom(msg=sylvia::types::SvCustomMsg)] -impl Cw1 - for crate::contract::GenericContract< - InstantiateParam, - ExecParam, - QueryParam, - MigrateParam, - RetType, - FieldType, - > -{ - type Error = StdError; - - #[msg(exec)] - fn execute(&self, _ctx: ExecCtx, _msgs: Vec) -> StdResult { - Ok(Response::new()) - } - - #[msg(query)] - fn can_execute( - &self, - _ctx: QueryCtx, - _sender: String, - _msg: CosmosMsg, - ) -> StdResult { - Ok(CanExecuteResp::default()) - } -} - -#[cfg(test)] -mod tests { - use super::sv::test_utils::Cw1; - use crate::contract::sv::multitest_utils::CodeId; - use cosmwasm_std::{CosmosMsg, Empty}; - use sylvia::{multitest::App, types::SvCustomMsg}; - - #[test] - fn proxy_methods() { - let app = App::>::custom(|_, _, _| {}); - let code_id = CodeId::< - SvCustomMsg, - sylvia::types::SvCustomMsg, - SvCustomMsg, - SvCustomMsg, - sylvia::types::SvCustomMsg, - String, - _, - >::store_code(&app); - - let owner = "owner"; - - let contract = code_id - .instantiate(SvCustomMsg {}) - .with_label("GenericContract") - .with_admin(owner) - .call(owner) - .unwrap(); - - contract.cw1_proxy().execute(vec![]).call(owner).unwrap(); - contract - .cw1_proxy() - .can_execute("sender".to_owned(), CosmosMsg::Custom(Empty {})) - .unwrap(); - } -} +// use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; +// use cw1::{CanExecuteResp, Cw1}; +// use sylvia::contract; +// use sylvia::types::{ExecCtx, QueryCtx}; +// +// #[contract(module = crate::contract)] +// #[messages(cw1 as Cw1)] +// #[sv::custom(msg=sylvia::types::SvCustomMsg, query=sylvia::types::SvCustomQuery)] +// impl Cw1 +// for crate::contract::GenericContract< +// InstantiateParam, +// ExecParam, +// QueryParam, +// MigrateParam, +// RetType, +// CtxQuery, +// FieldType, +// > +// { +// type Error = StdError; +// +// #[msg(exec)] +// fn execute(&self, _ctx: ExecCtx, _msgs: Vec) -> StdResult { +// Ok(Response::new()) +// } +// +// #[msg(query)] +// fn can_execute( +// &self, +// _ctx: QueryCtx, +// _sender: String, +// _msg: CosmosMsg, +// ) -> StdResult { +// Ok(CanExecuteResp::default()) +// } +// } +// +// #[cfg(test)] +// mod tests { +// use super::sv::test_utils::Cw1; +// use crate::contract::sv::multitest_utils::CodeId; +// use cosmwasm_std::{CosmosMsg, Empty}; +// use sylvia::{ +// multitest::App, +// types::{SvCustomMsg, SvCustomQuery}, +// }; +// +// #[test] +// fn proxy_methods() { +// let app = App::>::custom(|_, _, _| {}); +// let code_id = CodeId::< +// SvCustomMsg, +// sylvia::types::SvCustomMsg, +// SvCustomMsg, +// SvCustomMsg, +// SvCustomMsg, +// SvCustomQuery, +// String, +// _, +// >::store_code(&app); +// +// let owner = "owner"; +// +// let contract = code_id +// .instantiate(SvCustomMsg {}) +// .with_label("GenericContract") +// .with_admin(owner) +// .call(owner) +// .unwrap(); +// +// contract.cw1_proxy().execute(vec![]).call(owner).unwrap(); +// contract +// .cw1_proxy() +// .can_execute("sender".to_owned(), CosmosMsg::Custom(Empty {})) +// .unwrap(); +// } +// } diff --git a/examples/contracts/generic_contract/src/generic.rs b/examples/contracts/generic_contract/src/generic.rs index 27176d94..615ff52a 100644 --- a/examples/contracts/generic_contract/src/generic.rs +++ b/examples/contracts/generic_contract/src/generic.rs @@ -1,30 +1,37 @@ -use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; +use cosmwasm_std::{CosmosMsg, CustomMsg, Response, StdError, StdResult}; use generic::Generic; +use serde::de::DeserializeOwned; +use serde::Deserialize; use sylvia::contract; -use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg}; +use sylvia::types::{CustomQuery, ExecCtx, QueryCtx, SvCustomMsg}; #[contract(module = crate::contract)] #[messages(generic as Generic)] -#[sv::custom(msg=SvCustomMsg)] -impl - Generic +#[sv::custom(msg=CustomMsgT, query=CustomQueryT)] +impl + Generic for crate::contract::GenericContract< - InstantiateParam, - ExecParam, - QueryParam, - MigrateParam, - RetType, - FieldType, + InstantiateT, + ExecT, + QueryT, + MigrateT, + CustomMsgT, + CustomQueryT, + FieldT, > +where + for<'msg_de> InstantiateT: CustomMsg + Deserialize<'msg_de> + 'msg_de, + ExecT: CustomMsg + DeserializeOwned + 'static, + QueryT: CustomMsg + DeserializeOwned + 'static, + MigrateT: CustomMsg + DeserializeOwned + 'static, + CustomMsgT: CustomMsg + DeserializeOwned + 'static, + CustomQueryT: CustomQuery + 'static, + FieldT: 'static, { type Error = StdError; #[msg(exec)] - fn generic_exec( - &self, - _ctx: ExecCtx, - _msgs: Vec>, - ) -> StdResult { + fn generic_exec(&self, _ctx: ExecCtx, _msgs: Vec>) -> StdResult { Ok(Response::new()) } @@ -32,12 +39,12 @@ impl // It's because we have to map unique generics used as they can be used multiple times. // If for some reason like here one type would be used in place of two generics either full // path or some alias has to be used. + // + // Sylvia will fail to recognize generic used if their path is different. + // F.e. if we this query would return `SvCustomMsg` and we would pass + // `sylvia::types::SvCustomMsg` to the `Generic` trait paths would not match. #[msg(query)] - fn generic_query( - &self, - _ctx: QueryCtx, - _msg: sylvia::types::SvCustomMsg, - ) -> StdResult { + fn generic_query(&self, _ctx: QueryCtx, _msg: QueryT) -> StdResult { Ok(SvCustomMsg {}) } } @@ -48,17 +55,18 @@ mod tests { use crate::contract::sv::multitest_utils::CodeId; use cosmwasm_std::CosmosMsg; use sylvia::multitest::App; - use sylvia::types::SvCustomMsg; + use sylvia::types::{SvCustomMsg, SvCustomQuery}; #[test] fn proxy_methods() { - let app = App::>::custom(|_, _, _| {}); + let app = App::>::custom(|_, _, _| {}); let code_id: CodeId< SvCustomMsg, sylvia::types::SvCustomMsg, SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg, + SvCustomQuery, String, _, > = CodeId::store_code(&app); @@ -73,10 +81,9 @@ mod tests { .unwrap(); contract - .generic_proxy() .generic_exec(vec![CosmosMsg::Custom(SvCustomMsg {})]) .call(owner) .unwrap(); - contract.generic_proxy().generic_query(SvCustomMsg).unwrap(); + contract.generic_query(SvCustomMsg).unwrap(); } } diff --git a/examples/contracts/generic_iface_on_contract/src/contract.rs b/examples/contracts/generic_iface_on_contract/src/contract.rs index a8f92805..70c602fd 100644 --- a/examples/contracts/generic_iface_on_contract/src/contract.rs +++ b/examples/contracts/generic_iface_on_contract/src/contract.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{Response, StdResult}; -use sylvia::types::{InstantiateCtx, SvCustomMsg}; +use sylvia::types::{InstantiateCtx, SvCustomMsg, SvCustomQuery}; use sylvia::{contract, schemars}; #[cfg(not(feature = "library"))] @@ -9,18 +9,21 @@ pub struct NonGenericContract; #[cfg_attr(not(feature = "library"), entry_points)] #[contract] -#[messages(generic as Generic: custom(msg))] -#[messages(custom_and_generic as CustomAndGeneric)] -#[messages(cw1 as Cw1: custom(msg))] +#[messages(generic as Generic: custom(msg, query))] +#[messages(custom_and_generic as CustomAndGeneric)] +#[messages(cw1 as Cw1: custom(msg, query))] /// Required if interface returns generic `Response` -#[sv::custom(msg=SvCustomMsg)] +#[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)] impl NonGenericContract { pub const fn new() -> Self { Self } #[msg(instantiate)] - pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult> { + pub fn instantiate( + &self, + _ctx: InstantiateCtx, + ) -> StdResult> { Ok(Response::new()) } } @@ -28,6 +31,7 @@ impl NonGenericContract { #[cfg(test)] mod tests { use cosmwasm_std::{CosmosMsg, Empty}; + use sylvia::types::SvCustomQuery; use sylvia::{multitest::App, types::SvCustomMsg}; use super::NonGenericContract; @@ -38,7 +42,7 @@ mod tests { #[test] fn mt_helpers() { let _ = NonGenericContract::new(); - let app = App::>::custom(|_, _, _| {}); + let app = App::>::custom(|_, _, _| {}); let code_id = super::sv::multitest_utils::CodeId::store_code(&app); let owner = "owner"; diff --git a/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs b/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs index 90052b86..346d4f27 100644 --- a/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs +++ b/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs @@ -1,12 +1,12 @@ use cosmwasm_std::{CosmosMsg, Response, StdError, StdResult}; use custom_and_generic::CustomAndGeneric; use sylvia::contract; -use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg}; +use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg, SvCustomQuery}; #[contract(module = crate::contract)] #[messages(custom_and_generic as CustomAndGeneric)] -#[sv::custom(msg=sylvia::types::SvCustomMsg)] -impl CustomAndGeneric +#[sv::custom(msg=sylvia::types::SvCustomMsg, query=SvCustomQuery)] +impl CustomAndGeneric for crate::contract::NonGenericContract { type Error = StdError; @@ -14,7 +14,7 @@ impl CustomAndGeneric #[msg(exec)] fn custom_generic_execute( &self, - _ctx: ExecCtx, + _ctx: ExecCtx, _msgs: Vec>, ) -> StdResult> { Ok(Response::new()) @@ -23,7 +23,7 @@ impl CustomAndGeneric #[msg(query)] fn custom_generic_query( &self, - _ctx: QueryCtx, + _ctx: QueryCtx, _msg: sylvia::types::SvCustomMsg, ) -> StdResult { Ok(SvCustomMsg {}) diff --git a/examples/interfaces/custom-and-generic/src/lib.rs b/examples/interfaces/custom-and-generic/src/lib.rs index f56d4503..d7ff14c7 100644 --- a/examples/interfaces/custom-and-generic/src/lib.rs +++ b/examples/interfaces/custom-and-generic/src/lib.rs @@ -6,11 +6,12 @@ use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; #[interface] -#[sv::custom(msg=RetType)] -pub trait CustomAndGeneric +#[sv::custom(msg=RetType, query=CtxQuery)] +pub trait CustomAndGeneric where for<'msg_de> ExecParam: CustomMsg + Deserialize<'msg_de>, QueryParam: sylvia::types::CustomMsg, + CtxQuery: sylvia::types::CustomQuery, RetType: CustomMsg + DeserializeOwned, { type Error: From; @@ -18,14 +19,14 @@ where #[msg(exec)] fn custom_generic_execute( &self, - ctx: ExecCtx, + ctx: ExecCtx, msgs: Vec>, ) -> Result, Self::Error>; #[msg(query)] fn custom_generic_query( &self, - ctx: QueryCtx, + ctx: QueryCtx, param: QueryParam, ) -> Result; } @@ -34,7 +35,7 @@ where mod tests { use cosmwasm_std::testing::mock_dependencies; use cosmwasm_std::{Addr, CosmosMsg, Empty, QuerierWrapper}; - use sylvia::types::{InterfaceApi, SvCustomMsg}; + use sylvia::types::{InterfaceApi, SvCustomMsg, SvCustomQuery}; use crate::sv::Querier; @@ -58,11 +59,11 @@ mod tests { // Construct messages with Interface extension let _ = - as InterfaceApi>::Query::custom_generic_query( + as InterfaceApi>::Query::custom_generic_query( SvCustomMsg {}, ); let _= - as InterfaceApi>::Exec::custom_generic_execute( + as InterfaceApi>::Exec::custom_generic_execute( vec![ CosmosMsg::Custom(SvCustomMsg{}), ]); } diff --git a/examples/interfaces/generic/src/lib.rs b/examples/interfaces/generic/src/lib.rs index f6801536..c144aa23 100644 --- a/examples/interfaces/generic/src/lib.rs +++ b/examples/interfaces/generic/src/lib.rs @@ -5,11 +5,11 @@ use sylvia::types::{ExecCtx, QueryCtx}; use sylvia::{interface, schemars}; #[interface] -pub trait Generic +pub trait Generic where - for<'msg_de> ExecParam: CustomMsg + Deserialize<'msg_de>, - QueryParam: sylvia::types::CustomMsg, - RetType: CustomMsg + DeserializeOwned, + for<'msg_de> ExecT: CustomMsg + Deserialize<'msg_de>, + QueryT: sylvia::types::CustomMsg, + RetT: CustomMsg + DeserializeOwned, { type Error: From; @@ -17,11 +17,11 @@ where fn generic_exec( &self, ctx: ExecCtx, - msgs: Vec>, + msgs: Vec>, ) -> Result; #[msg(query)] - fn generic_query(&self, ctx: QueryCtx, param: QueryParam) -> Result; + fn generic_query(&self, ctx: QueryCtx, param: QueryT) -> Result; } #[cfg(test)] diff --git a/sylvia-derive/Cargo.toml b/sylvia-derive/Cargo.toml index ebbcdf9e..4185f786 100644 --- a/sylvia-derive/Cargo.toml +++ b/sylvia-derive/Cargo.toml @@ -31,6 +31,7 @@ proc-macro2 = "1.0.50" convert_case = "0.6.0" proc-macro-error = "1.0.4" proc-macro-crate = "1.3.0" +itertools = "0.12.0" [dev-dependencies] sylvia-runtime-macros = "0.6.0" diff --git a/sylvia-derive/src/input.rs b/sylvia-derive/src/input.rs index 839702cc..5307e002 100644 --- a/sylvia-derive/src/input.rs +++ b/sylvia-derive/src/input.rs @@ -1,15 +1,8 @@ use proc_macro2::{Span, TokenStream}; use proc_macro_error::emit_error; -use quote::{quote, ToTokens}; -use syn::parse::{Parse, Parser}; -use syn::spanned::Spanned; -use syn::{ - parse_quote, GenericArgument, GenericParam, Ident, ItemImpl, ItemTrait, PathArguments, - TraitItem, Type, -}; +use quote::quote; +use syn::{GenericArgument, GenericParam, Ident, ItemImpl, ItemTrait, PathArguments, TraitItem}; -use crate::check_generics::GetPath; -use crate::crate_module; use crate::interfaces::Interfaces; use crate::message::{ ContractApi, ContractEnumMessage, EnumMessage, GlueMessage, InterfaceApi, MsgVariants, @@ -18,6 +11,7 @@ use crate::message::{ use crate::multitest::{MultitestHelpers, TraitMultitestHelpers}; use crate::parser::{ContractArgs, ContractErrorAttr, Custom, MsgType, OverrideEntryPoints}; use crate::remote::Remote; +use crate::utils::is_trait; use crate::variant_descs::AsVariantDescs; /// Preprocessed `interface` macro input @@ -30,7 +24,7 @@ pub struct TraitInput<'a> { /// Preprocessed `contract` macro input for non-trait impl block pub struct ImplInput<'a> { attributes: &'a ContractArgs, - error: Type, + error: ContractErrorAttr, item: &'a ItemImpl, generics: Vec<&'a GenericParam>, custom: Custom<'a>, @@ -129,25 +123,8 @@ impl<'a> TraitInput<'a> { impl<'a> ImplInput<'a> { pub fn new(attributes: &'a ContractArgs, item: &'a ItemImpl) -> Self { - let sylvia = crate_module(); - let generics = item.generics.params.iter().collect(); - - let error = item - .attrs - .iter() - .find(|attr| attr.path.is_ident("error")) - .and_then( - |attr| match ContractErrorAttr::parse.parse2(attr.tokens.clone()) { - Ok(error) => Some(error.error), - Err(err) => { - emit_error!(attr.span(), err); - None - } - }, - ) - .unwrap_or_else(|| parse_quote! { #sylvia ::cw_std::StdError }); - + let error = ContractErrorAttr::new(item); let custom = Custom::new(&item.attrs); let override_entry_points = OverrideEntryPoints::new(&item.attrs); let interfaces = Interfaces::new(item); @@ -164,17 +141,14 @@ impl<'a> ImplInput<'a> { } pub fn process(&self) -> TokenStream { - let is_trait = self.item.trait_.is_some(); - - match is_trait { + match is_trait(self.item) { true => self.process_interface(), false => self.process_contract(), } } fn process_interface(&self) -> TokenStream { - let interface_generics = self.extract_generic_argument(); - let multitest_helpers = self.emit_multitest_helpers(&interface_generics); + let multitest_helpers = self.emit_multitest_helpers(); let querier_bound_for_impl = self.emit_querier_for_bound_impl(); #[cfg(not(tarpaulin_include))] @@ -194,9 +168,10 @@ impl<'a> ImplInput<'a> { item, generics, custom, + interfaces, .. } = self; - let multitest_helpers = self.emit_multitest_helpers(generics); + let multitest_helpers = self.emit_multitest_helpers(); let where_clause = &item.generics.where_clause; let querier = MsgVariants::new( @@ -209,7 +184,14 @@ impl<'a> ImplInput<'a> { let messages = self.emit_messages(); let remote = Remote::new(&self.interfaces).emit(); let querier_from_impl = self.interfaces.emit_querier_from_impl(); - let contract_api = ContractApi::new(item, generics, custom).emit(); + let contract_api = ContractApi::new( + item, + generics, + &item.generics.where_clause, + custom, + interfaces, + ) + .emit(); #[cfg(not(tarpaulin_include))] { @@ -306,41 +288,52 @@ impl<'a> ImplInput<'a> { .get_only_interface() .map(|interface| &interface.module); let contract_module = self.attributes.module.as_ref(); - let generics = self.extract_generic_argument(); - let variants = MsgVariants::new(self.item.as_variants(), MsgType::Query, &generics, &None); + let generic_args = self.extract_generic_argument(); + let where_clause = &self.item.generics.where_clause; + + let variants_args = MsgVariants::new( + self.item.as_variants(), + MsgType::Query, + &generic_args, + where_clause, + ); + let variants_params = MsgVariants::new( + self.item.as_variants(), + MsgType::Query, + &self.generics, + where_clause, + ); + let generic_args = variants_args.used_generics(); - variants.emit_querier_for_bound_impl(trait_module, contract_module) + variants_params.emit_querier_for_bound_impl(trait_module, contract_module, generic_args) } - fn emit_multitest_helpers(&self, generics: &[&Generic]) -> TokenStream - where - Generic: ToTokens + PartialEq + GetPath, - { + fn emit_multitest_helpers(&self) -> TokenStream { + if !cfg!(feature = "mt") { + return quote! {}; + } + let Self { item, - error, custom, override_entry_points, interfaces, .. } = self; + let contract_module = self.attributes.module.as_ref(); + let generic_args = self.extract_generic_argument(); + let generic_params = &self.generics; - let is_trait = self.item.trait_.is_some(); - - if cfg!(feature = "mt") { - MultitestHelpers::new( - item, - is_trait, - error, - generics, - custom, - override_entry_points, - interfaces, - ) - .emit() - } else { - quote! {} - } + MultitestHelpers::new( + item, + generic_params, + &generic_args, + custom, + override_entry_points, + interfaces, + &contract_module, + ) + .emit() } } diff --git a/sylvia-derive/src/interfaces.rs b/sylvia-derive/src/interfaces.rs index fbfe9718..1b28eece 100644 --- a/sylvia-derive/src/interfaces.rs +++ b/sylvia-derive/src/interfaces.rs @@ -4,7 +4,7 @@ use proc_macro_error::emit_error; use quote::quote; use syn::parse::{Parse, Parser}; use syn::spanned::Spanned; -use syn::{ItemImpl, Path, Type}; +use syn::{GenericArgument, ItemImpl, Path, Type}; use crate::crate_module; use crate::parser::{ContractMessageAttr, MsgType}; @@ -171,6 +171,13 @@ impl Interfaces { self.interfaces.iter().map(|interface| &interface.module) } + pub fn as_generic_args(&self) -> Vec<&GenericArgument> { + self.interfaces + .iter() + .flat_map(|interface| &interface.generics) + .collect() + } + pub fn get_only_interface(&self) -> Option<&ContractMessageAttr> { let interfaces = &self.interfaces; match interfaces.len() { @@ -180,9 +187,9 @@ impl Interfaces { let first = &interfaces[0]; for redefined in &interfaces[1..] { emit_error!( - redefined.module, "The attribute `messages` is redefined"; - note = first.module.span() => "Previous definition of the attribute `messsages`"; - note = "Only one `messages` attribute can exist on an interface implementation on contract" + redefined.module, "The attribute `messages` is redefined"; + note = first.module.span() => "Previous definition of the attribute `messsages`"; + note = "Only one `messages` attribute can exist on an interface implementation on contract" ); } None diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs index 2ac57d84..86b83023 100644 --- a/sylvia-derive/src/message.rs +++ b/sylvia-derive/src/message.rs @@ -7,10 +7,12 @@ use crate::parser::{ }; use crate::strip_generics::StripGenerics; use crate::utils::{ - as_where_clause, emit_bracketed_generics, extract_return_type, filter_wheres, process_fields, + as_where_clause, emit_bracketed_generics, extract_return_type, filter_generics, filter_wheres, + process_fields, }; use crate::variant_descs::{AsVariantDescs, VariantDescs}; use convert_case::{Case, Casing}; +use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use proc_macro_error::emit_error; use quote::{quote, ToTokens}; @@ -356,7 +358,7 @@ pub struct ContractEnumMessage<'a> { variants: MsgVariants<'a, GenericParam>, msg_ty: MsgType, contract: &'a Type, - error: &'a Type, + error: &'a ContractErrorAttr, custom: &'a Custom<'a>, where_clause: &'a Option, } @@ -366,7 +368,7 @@ impl<'a> ContractEnumMessage<'a> { source: &'a ItemImpl, msg_ty: MsgType, generics: &'a [&'a GenericParam], - error: &'a Type, + error: &'a ContractErrorAttr, custom: &'a Custom, ) -> Self { let where_clause = &source.generics.where_clause; @@ -398,9 +400,9 @@ impl<'a> ContractEnumMessage<'a> { let enum_name = msg_ty.emit_msg_name(false); let match_arms = variants.emit_dispatch_legs(); let unused_generics = variants.unused_generics(); - let unused_generics = emit_bracketed_generics(unused_generics); + let bracketed_unused_generics = emit_bracketed_generics(unused_generics); let used_generics = variants.used_generics(); - let used_generics = emit_bracketed_generics(used_generics); + let bracketed_used_generics = emit_bracketed_generics(used_generics); let mut variant_names = variants.as_names_snake_cased(); variant_names.sort(); @@ -409,7 +411,7 @@ impl<'a> ContractEnumMessage<'a> { let variants = variants.emit(); let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default()); - let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), error); + let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error); let derive_query = match msg_ty { MsgType::Query => quote! { #sylvia ::cw_schema::QueryResponses }, @@ -419,22 +421,49 @@ impl<'a> ContractEnumMessage<'a> { let ep_name = msg_ty.emit_ep_name(); let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span()); + let phantom = if used_generics.is_empty() { + quote! {} + } else if MsgType::Query == *msg_ty { + quote! { + #[serde(skip)] + #[returns((#(#used_generics,)*))] + _Phantom(std::marker::PhantomData<( #(#used_generics,)* )>), + } + } else { + quote! { + #[serde(skip)] + _Phantom(std::marker::PhantomData<( #(#used_generics,)* )>), + } + }; + + let match_arms = if !used_generics.is_empty() { + quote! { + #(#match_arms,)* + _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into), + } + } else { + quote! { + #(#match_arms,)* + } + }; + #[cfg(not(tarpaulin_include))] { quote! { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #derive_query )] #[serde(rename_all="snake_case")] - pub enum #enum_name #used_generics { + pub enum #enum_name #bracketed_used_generics { #(#variants,)* + #phantom } - impl #used_generics #enum_name #used_generics { - pub fn dispatch #unused_generics (self, contract: &#contract, ctx: #ctx_type) -> #ret_type #where_clause { + impl #bracketed_used_generics #enum_name #bracketed_used_generics { + pub fn dispatch #bracketed_unused_generics (self, contract: &#contract, ctx: #ctx_type) -> #ret_type #where_clause { use #enum_name::*; match self { - #(#match_arms,)* + #match_arms } } @@ -962,6 +991,7 @@ where &self, trait_module: Option<&Path>, contract_module: Option<&Path>, + generic_args: &Vec<&GenericArgument>, ) -> TokenStream { let sylvia = crate_module(); let Self { @@ -974,7 +1004,7 @@ where let methods_impl = variants .iter() .filter(|variant| variant.msg_type == MsgType::Query) - .map(|variant| variant.emit_querier_impl(trait_module, used_generics)); + .map(|variant| variant.emit_querier_impl(trait_module, generic_args)); let querier = trait_module .map(|module| quote! { #module ::sv::Querier }) @@ -983,8 +1013,8 @@ where .map(|module| quote! { #module ::sv::BoundQuerier}) .unwrap_or_else(|| quote! { sv::BoundQuerier }); - let querier = if !used_generics.is_empty() { - quote! { #querier < #(#used_generics,)* > } + let querier = if !generic_args.is_empty() { + quote! { #querier < #(#generic_args,)* > } } else { quote! { #querier } }; @@ -992,32 +1022,13 @@ where #[cfg(not(tarpaulin_include))] { quote! { - impl <'a, C: #sylvia ::cw_std::CustomQuery> #querier for #bound_querier<'a, C > #where_clause { + impl <'a, C: #sylvia ::cw_std::CustomQuery, #(#used_generics,)* > #querier for #bound_querier<'a, C > #where_clause { #(#methods_impl)* } } } } - pub fn emit_multitest_default_dispatch(&self) -> TokenStream { - let sylvia = crate_module(); - let Self { - msg_ty, - used_generics, - .. - } = self; - - let values = msg_ty.emit_ctx_values(); - let msg_name = msg_ty.emit_msg_name(true); - let bracketed_generics = emit_bracketed_generics(used_generics); - - quote! { - #sylvia ::cw_std::from_json::< #msg_name #bracketed_generics >(&msg)? - .dispatch(self, ( #values )) - .map_err(Into::into) - } - } - pub fn emit_default_entry_point( &self, custom_msg: &Type, @@ -1229,7 +1240,7 @@ pub struct GlueMessage<'a> { source: &'a ItemImpl, contract: &'a Type, msg_ty: MsgType, - error: &'a Type, + error: &'a ContractErrorAttr, custom: &'a Custom<'a>, interfaces: &'a Interfaces, variants: MsgVariants<'a, GenericParam>, @@ -1239,7 +1250,7 @@ impl<'a> GlueMessage<'a> { pub fn new( source: &'a ItemImpl, msg_ty: MsgType, - error: &'a Type, + error: &'a ContractErrorAttr, custom: &'a Custom, interfaces: &'a Interfaces, variants: MsgVariants<'a, GenericParam>, @@ -1267,16 +1278,41 @@ impl<'a> GlueMessage<'a> { variants, } = self; + let generics: Vec<_> = source.generics.params.iter().collect(); + let interface_generic_args = interfaces.as_generic_args(); + let interface_used_generics = filter_generics(&generics, &interface_generic_args); let used_generics = variants.used_generics(); - let unused_generics = variants.unused_generics(); + + let used_wrapper_generics: Vec<_> = interface_used_generics + .iter() + .chain(used_generics.iter()) + .unique() + .copied() + .collect(); + + let unused_generics: Vec<_> = variants + .unused_generics() + .iter() + .filter(|unused| !used_wrapper_generics.iter().any(|used| used == *unused)) + .collect(); + let where_clause = variants.as_where_clause(); let full_where_clause = &source.generics.where_clause; + let query_responses_where_clause = + filter_wheres(full_where_clause, &generics, &used_wrapper_generics); + let query_responses_where_clause = if !query_responses_where_clause.is_empty() { + quote! { where #(#query_responses_where_clause,)* } + } else { + quote! {} + }; + + let unused_generics = emit_bracketed_generics(&unused_generics); + let bracketed_used_generics = emit_bracketed_generics(used_generics); + let bracketed_used_wrapper_generics = emit_bracketed_generics(&used_wrapper_generics); let contract_enum_name = msg_ty.emit_msg_name(true); let enum_name = msg_ty.emit_msg_name(false); let contract_name = StripGenerics.fold_type((*contract).clone()); - let unused_generics = emit_bracketed_generics(unused_generics); - let bracketed_used_generics = emit_bracketed_generics(used_generics); let variants = interfaces.emit_glue_message_variants(msg_ty); @@ -1337,7 +1373,7 @@ impl<'a> GlueMessage<'a> { }; let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default()); - let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), error); + let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error); let mut response_schemas_calls = interfaces.emit_response_schemas_calls(msg_ty); response_schemas_calls @@ -1349,7 +1385,7 @@ impl<'a> GlueMessage<'a> { { quote! { #[cfg(not(target_arch = "wasm32"))] - impl #bracketed_used_generics #sylvia ::cw_schema::QueryResponses for #contract_enum_name #bracketed_used_generics #where_clause { + impl #bracketed_used_wrapper_generics #sylvia ::cw_schema::QueryResponses for #contract_enum_name #bracketed_used_wrapper_generics #query_responses_where_clause { fn response_schemas_impl() -> std::collections::BTreeMap { let responses = [#(#response_schemas_calls),*]; responses.into_iter().flatten().collect() @@ -1369,12 +1405,12 @@ impl<'a> GlueMessage<'a> { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(#sylvia ::serde::Serialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)] #[serde(rename_all="snake_case", untagged)] - pub enum #contract_enum_name #bracketed_used_generics { + pub enum #contract_enum_name #bracketed_used_wrapper_generics { #(#variants,)* #contract_variant } - impl #bracketed_used_generics #contract_enum_name #bracketed_used_generics { + impl #bracketed_used_wrapper_generics #contract_enum_name #bracketed_used_wrapper_generics { pub fn dispatch #unused_generics ( self, contract: &#contract, @@ -1394,7 +1430,7 @@ impl<'a> GlueMessage<'a> { #response_schemas - impl<'de, #(#used_generics,)* > serde::Deserialize<'de> for #contract_enum_name #bracketed_used_generics #where_clause { + impl<'de, #(#used_wrapper_generics,)* > serde::Deserialize<'de> for #contract_enum_name #bracketed_used_wrapper_generics #where_clause { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { @@ -1443,14 +1479,18 @@ pub struct ContractApi<'a> { instantiate_variants: MsgVariants<'a, GenericParam>, migrate_variants: MsgVariants<'a, GenericParam>, generics: &'a [&'a GenericParam], + where_clause: &'a Option, custom: &'a Custom<'a>, + interfaces: &'a Interfaces, } impl<'a> ContractApi<'a> { pub fn new( source: &'a ItemImpl, generics: &'a [&'a GenericParam], + where_clause: &'a Option, custom: &'a Custom<'a>, + interfaces: &'a Interfaces, ) -> Self { let exec_variants = MsgVariants::new( source.as_variants(), @@ -1487,7 +1527,9 @@ impl<'a> ContractApi<'a> { instantiate_variants, migrate_variants, generics, + where_clause, custom, + interfaces, } } @@ -1500,7 +1542,9 @@ impl<'a> ContractApi<'a> { instantiate_variants, migrate_variants, generics, + where_clause, custom, + interfaces, } = self; let contract_name = &source.self_ty; @@ -1509,11 +1553,27 @@ impl<'a> ContractApi<'a> { let instantiate_generics = &instantiate_variants.used_generics; let migrate_generics = &migrate_variants.used_generics; + let interface_generics = interfaces.as_generic_args(); + let interface_generics = filter_generics(generics, &interface_generics); + + let contract_exec_generics: Vec<_> = interface_generics + .iter() + .chain(exec_generics.iter()) + .unique() + .collect(); + let contract_query_generics: Vec<_> = interface_generics + .iter() + .chain(query_generics.iter()) + .unique() + .collect(); + let bracket_generics = emit_bracketed_generics(generics); let exec_bracketed_generics = emit_bracketed_generics(exec_generics); let query_bracketed_generics = emit_bracketed_generics(query_generics); let instantiate_bracketed_generics = emit_bracketed_generics(instantiate_generics); let migrate_bracketed_generics = emit_bracketed_generics(migrate_generics); + let contract_exec_bracketed_generics = emit_bracketed_generics(&contract_exec_generics); + let contract_query_bracketed_generics = emit_bracketed_generics(&contract_query_generics); let migrate_type = match !migrate_variants.variants().is_empty() { true => quote! { type Migrate = MigrateMsg #migrate_bracketed_generics; }, @@ -1522,9 +1582,9 @@ impl<'a> ContractApi<'a> { let custom_query = custom.query_or_default(); quote! { - impl #bracket_generics #sylvia ::types::ContractApi for #contract_name { - type ContractExec = ContractExecMsg #exec_bracketed_generics; - type ContractQuery = ContractQueryMsg #query_bracketed_generics; + impl #bracket_generics #sylvia ::types::ContractApi for #contract_name #where_clause { + type ContractExec = ContractExecMsg #contract_exec_bracketed_generics; + type ContractQuery = ContractQueryMsg #contract_query_bracketed_generics; type Exec = ExecMsg #exec_bracketed_generics; type Query = QueryMsg #query_bracketed_generics; type Instantiate = InstantiateMsg #instantiate_bracketed_generics; diff --git a/sylvia-derive/src/multitest.rs b/sylvia-derive/src/multitest.rs index ebc5fcfc..0380e96f 100644 --- a/sylvia-derive/src/multitest.rs +++ b/sylvia-derive/src/multitest.rs @@ -1,14 +1,16 @@ use convert_case::{Case, Casing}; +use itertools::Itertools; use proc_macro2::{Ident, TokenStream}; -use quote::{quote, ToTokens}; -use syn::{parse_quote, ImplItem, ItemImpl, ItemTrait, Path, Type}; +use quote::quote; +use syn::visit::Visit; +use syn::{parse_quote, GenericArgument, GenericParam, ImplItem, ItemImpl, ItemTrait, Path, Type}; -use crate::check_generics::GetPath; +use crate::check_generics::CheckGenerics; use crate::crate_module; use crate::interfaces::Interfaces; use crate::message::{MsgVariant, MsgVariants}; -use crate::parser::{Custom, MsgType, OverrideEntryPoint, OverrideEntryPoints}; -use crate::utils::emit_bracketed_generics; +use crate::parser::{ContractErrorAttr, Custom, MsgType, OverrideEntryPoint, OverrideEntryPoints}; +use crate::utils::{emit_bracketed_generics, filter_wheres, is_trait}; use crate::variant_descs::AsVariantDescs; fn interface_name(source: &ItemImpl) -> &Ident { @@ -30,63 +32,73 @@ fn extract_contract_name(contract: &Type) -> &Ident { }; let segments = &type_path.path.segments; assert!(!segments.is_empty()); - let segment = &segments[0]; + let segment = &segments.last().unwrap(); &segment.ident } -pub struct MultitestHelpers<'a, Generics> { +pub struct MultitestHelpers<'a> { error_type: Type, contract: &'a Type, - is_trait: bool, source: &'a ItemImpl, - generics: &'a [&'a Generics], + generic_params: &'a [&'a GenericParam], + generic_args: &'a [&'a GenericArgument], where_clause: &'a Option, contract_name: &'a Ident, proxy_name: Ident, custom: &'a Custom<'a>, override_entry_points: &'a OverrideEntryPoints, interfaces: &'a Interfaces, - instantiate_variants: MsgVariants<'a, Generics>, - exec_variants: MsgVariants<'a, Generics>, - query_variants: MsgVariants<'a, Generics>, - migrate_variants: MsgVariants<'a, Generics>, - reply_variants: MsgVariants<'a, Generics>, + instantiate_variants: MsgVariants<'a, GenericParam>, + exec_variants: MsgVariants<'a, GenericParam>, + query_variants: MsgVariants<'a, GenericParam>, + migrate_variants: MsgVariants<'a, GenericParam>, + reply_variants: MsgVariants<'a, GenericParam>, + contract_module: &'a Option<&'a Path>, } -impl<'a, Generics> MultitestHelpers<'a, Generics> -where - Generics: ToTokens + PartialEq + GetPath, -{ +impl<'a> MultitestHelpers<'a> { pub fn new( source: &'a ItemImpl, - is_trait: bool, - contract_error: &'a Type, - generics: &'a [&'a Generics], + generic_params: &'a [&'a GenericParam], + generic_args: &'a [&'a GenericArgument], custom: &'a Custom, override_entry_points: &'a OverrideEntryPoints, interfaces: &'a Interfaces, + contract_module: &'a Option<&'a Path>, ) -> Self { let where_clause = &source.generics.where_clause; let instantiate_variants = MsgVariants::new( source.as_variants(), MsgType::Instantiate, - generics, + generic_params, + where_clause, + ); + let exec_variants = MsgVariants::new( + source.as_variants(), + MsgType::Exec, + generic_params, + where_clause, + ); + let query_variants = MsgVariants::new( + source.as_variants(), + MsgType::Query, + generic_params, where_clause, ); - let exec_variants = - MsgVariants::new(source.as_variants(), MsgType::Exec, generics, where_clause); - let query_variants = - MsgVariants::new(source.as_variants(), MsgType::Query, generics, where_clause); let migrate_variants = MsgVariants::new( source.as_variants(), MsgType::Migrate, - generics, + generic_params, + where_clause, + ); + let reply_variants = MsgVariants::new( + source.as_variants(), + MsgType::Reply, + generic_params, where_clause, ); - let reply_variants = - MsgVariants::new(source.as_variants(), MsgType::Reply, generics, where_clause); - let error_type: Type = if is_trait { + let error_type: Type = if is_trait(source) { let error_type: Vec<_> = source .items .iter() @@ -101,7 +113,7 @@ where }; assert!(!segments.is_empty()); - Some(&segments[0].ident) + Some(&segments[0]) } _ => None, }) @@ -111,13 +123,14 @@ where let error_type = error_type[0]; parse_quote! {#error_type} } else { - parse_quote! {#contract_error} + let error = ContractErrorAttr::new(source).error; + parse_quote! { #error } }; let contract = &source.self_ty; let contract_name = extract_contract_name(contract); - let proxy_name = if is_trait { + let proxy_name = if is_trait(source) { let interface_name = interface_name(source); Ident::new(&format!("{}Proxy", interface_name), interface_name.span()) } else { @@ -127,9 +140,9 @@ where Self { error_type, contract, - is_trait, source, - generics, + generic_params, + generic_args, where_clause, contract_name, proxy_name, @@ -141,26 +154,27 @@ where query_variants, migrate_variants, reply_variants, + contract_module, } } pub fn emit(&self) -> TokenStream { let Self { + source, error_type, proxy_name, - is_trait, custom, interfaces, exec_variants, query_variants, migrate_variants, - generics, + generic_params, where_clause, .. } = self; let sylvia = crate_module(); - if *is_trait { + if is_trait(source) { return self.impl_trait_on_proxy(); } @@ -204,14 +218,14 @@ where #[derive(Derivative)] #[derivative(Debug)] - pub struct #proxy_name <'app, MtApp, #(#generics,)* > { + pub struct #proxy_name <'app, MtApp, #(#generic_params,)* > { pub contract_addr: #sylvia ::cw_std::Addr, #[derivative(Debug="ignore")] pub app: &'app #sylvia ::multitest::App, - _phantom: std::marker::PhantomData<( #(#generics,)* )>, + _phantom: std::marker::PhantomData<( #(#generic_params,)* )>, } - impl<'app, BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #(#generics,)* > #proxy_name <'app, #mt_app, #(#generics,)* > + impl<'app, BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #(#generic_params,)* > #proxy_name <'app, #mt_app, #(#generic_params,)* > where CustomT: #sylvia ::cw_multi_test::Module, CustomT::ExecT: std::fmt::Debug @@ -242,12 +256,12 @@ where #( #proxy_accessors )* } - impl<'app, BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #(#generics,)* > + impl<'app, BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #(#generic_params,)* > From<( #sylvia ::cw_std::Addr, &'app #sylvia ::multitest::App<#mt_app>, )> - for #proxy_name <'app, #mt_app, #(#generics,)* > + for #proxy_name <'app, #mt_app, #(#generic_params,)* > where CustomT: #sylvia ::cw_multi_test::Module, CustomT::ExecT: std::fmt::Debug @@ -269,7 +283,7 @@ where #where_predicates { fn from(input: (#sylvia ::cw_std::Addr, &'app #sylvia ::multitest::App< #mt_app >)) - -> #proxy_name<'app, #mt_app, #(#generics,)* > { + -> #proxy_name<'app, #mt_app, #(#generic_params,)* > { #proxy_name::new(input.0, input.1) } } @@ -285,9 +299,13 @@ where error_type, custom, interfaces, - generics, + generic_params, + generic_args, exec_variants, query_variants, + where_clause, + contract_module, + contract_name, .. } = self; @@ -322,7 +340,7 @@ where > }; - let bracketed_generics = emit_bracketed_generics(generics); + let bracketed_generics = emit_bracketed_generics(generic_args); let interface_enum = quote! { < #module sv::Api #bracketed_generics as #sylvia ::types::InterfaceApi> }; @@ -330,14 +348,14 @@ where &custom_msg, &mt_app, error_type, - generics, + generic_args, &module, ); let query_methods = query_variants.emit_interface_multitest_proxy_methods( &custom_msg, &mt_app, error_type, - generics, + generic_args, &module, ); let exec_methods_declarations = @@ -347,6 +365,37 @@ where error_type, &interface_enum, ); + let exec_generics = exec_variants.used_generics(); + let query_generics = query_variants.used_generics(); + + // Check if custom_msg is a generic type + + let mut generics_checker = CheckGenerics::new(generic_params); + generics_checker.visit_type(&custom_msg); + let (custom_generic, _) = generics_checker.used_unused(); + let custom_generic = custom_generic.first(); + let custom_where_predicate = match custom_generic { + Some(generic) => filter_wheres(where_clause, generic_params, &[generic]), + None => vec![], + }; + let exec_where_predicates = filter_wheres(where_clause, generic_params, exec_generics); + let query_where_predicates = filter_wheres(where_clause, generic_params, query_generics); + let trait_where_clause = if !exec_where_predicates.is_empty() { + quote! { where #(#exec_where_predicates,)* } + } else { + quote! {} + }; + let contract_module = match contract_module { + Some(contract_module) => quote! { #contract_module :: }, + None => quote! {}, + }; + let contract_proxy = Ident::new(&format!("{}Proxy", contract_name), contract_name.span()); + let contract_generics: Vec<_> = exec_generics + .iter() + .chain(query_generics.iter()) + .chain(generic_params.iter()) + .unique() + .collect(); #[cfg(not(tarpaulin_include))] { @@ -354,12 +403,12 @@ where pub mod test_utils { use super::*; - pub trait #trait_name { + pub trait #trait_name #trait_where_clause { #(#query_methods_declarations)* #(#exec_methods_declarations)* } - impl #trait_name< #mt_app > for #module sv::trait_utils:: #proxy_name<'_, #mt_app > + impl #trait_name< #mt_app , #(#exec_generics,)* #(#query_generics,)* #custom_generic > for #module sv::trait_utils:: #proxy_name<'_, #mt_app > where CustomT: #sylvia ::cw_multi_test::Module, WasmT: #sylvia ::cw_multi_test::Wasm, @@ -378,7 +427,38 @@ where + #sylvia ::serde::de::DeserializeOwned + 'static, CustomT::QueryT: #sylvia:: cw_std::CustomQuery + #sylvia ::serde::de::DeserializeOwned + 'static, - #mt_app : #sylvia ::cw_multi_test::Executor< #custom_msg > + #mt_app : #sylvia ::cw_multi_test::Executor< #custom_msg >, + #(#custom_where_predicate,)* + #(#exec_where_predicates,)* + #(#query_where_predicates,)* + { + #(#query_methods)* + #(#exec_methods)* + } + + impl #trait_name< #mt_app , #(#exec_generics,)* #(#query_generics,)* #custom_generic > for #contract_module sv::multitest_utils:: #contract_proxy <'_, #mt_app, #(#contract_generics,)* > + where + CustomT: #sylvia ::cw_multi_test::Module, + WasmT: #sylvia ::cw_multi_test::Wasm, + BankT: #sylvia ::cw_multi_test::Bank, + ApiT: #sylvia ::cw_std::Api, + StorageT: #sylvia ::cw_std::Storage, + CustomT: #sylvia ::cw_multi_test::Module, + StakingT: #sylvia ::cw_multi_test::Staking, + DistrT: #sylvia ::cw_multi_test::Distribution, + IbcT: #sylvia ::cw_multi_test::Ibc, + GovT: #sylvia ::cw_multi_test::Gov, + CustomT::ExecT: Clone + + std::fmt::Debug + + PartialEq + + #sylvia ::schemars::JsonSchema + + #sylvia ::serde::de::DeserializeOwned + + 'static, + CustomT::QueryT: #sylvia:: cw_std::CustomQuery + #sylvia ::serde::de::DeserializeOwned + 'static, + #mt_app : #sylvia ::cw_multi_test::Executor< #custom_msg >, + #(#custom_where_predicate,)* + #(#exec_where_predicates,)* + #(#query_where_predicates,)* { #(#query_methods)* #(#exec_methods)* @@ -392,8 +472,7 @@ where let sylvia = crate_module(); let Self { error_type, - is_trait, - generics, + generic_params, where_clause, contract_name, proxy_name, @@ -401,10 +480,6 @@ where .. } = self; - if *is_trait { - return quote! {}; - } - let fields_names = instantiate_variants .get_only_variant() .map(MsgVariant::as_fields_names) @@ -421,8 +496,8 @@ where let where_predicates = where_clause .as_ref() .map(|where_clause| &where_clause.predicates); - let contract = if !generics.is_empty() { - quote! { #contract_name ::< #(#generics,)* > } + let contract = if !generic_params.is_empty() { + quote! { #contract_name ::< #(#generic_params,)* > } } else { quote! { #contract_name } }; @@ -511,14 +586,14 @@ where quote! { #impl_contract - pub struct CodeId<'app, #(#generics,)* MtApp> { + pub struct CodeId<'app, #(#generic_params,)* MtApp> { code_id: u64, app: &'app #sylvia ::multitest::App, - _phantom: std::marker::PhantomData<( #(#generics,)* )>, + _phantom: std::marker::PhantomData<( #(#generic_params,)* )>, } - impl<'app, BankT, ApiT, StorageT, CustomT, StakingT, DistrT, IbcT, GovT, #(#generics,)* > CodeId<'app, #(#generics,)* #mt_app > + impl<'app, BankT, ApiT, StorageT, CustomT, StakingT, DistrT, IbcT, GovT, #(#generic_params,)* > CodeId<'app, #(#generic_params,)* #mt_app > where BankT: #sylvia ::cw_multi_test::Bank, ApiT: #sylvia ::cw_std::Api, @@ -545,9 +620,9 @@ where pub fn instantiate( &self, #(#fields,)* - ) -> InstantiateProxy<'_, 'app, #(#generics,)* #mt_app > { + ) -> InstantiateProxy<'_, 'app, #(#generic_params,)* #mt_app > { let msg = #instantiate_msg {#(#fields_names,)*}; - InstantiateProxy::< #(#generics,)* _> { + InstantiateProxy::< #(#generic_params,)* _> { code_id: self, funds: &[], label: "Contract", @@ -558,8 +633,8 @@ where } } - pub struct InstantiateProxy<'proxy, 'app, #(#generics,)* MtApp> { - code_id: &'proxy CodeId <'app, #(#generics,)* MtApp>, + pub struct InstantiateProxy<'proxy, 'app, #(#generic_params,)* MtApp> { + code_id: &'proxy CodeId <'app, #(#generic_params,)* MtApp>, funds: &'proxy [#sylvia ::cw_std::Coin], label: &'proxy str, admin: Option, @@ -567,7 +642,7 @@ where msg: InstantiateMsg #bracketed_used_generics, } - impl<'proxy, 'app, #(#generics,)* MtApp> InstantiateProxy<'proxy, 'app, #(#generics,)* MtApp> + impl<'proxy, 'app, #(#generic_params,)* MtApp> InstantiateProxy<'proxy, 'app, #(#generic_params,)* MtApp> where MtApp: Executor< #custom_msg >, #where_predicates @@ -591,7 +666,7 @@ where } #[track_caller] - pub fn call(self, sender: &str) -> Result<#proxy_name<'app, MtApp, #(#generics,)* >, #error_type> { + pub fn call(self, sender: &str) -> Result<#proxy_name<'app, MtApp, #(#generic_params,)* >, #error_type> { let Self {code_id, funds, label, admin, salt, msg} = self; match salt { @@ -627,32 +702,38 @@ where contract, custom, override_entry_points, - generics, - instantiate_variants, - exec_variants, - query_variants, + generic_params, migrate_variants, reply_variants, .. } = self; let sylvia = crate_module(); - let bracketed_generics = emit_bracketed_generics(generics); + let bracketed_generics = emit_bracketed_generics(generic_params); let full_where_clause = &source.generics.where_clause; let instantiate_body = override_entry_points .get_entry_point(MsgType::Instantiate) .map(OverrideEntryPoint::emit_multitest_dispatch) - .unwrap_or_else(|| instantiate_variants.emit_multitest_default_dispatch()); + .unwrap_or_else(|| { + let msg_ty = MsgType::Instantiate; + msg_ty.emit_multitest_default_dispatch(contract, generic_params) + }); let exec_body = override_entry_points .get_entry_point(MsgType::Exec) .map(OverrideEntryPoint::emit_multitest_dispatch) - .unwrap_or_else(|| exec_variants.emit_multitest_default_dispatch()); + .unwrap_or_else(|| { + let msg_ty = MsgType::Exec; + msg_ty.emit_multitest_default_dispatch(contract, generic_params) + }); let query_body = override_entry_points .get_entry_point(MsgType::Query) .map(OverrideEntryPoint::emit_multitest_dispatch) - .unwrap_or_else(|| query_variants.emit_multitest_default_dispatch()); + .unwrap_or_else(|| { + let msg_ty = MsgType::Query; + msg_ty.emit_multitest_default_dispatch(contract, generic_params) + }); let sudo_body = override_entry_points .get_entry_point(MsgType::Sudo) @@ -666,7 +747,8 @@ where let migrate_body = match override_entry_points.get_entry_point(MsgType::Migrate) { Some(entry_point) => entry_point.emit_multitest_dispatch(), None if migrate_variants.get_only_variant().is_some() => { - migrate_variants.emit_multitest_default_dispatch() + let msg_ty = MsgType::Migrate; + msg_ty.emit_multitest_default_dispatch(contract, generic_params) } None => quote! { #sylvia ::anyhow::bail!("migrate not implemented for contract") diff --git a/sylvia-derive/src/parser.rs b/sylvia-derive/src/parser.rs index 5f80d0a0..4852e18d 100644 --- a/sylvia-derive/src/parser.rs +++ b/sylvia-derive/src/parser.rs @@ -6,12 +6,13 @@ use syn::parse::{Error, Nothing, Parse, ParseBuffer, ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - parenthesized, parse_quote, Attribute, GenericArgument, Ident, ImplItem, ImplItemMethod, - ItemImpl, ItemTrait, Path, PathArguments, Result, Token, TraitItem, Type, + parenthesized, parse_quote, Attribute, GenericArgument, GenericParam, Ident, ImplItem, + ImplItemMethod, ItemImpl, ItemTrait, Path, PathArguments, Result, Token, TraitItem, Type, }; use crate::crate_module; use crate::strip_generics::StripGenerics; +use crate::utils::emit_bracketed_generics; /// Parsed arguments for `contract` macro pub struct ContractArgs { @@ -196,6 +197,25 @@ impl MsgType { MsgType::Reply => Some(parse_quote! { Reply }), } } + + pub fn emit_multitest_default_dispatch( + &self, + contract_name: &Type, + generics: &[&GenericParam], + ) -> TokenStream { + let sylvia = crate_module(); + + let values = self.emit_ctx_values(); + let msg_name = self.as_accessor_name(true); + let _bracketed_generics = emit_bracketed_generics(generics); + let api_msg = quote! { < #contract_name as #sylvia ::types::ContractApi> :: #msg_name }; + + quote! { + #sylvia ::cw_std::from_json::< #api_msg >(&msg)? + .dispatch(self, ( #values )) + .map_err(Into::into) + } + } } impl PartialEq for MsgAttr { @@ -262,6 +282,29 @@ pub struct ContractErrorAttr { pub error: Type, } +impl ContractErrorAttr { + pub fn new(item: &ItemImpl) -> Self { + let sylvia = crate_module(); + + item.attrs + .iter() + .find(|attr| attr.path.is_ident("error")) + .and_then( + |attr| match ContractErrorAttr::parse.parse2(attr.tokens.clone()) { + Ok(error) => Some(error), + Err(err) => { + emit_error!(attr.span(), err); + None + } + }, + ) + .unwrap_or_else(|| { + let error = parse_quote! { #sylvia ::cw_std::StdError }; + Self { error } + }) + } +} + #[cfg(not(tarpaulin_include))] // False negative. It is being called in closure impl Parse for ContractErrorAttr { diff --git a/sylvia-derive/src/utils.rs b/sylvia-derive/src/utils.rs index 276deb3d..57bfe295 100644 --- a/sylvia-derive/src/utils.rs +++ b/sylvia-derive/src/utils.rs @@ -4,8 +4,8 @@ use quote::{quote, ToTokens}; use syn::spanned::Spanned; use syn::visit::Visit; use syn::{ - parse_quote, FnArg, GenericArgument, Path, PathArguments, ReturnType, Signature, Type, - WhereClause, WherePredicate, + parse_quote, FnArg, GenericArgument, GenericParam, ItemImpl, Path, PathArguments, ReturnType, + Signature, Type, WhereClause, WherePredicate, }; use crate::check_generics::{CheckGenerics, GetPath}; @@ -36,6 +36,29 @@ pub fn filter_wheres<'a, Generic: GetPath + PartialEq>( .unwrap_or_default() } +/// Filters generic arguments, which are a concrete types, +/// from the generic parameters +/// +/// f.e. +/// impl MyTrait for MyContract +/// +/// where generic parameters are `[A, B, C]` and generic arguments are `[A, B, D]` +/// should return us the `[A, B]`. +pub fn filter_generics<'a>( + generic_params: &'a [&'a GenericParam], + generic_args: &'a [&'a GenericArgument], +) -> Vec<&'a GenericParam> { + generic_params + .iter() + .filter(|param| { + generic_args + .iter() + .any(|arg| param.get_path() == arg.get_path()) + }) + .copied() + .collect() +} + pub fn process_fields<'s, Generic>( sig: &'s Signature, generics_checker: &mut CheckGenerics, @@ -103,3 +126,7 @@ pub fn emit_bracketed_generics(unbonded_generics: &[&Generic] false => quote! { < #(#unbonded_generics,)* > }, } } + +pub fn is_trait(item: &ItemImpl) -> bool { + item.trait_.is_some() +} diff --git a/sylvia/src/lib.rs b/sylvia/src/lib.rs index 69f827a8..feedd894 100644 --- a/sylvia/src/lib.rs +++ b/sylvia/src/lib.rs @@ -1,6 +1,6 @@ //! Framework for creating CosmWasm Smart Contract with high-level abstraction layer //! -//! Most of implementation lies in `cw-derive-ng` crate which is reexported here +//! Most of implementation lies in `sylvia-derive` crate which is reexported here pub mod into_response; #[cfg(feature = "mt")] diff --git a/sylvia/src/types.rs b/sylvia/src/types.rs index d5c3d330..96648ce5 100644 --- a/sylvia/src/types.rs +++ b/sylvia/src/types.rs @@ -1,41 +1,41 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo}; +use cosmwasm_std::{Deps, DepsMut, Empty, Env, MessageInfo}; use serde::de::DeserializeOwned; -pub struct ReplyCtx<'a, C: CustomQuery = Empty> { +pub struct ReplyCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: DepsMut<'a, C>, pub env: Env, } -pub struct MigrateCtx<'a, C: CustomQuery = Empty> { +pub struct MigrateCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: DepsMut<'a, C>, pub env: Env, } -pub struct ExecCtx<'a, C: CustomQuery = Empty> { +pub struct ExecCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: DepsMut<'a, C>, pub env: Env, pub info: MessageInfo, } -pub struct InstantiateCtx<'a, C: CustomQuery = Empty> { +pub struct InstantiateCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: DepsMut<'a, C>, pub env: Env, pub info: MessageInfo, } -pub struct QueryCtx<'a, C: CustomQuery = Empty> { +pub struct QueryCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: Deps<'a, C>, pub env: Env, } -pub struct SudoCtx<'a, C: CustomQuery = Empty> { +pub struct SudoCtx<'a, C: cosmwasm_std::CustomQuery = Empty> { pub deps: DepsMut<'a, C>, pub env: Env, } #[cfg(not(tarpaulin_include))] -impl ExecCtx<'_, C> { +impl ExecCtx<'_, C> { pub fn branch(&'_ mut self) -> ExecCtx<'_, C> { ExecCtx { deps: self.deps.branch(), @@ -46,7 +46,7 @@ impl ExecCtx<'_, C> { } #[cfg(not(tarpaulin_include))] -impl InstantiateCtx<'_, C> { +impl InstantiateCtx<'_, C> { pub fn branch(&'_ mut self) -> InstantiateCtx<'_, C> { InstantiateCtx { deps: self.deps.branch(), @@ -57,7 +57,7 @@ impl InstantiateCtx<'_, C> { } #[cfg(not(tarpaulin_include))] -impl SudoCtx<'_, C> { +impl SudoCtx<'_, C> { pub fn branch(&'_ mut self) -> SudoCtx<'_, C> { SudoCtx { deps: self.deps.branch(), @@ -66,31 +66,33 @@ impl SudoCtx<'_, C> { } } -impl<'a, C: CustomQuery> From<(DepsMut<'a, C>, Env)> for MigrateCtx<'a, C> { +impl<'a, C: cosmwasm_std::CustomQuery> From<(DepsMut<'a, C>, Env)> for MigrateCtx<'a, C> { fn from((deps, env): (DepsMut<'a, C>, Env)) -> Self { Self { deps, env } } } -impl<'a, C: CustomQuery> From<(DepsMut<'a, C>, Env)> for ReplyCtx<'a, C> { +impl<'a, C: cosmwasm_std::CustomQuery> From<(DepsMut<'a, C>, Env)> for ReplyCtx<'a, C> { fn from((deps, env): (DepsMut<'a, C>, Env)) -> Self { Self { deps, env } } } -impl<'a, C: CustomQuery> From<(DepsMut<'a, C>, Env, MessageInfo)> for ExecCtx<'a, C> { +impl<'a, C: cosmwasm_std::CustomQuery> From<(DepsMut<'a, C>, Env, MessageInfo)> for ExecCtx<'a, C> { fn from((deps, env, info): (DepsMut<'a, C>, Env, MessageInfo)) -> Self { Self { deps, env, info } } } -impl<'a, C: CustomQuery> From<(DepsMut<'a, C>, Env, MessageInfo)> for InstantiateCtx<'a, C> { +impl<'a, C: cosmwasm_std::CustomQuery> From<(DepsMut<'a, C>, Env, MessageInfo)> + for InstantiateCtx<'a, C> +{ fn from((deps, env, info): (DepsMut<'a, C>, Env, MessageInfo)) -> Self { Self { deps, env, info } } } -impl<'a, C: CustomQuery> From<(Deps<'a, C>, Env)> for QueryCtx<'a, C> { +impl<'a, C: cosmwasm_std::CustomQuery> From<(Deps<'a, C>, Env)> for QueryCtx<'a, C> { fn from((deps, env): (Deps<'a, C>, Env)) -> Self { Self { deps, env } } @@ -100,11 +102,20 @@ pub trait CustomMsg: cosmwasm_std::CustomMsg + DeserializeOwned {} impl CustomMsg for T where T: cosmwasm_std::CustomMsg + DeserializeOwned {} +pub trait CustomQuery: cosmwasm_std::CustomQuery + DeserializeOwned {} + +impl CustomQuery for T where T: cosmwasm_std::CustomQuery + DeserializeOwned {} + #[cw_serde] pub struct SvCustomMsg; impl cosmwasm_std::CustomMsg for SvCustomMsg {} +#[cw_serde] +pub struct SvCustomQuery; + +impl cosmwasm_std::CustomQuery for SvCustomQuery {} + pub trait InterfaceApi { type Exec; type Query;