Repository: CosmWasm/sylvia
Pull request #127 (2023-05-24 13:27:15)

Bound querier conversion
PR3 of #28 


Patch:
diff --git a/sylvia-derive/src/input.rs b/sylvia-derive/src/input.rs
index 3ae3dff..4a32c6b 100644
--- a/sylvia-derive/src/input.rs
+++ b/sylvia-derive/src/input.rs
@@ -6,6 +6,7 @@ use syn::spanned::Spanned;
 use syn::{parse_quote, GenericParam, Ident, ItemImpl, ItemTrait, TraitItem, Type};
 
 use crate::crate_module;
+use crate::interfaces::Interfaces;
 use crate::message::{ContractEnumMessage, EnumMessage, GlueMessage, MsgVariants, StructMessage};
 use crate::multitest::{MultitestHelpers, TraitMultitestHelpers};
 use crate::parser::{ContractArgs, ContractErrorAttr, InterfaceArgs, MsgType};
@@ -172,6 +173,7 @@ impl<'a> ImplInput<'a> {
         let messages = self.emit_messages();
         let remote = Remote::new(&self.item.attrs).emit();
         let querier = MsgVariants::new(self.item.as_variants(), &self.generics).emit_querier();
+        let querier_from_impl = Interfaces::new(self.item).emit_querier_from_impl();
 
         #[cfg(not(tarpaulin_include))]
         let code = quote! {
@@ -182,6 +184,8 @@ impl<'a> ImplInput<'a> {
             #remote
 
             #querier
+
+            #(#querier_from_impl)*
         };
 
         if let Some(module) = &self.attributes.module {
diff --git a/sylvia-derive/src/interfaces.rs b/sylvia-derive/src/interfaces.rs
new file mode 100644
index 0000000..bb0cdb8
--- /dev/null
+++ b/sylvia-derive/src/interfaces.rs
@@ -0,0 +1,54 @@
+use proc_macro2::TokenStream;
+use proc_macro_error::emit_error;
+use quote::quote;
+use syn::parse::{Parse, Parser};
+use syn::spanned::Spanned;
+use syn::ItemImpl;
+
+use crate::crate_module;
+use crate::parser::ContractMessageAttr;
+
+pub struct Interfaces {
+    interfaces: Vec<ContractMessageAttr>,
+}
+
+impl Interfaces {
+    pub fn new(source: &ItemImpl) -> Self {
+        let interfaces: Vec<_> = source
+            .attrs
+            .iter()
+            .filter(|attr| attr.path.is_ident("messages"))
+            .filter_map(|attr| {
+                let interface = match ContractMessageAttr::parse.parse2(attr.tokens.clone()) {
+                    Ok(interface) => interface,
+                    Err(err) => {
+                        emit_error!(attr.span(), err);
+                        return None;
+                    }
+                };
+
+                Some(interface)
+            })
+            .collect();
+
+        Self { interfaces }
+    }
+
+    pub fn emit_querier_from_impl(&self) -> Vec<TokenStream> {
+        let sylvia = crate_module();
+
+        self.interfaces
+            .iter()
+            .map(|interface| {
+                let ContractMessageAttr { module, .. } = interface;
+                quote! {
+                    impl<'a, C: #sylvia ::cw_std::CustomQuery> From<&'a BoundQuerier<'a, C>> for #module ::BoundQuerier<'a, C> {
+                        fn from(querier: &'a BoundQuerier<'a, C>) -> Self {
+                            Self::borrowed(querier.contract(),  querier.querier())
+                        }
+                    }
+                }
+            })
+            .collect()
+    }
+}
diff --git a/sylvia-derive/src/lib.rs b/sylvia-derive/src/lib.rs
index 86fde8e..b4c5841 100644
--- a/sylvia-derive/src/lib.rs
+++ b/sylvia-derive/src/lib.rs
@@ -8,6 +8,7 @@ use syn::{parse2, parse_quote, ItemImpl, ItemTrait, Path};
 
 pub(crate) mod check_generics;
 mod input;
+mod interfaces;
 mod message;
 mod multitest;
 mod parser;
diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs
index a9f46f8..36994d4 100644
--- a/sylvia-derive/src/message.rs
+++ b/sylvia-derive/src/message.rs
@@ -682,6 +682,20 @@ impl<'a> MsgVariants<'a> {
                     querier: &'a #sylvia ::cw_std::QuerierWrapper<'a, C>,
                 }
 
+                impl<'a, C: #sylvia ::cw_std::CustomQuery> BoundQuerier<'a, C> {
+                    pub fn querier(&self) -> &'a #sylvia ::cw_std::QuerierWrapper<'a, C> {
+                        self.querier
+                    }
+
+                    pub fn contract(&self) -> &'a #sylvia ::cw_std::Addr {
+                        self.contract
+                    }
+
+                    pub fn borrowed(contract: &'a #sylvia ::cw_std::Addr, querier: &'a #sylvia ::cw_std::QuerierWrapper<'a, C>) -> Self {
+                        Self {contract, querier}
+                    }
+                }
+
                 impl <'a, C: #sylvia ::cw_std::CustomQuery> Querier for BoundQuerier<'a, C> {
                     #(#methods_impl)*
                 }
diff --git a/sylvia-derive/src/remote.rs b/sylvia-derive/src/remote.rs
index 92d73ac..c330b03 100644
--- a/sylvia-derive/src/remote.rs
+++ b/sylvia-derive/src/remote.rs
@@ -70,7 +70,7 @@ impl Remote {
             }
 
             impl Remote<'_> {
-                fn querier<'a, C: #sylvia ::cw_std::CustomQuery>(&'a self, querier: &'a #sylvia ::cw_std::QuerierWrapper<'a, C>) -> BoundQuerier<'a, C> {
+                pub fn querier<'a, C: #sylvia ::cw_std::CustomQuery>(&'a self, querier: &'a #sylvia ::cw_std::QuerierWrapper<'a, C>) -> BoundQuerier<'a, C> {
                     BoundQuerier {
                         contract: &self.0,
                         querier,


Test patch:
diff --git a/sylvia/tests/querier.rs b/sylvia/tests/querier.rs
index ccf2dce..beadd27 100644
--- a/sylvia/tests/querier.rs
+++ b/sylvia/tests/querier.rs
@@ -29,6 +29,9 @@ pub mod counter {
 
         #[msg(exec)]
         fn set_count(&self, ctx: ExecCtx, new_count: u64) -> StdResult<Response>;
+
+        #[msg(exec)]
+        fn decrease_by_count(&self, ctx: ExecCtx) -> StdResult<Response>;
     }
 
     #[contract]
@@ -50,11 +53,25 @@ pub mod counter {
         #[msg(exec)]
         fn copy_count(&self, ctx: ExecCtx) -> StdResult<Response> {
             let remote = self.remote.load(ctx.deps.storage)?;
-            let remote = Remote::from(&remote);
-            let other_count = remote.querier(&ctx.deps.querier).count()?.count;
+            let querier = remote.querier(&ctx.deps.querier);
+            let other_count = BoundQuerier::from(&querier).count()?.count;
             self.count.save(ctx.deps.storage, &other_count)?;
             Ok(Response::new())
         }
+
+        #[msg(exec)]
+        fn decrease_by_count(&self, ctx: ExecCtx) -> StdResult<Response> {
+            let remote = self.remote.load(ctx.deps.storage)?;
+            let other_count = BoundQuerier::borrowed(&remote.0, &ctx.deps.querier)
+                .count()?
+                .count;
+            self.count.update(ctx.deps.storage, |count| {
+                let count = count.saturating_sub(other_count);
+                Ok::<_, StdError>(count)
+            })?;
+
+            Ok(Response::new())
+        }
     }
 }
 
@@ -85,12 +102,33 @@ impl CounterContract<'_> {
 
 #[cfg(test)]
 mod tests {
-    use cosmwasm_std::Addr;
+
+    use cosmwasm_std::testing::mock_dependencies;
+    use cosmwasm_std::{Addr, Empty, QuerierWrapper};
     use sylvia::multitest::App;
 
     use crate::counter::test_utils::Counter;
     use crate::multitest_utils::CodeId;
 
+    #[test]
+    fn querier_generation() {
+        let deps = mock_dependencies();
+        let querier_wrapper = QuerierWrapper::<Empty>::new(&deps.querier);
+        let remote_addr = Addr::unchecked("remote");
+
+        // Remote generation
+        let remote = super::counter::Remote::new(remote_addr.clone());
+        let _: super::counter::BoundQuerier<_> = remote.querier(&querier_wrapper);
+        let remote = super::Remote::new(remote_addr.clone());
+        let _: super::BoundQuerier<_> = remote.querier(&querier_wrapper);
+
+        // Querier generation
+        let _ = super::counter::BoundQuerier::borrowed(&remote_addr, &querier_wrapper);
+        let querier = super::BoundQuerier::borrowed(&remote_addr, &querier_wrapper);
+
+        let _ = super::counter::BoundQuerier::from(&querier);
+    }
+
     #[test]
     fn call_querier() {
         let app = App::default();
@@ -127,5 +165,14 @@ mod tests {
 
         let resp = second_contract.counter_proxy().count().unwrap();
         assert_eq!(resp.count, 42);
+
+        second_contract
+            .counter_proxy()
+            .decrease_by_count()
+            .call(owner)
+            .unwrap();
+
+        let resp = second_contract.counter_proxy().count().unwrap();
+        assert_eq!(resp.count, 0);
     }
 }