Skip to content

Commit

Permalink
feat: Generate unique reply_ids (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
jawoznia committed Sep 17, 2024
1 parent 778c5f0 commit d4d5ba8
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 25 additions & 15 deletions sylvia-derive/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use communication::api::Api;
use communication::enum_msg::EnumMessage;
use communication::executor::Executor;
use communication::querier::Querier;
use communication::reply::Reply;
use communication::struct_msg::StructMessage;
use communication::wrapper_msg::GlueMessage;
use mt::MtHelpers;
Expand Down Expand Up @@ -76,23 +77,11 @@ impl<'a> ContractInput<'a> {
..
} = self;
let multitest_helpers = self.emit_multitest_helpers();

let executor_variants = MsgVariants::new(item.as_variants(), MsgType::Exec, &[], &None);
let querier_variants = MsgVariants::new(item.as_variants(), MsgType::Query, &[], &None);
let executor = Executor::new(
item.generics.clone(),
*item.self_ty.clone(),
executor_variants,
)
.emit();
let querier = Querier::new(
item.generics.clone(),
*item.self_ty.clone(),
querier_variants,
)
.emit();
let messages = self.emit_messages();
let contract_api = Api::new(item, generics, custom).emit();
let querier = self.emit_querier();
let executor = self.emit_executor();
let reply = self.emit_reply();

quote! {
pub mod sv {
Expand All @@ -106,6 +95,8 @@ impl<'a> ContractInput<'a> {

#executor

#reply

#contract_api
}
}
Expand Down Expand Up @@ -175,4 +166,23 @@ impl<'a> ContractInput<'a> {
let generic_params = &self.generics;
MtHelpers::new(item, generic_params, custom, override_entry_points.clone()).emit()
}

fn emit_executor(&self) -> TokenStream {
let item = self.item;
let variants = MsgVariants::new(item.as_variants(), MsgType::Exec, &[], &None);

Executor::new(item.generics.clone(), *item.self_ty.clone(), variants).emit()
}
fn emit_querier(&self) -> TokenStream {
let item = self.item;
let variants = MsgVariants::new(item.as_variants(), MsgType::Query, &[], &None);

Querier::new(item.generics.clone(), *item.self_ty.clone(), variants).emit()
}

fn emit_reply(&self) -> TokenStream {
let variants = MsgVariants::new(self.item.as_variants(), MsgType::Reply, &[], &None);

Reply::new(&variants).emit()
}
}
1 change: 1 addition & 0 deletions sylvia-derive/src/contract/communication/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub mod api;
pub mod enum_msg;
pub mod executor;
pub mod querier;
pub mod reply;
pub mod struct_msg;
pub mod wrapper_msg;
60 changes: 60 additions & 0 deletions sylvia-derive/src/contract/communication/reply.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use convert_case::{Case, Casing};
use itertools::Itertools;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{GenericParam, Ident};

use crate::types::msg_variant::MsgVariants;

pub struct Reply<'a> {
variants: &'a MsgVariants<'a, GenericParam>,
}

impl<'a> Reply<'a> {
pub fn new(variants: &'a MsgVariants<'a, GenericParam>) -> Self {
Self { variants }
}

pub fn emit(&self) -> TokenStream {
let unique_handlers = self.emit_reply_ids();

quote! {
#(#unique_handlers)*
}
}

fn emit_reply_ids(&self) -> impl Iterator<Item = TokenStream> + 'a {
self.variants
.as_reply_ids()
.enumerate()
.map(|(id, reply_id)| {
let id = id as u64;

quote! {
pub const #reply_id : u64 = #id ;
}
})
}
}

trait ReplyVariants<'a> {
fn as_reply_ids(&'a self) -> impl Iterator<Item = Ident> + 'a;
}

impl<'a> ReplyVariants<'a> for MsgVariants<'a, GenericParam> {
fn as_reply_ids(&'a self) -> impl Iterator<Item = Ident> + 'a {
self.variants()
.flat_map(|variant| {
if variant.msg_attr().handlers().is_empty() {
return vec![variant.function_name()];
}
variant.msg_attr().handlers().iter().collect()
})
.unique()
.map(|handler| {
let reply_id =
format! {"{}_REPLY_ID", handler.to_string().to_case(Case::UpperSnake)};
Ident::new(&reply_id, handler.span())
})
}
}
8 changes: 6 additions & 2 deletions sylvia-derive/src/parser/attributes/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl ReplyOn {
pub struct MsgAttr {
msg_type: MsgType,
query_resp_type: Option<Ident>,
_reply_handlers: Vec<Ident>,
reply_handlers: Vec<Ident>,
_reply_on: ReplyOn,
}

Expand All @@ -114,6 +114,10 @@ impl MsgAttr {
pub fn resp_type(&self) -> &Option<Ident> {
&self.query_resp_type
}

pub fn handlers(&self) -> &[Ident] {
&self.reply_handlers
}
}

impl PartialEq<MsgType> for MsgAttr {
Expand All @@ -135,7 +139,7 @@ impl Parse for MsgAttr {
Ok(Self {
msg_type,
query_resp_type,
_reply_handlers: reply_handlers,
reply_handlers,
_reply_on: reply_on.unwrap_or_default(),
})
}
Expand Down
4 changes: 4 additions & 0 deletions sylvia-derive/src/types/msg_variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ impl<'a> MsgVariant<'a> {
self.msg_attr.msg_type()
}

pub fn msg_attr(&self) -> &MsgAttr {
&self.msg_attr
}

pub fn return_type(&self) -> &Option<Type> {
&self.return_type
}
Expand Down
1 change: 1 addition & 0 deletions sylvia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ cw-storage-plus = { workspace = true }
cw-utils = { workspace = true }
thiserror = { workspace = true }
trybuild = "1.0.91"
itertools = "0.13.0"

[package.metadata.docs.rs]
all-features = true
Expand Down
28 changes: 28 additions & 0 deletions sylvia/tests/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,31 @@ impl Contract {
Ok(Response::new())
}
}

#[cfg(test)]
mod tests {
use itertools::Itertools;

#[test]
fn reply_id_generation() {
// Assert IDs uniqueness
let unique_ids_count = [
super::sv::CLEAN_REPLY_ID,
super::sv::HANDLER_ONE_REPLY_ID,
super::sv::HANDLER_TWO_REPLY_ID,
super::sv::REPLY_ON_REPLY_ID,
super::sv::REPLY_ON_ALWAYS_REPLY_ID,
]
.iter()
.unique()
.count();

assert_eq!(unique_ids_count, 5);

assert_eq!(super::sv::CLEAN_REPLY_ID, 0);
assert_eq!(super::sv::HANDLER_ONE_REPLY_ID, 1);
assert_eq!(super::sv::HANDLER_TWO_REPLY_ID, 2);
assert_eq!(super::sv::REPLY_ON_REPLY_ID, 3);
assert_eq!(super::sv::REPLY_ON_ALWAYS_REPLY_ID, 4);
}
}

0 comments on commit d4d5ba8

Please sign in to comment.