Skip to content

Commit

Permalink
WIP: Reply dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
jawoznia committed Sep 6, 2024
1 parent 8d5cd4b commit 4f359ed
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 73 deletions.
124 changes: 82 additions & 42 deletions sylvia-derive/src/contract/communication/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use itertools::Itertools;
use proc_macro2::TokenStream;
use proc_macro_error::emit_error;
use quote::quote;
use syn::{parse_quote, GenericParam, Ident, ItemImpl};
use syn::{parse_quote, GenericParam, Ident, ItemImpl, Type};

use crate::crate_module;
use crate::parser::attributes::msg::ReplyOn;
Expand Down Expand Up @@ -48,38 +48,13 @@ impl<'a> Reply<'a> {
)
})
}
_ =>{ let _ = reply_id_to_data.entry(reply_id).and_modify(|values| values.push((function_name, reply_on))).or_insert_with(|| vec![(function_name, reply_on)]);},
// None => reply_id_to_data.insert(reply_id, vec![(function_name, reply_on)]),
_ => {
let _ = reply_id_to_data.entry(reply_id)
.and_modify(|values| values.push((function_name, reply_on)))
.or_insert_with(|| vec![(function_name, reply_on)]);
},
}
}
// let entry = reply_id_to_data.try_insert(reply_id, vec![(function_name, reply_on)]);
// match entry {
// Ok(_) => (),
// Err(err) => {
// if err
// .entry
// .get()
// .iter()
// .any(|(_, used_reply_on)| used_reply_on.excludes(reply_on))
// {
// emit_error!(reply_id.span(), "Duplicated reply handler.";
// note = prev_reply_id.span() => format!("Previous definition of handler={} for reply_on={}", prev_reply_id.to_string(), prev_reply_on)
// )
// }
// err.entry.get_mut().push((function_name, reply_on));
// }
// }
// match reply_id_to_data.get_key_value(&reply_id) {
// Some((&prev_reply_id, &(prev_function_name, prev_reply_on)))
// if prev_reply_on == reply_on =>
// {
// emit_error!(reply_id.span(), "Duplicated reply handler.";
// note = prev_reply_id.span() => format!("Previous definition of handler={} for reply_on={}", prev_reply_id.to_string(), prev_reply_on)
// )
// }
// _ => reply_id_to_data.insert(reply_id, (function_name, reply_on)),
// }
// }

Self {
source,
Expand All @@ -90,7 +65,7 @@ impl<'a> Reply<'a> {
}

pub fn emit(&self) -> TokenStream {
let unique_handlers = self.emit_reply_ids();
let unique_handlers: Vec<_> = self.emit_reply_ids().collect();
let dispatch = self.emit_dispatch();

quote! {
Expand All @@ -107,7 +82,7 @@ impl<'a> Reply<'a> {
let Self {
source,
generics,
variants,
reply_id_to_data,
..
} = self;

Expand All @@ -120,20 +95,55 @@ impl<'a> Reply<'a> {
let error = parse_quote!( < #contract as #sylvia ::types::ContractApi>::Error);
let ctx_params = msg_ty.emit_ctx_params(&custom_query);
let ret_type = msg_ty.emit_result_type(&custom_msg, &error);
let reply_ids = variants.as_reply_ids();

let match_arms = reply_id_to_data.iter().map(|(reply_id, values)| {
let result_match_arms = values.iter().map(|(function_name, reply_on)| {
let result_match_arm = reply_on.emit_match_arm();
let result_match_arm_body =
reply_on.emit_match_arm_body(function_name, &self.source.self_ty);
quote! {
#result_match_arm => {
#result_match_arm_body
}
}
});
// TODO: Add proper result forwarding.
let default_match_arm = if !values
.iter()
.any(|(_, reply_on)| reply_on == &ReplyOn::Always)
{
quote! {
_ => Ok( #sylvia ::cw_std::Response::new())

}
} else {
quote! {}
};

quote! {
#reply_id => {
match result {
#(#result_match_arms,)*
#default_match_arm
}
}
}
});

quote! {
pub fn dispatch_reply < #(#generics),* >( #ctx_params , reply: #sylvia ::cw_std::Reply) -> #ret_type #where_clause {
pub fn dispatch_reply < #(#generics),* >( #ctx_params , msg: #sylvia ::cw_std::Reply) -> #ret_type #where_clause {
let #sylvia ::cw_std::Reply {
id,
payload,
gas_used,
result,
} = reply;
} = msg;

// match id {
// }
Ok(Response::new())
match id {
#(#match_arms,)*
// TODO: Add proper result forwarding.
_ => Ok( #sylvia ::cw_std::Response::new())
}
}
}
}
Expand All @@ -142,9 +152,9 @@ impl<'a> Reply<'a> {
/// [`reply_handler`](crate::parser::attributes::msg::MsgAttr::reply_handlers) and
/// [`function_name`](crate::types::msg_variant::MsgVariant::function_name) not anotated with
/// the `#[sv::msg(..)]` attribute with the `handlers` parameter.
fn emit_reply_ids(&self) -> impl Iterator<Item = TokenStream> + 'a {
self.variants
.as_reply_ids()
fn emit_reply_ids(&'a self) -> impl Iterator<Item = TokenStream> + 'a {
self.reply_id_to_data
.keys()
.enumerate()
.map(|(id, reply_id)| {
let id = id as u64;
Expand Down Expand Up @@ -223,3 +233,33 @@ impl AsReplyId for Ident {
Ident::new(&reply_id, self.span())
}
}

trait ReplyOnMethods {
fn emit_match_arm(&self) -> TokenStream;
fn emit_match_arm_body(&self, function_name: &Ident, contract: &Type) -> TokenStream;
}

impl ReplyOnMethods for ReplyOn {
fn emit_match_arm(&self) -> TokenStream {
match self {
ReplyOn::Success => quote! { Ok(response) },
ReplyOn::Failure => quote! { Err(error) },
ReplyOn::Always => quote! { _ },
}
}

fn emit_match_arm_body(&self, function_name: &Ident, contract: &Type) -> TokenStream {
match self {
ReplyOn::Success => quote! {
let SubMsgResponse { events, data } = response;
#contract ::new(). #function_name ((deps, env, gas_used, events, data).into(), data, payload)
},
ReplyOn::Failure => quote! {
#contract ::new(). #function_name ((deps, env, gas_used, vec![], vec![]).into(), error, payload)
},
ReplyOn::Always => quote! {
#contract ::new(). #function_name ((deps, env, gas_used, vec![], vec![]).into(), result, payload)
},
}
}
}
5 changes: 2 additions & 3 deletions sylvia-derive/src/contract/mt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,10 +531,9 @@ impl<'a> MtHelpers<'a> {
None => reply_variants
.get_only_variant()
.as_ref()
.map(|reply| {
let reply_name = reply.name().to_case(Case::Snake);
.map(|_| {
quote! {
self. #reply_name ((deps, env).into(), msg).map_err(Into::into)
dispatch_reply(deps, env, msg).map_err(Into::into)
}
})
.unwrap_or_else(|| {
Expand Down
2 changes: 1 addition & 1 deletion sylvia-derive/src/entry_points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl<'a> EntryPoints<'a> {
};
let dispatch = match msg_ty {
MsgType::Reply => quote! {
#contract_turbo ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
sv::dispatch_reply(deps, env, msg).map_err(Into::into)
},
_ => quote! {
msg.dispatch(& #contract_turbo ::new() , ( #values )).map_err(Into::into)
Expand Down
5 changes: 0 additions & 5 deletions sylvia-derive/src/parser/attributes/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,6 @@ impl ReplyOn {
let are_equal = self == other;
let is_any_always = self == &ReplyOn::Always || other == &ReplyOn::Always;

println!(
"L: {}, R: {}, are_equal: {}, is_any_always: {}",
self, other, are_equal, is_any_always
);

are_equal || is_any_always
}
}
Expand Down
47 changes: 31 additions & 16 deletions sylvia/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Module providing utilities to build and use sylvia contracts.
use cosmwasm_std::{Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, WasmMsg};
use cosmwasm_std::{
Binary, Coin, Deps, DepsMut, Empty, Env, Event, MessageInfo, MsgResponse, WasmMsg,
};
use derivative::Derivative;
use schemars::JsonSchema;
use serde::de::DeserializeOwned;
Expand Down Expand Up @@ -441,45 +443,42 @@ impl<'a, Contract: ?Sized> AsRef<cosmwasm_std::Addr> for Remote<'a, Contract> {
}
}

/// Represantation of `reply` context received in entry point as
/// (DepsMut, Env) tuple.
/// Represantation of `reply` context received in entry point.
pub struct ReplyCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: DepsMut<'a, C>,
pub env: Env,
pub gas_used: u64,
pub events: Vec<Event>,
pub msg_responses: Vec<MsgResponse>,
}

/// Represantation of `reply` context received in entry point as
/// (DepsMut, Env) tuple.
/// Represantation of `migrate` context received in entry point.
pub struct MigrateCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: DepsMut<'a, C>,
pub env: Env,
}

/// Represantation of `reply` context received in entry point as
/// (DepsMut, Env, MessageInfo) tuple.
/// Represantation of `execute` context received in entry point.
pub struct ExecCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: DepsMut<'a, C>,
pub env: Env,
pub info: MessageInfo,
}

/// Represantation of `instantiate` context received in entry point as
/// (DepsMut, Env, MessageInfo) tuple.
/// Represantation of `instantiate` context received in entry point.
pub struct InstantiateCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: DepsMut<'a, C>,
pub env: Env,
pub info: MessageInfo,
}

/// Represantation of `query` context received in entry point as
/// (Deps, Env) tuple.
/// Represantation of `query` context received in entry point.
pub struct QueryCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: Deps<'a, C>,
pub env: Env,
}

/// Represantation of `sudo` context received in entry point as
/// (DepsMut, Env) tuple.
/// Represantation of `sudo` context received in entry point.
pub struct SudoCtx<'a, C: cosmwasm_std::CustomQuery = Empty> {
pub deps: DepsMut<'a, C>,
pub env: Env,
Expand Down Expand Up @@ -520,9 +519,25 @@ impl<'a, C: cosmwasm_std::CustomQuery> From<(DepsMut<'a, C>, Env)> for MigrateCt
}
}

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: cosmwasm_std::CustomQuery>
From<(DepsMut<'a, C>, Env, u64, Vec<Event>, Vec<MsgResponse>)> for ReplyCtx<'a, C>
{
fn from(
(deps, env, gas_used, events, msg_responses): (
DepsMut<'a, C>,
Env,
u64,
Vec<Event>,
Vec<MsgResponse>,
),
) -> Self {
Self {
deps,
env,
gas_used,
events,
msg_responses,
}
}
}

Expand Down
8 changes: 7 additions & 1 deletion sylvia/tests/replies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod noop_contract {
}

mod reply_contract {
use cosmwasm_std::{Binary, SubMsgResult};
use sylvia::types::{ExecCtx, InstantiateCtx, ReplyCtx};
use sylvia::{contract, entry_points};

Expand Down Expand Up @@ -69,7 +70,12 @@ mod reply_contract {
}

#[sv::msg(reply)]
fn reply(&self, _ctx: ReplyCtx, _msg: Reply) -> StdResult<Response> {
fn reply(
&self,
_ctx: ReplyCtx,
result: SubMsgResult,
payload: Binary,
) -> StdResult<Response> {
let resp = Response::new().set_data(to_json_binary("data")?);
Ok(resp)
}
Expand Down
31 changes: 26 additions & 5 deletions sylvia/tests/reply.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cosmwasm_std::{Binary, SubMsgResult};
use sylvia::contract;
use sylvia::cw_std::{Reply, Response, StdResult};
use sylvia::types::{InstantiateCtx, ReplyCtx};
Expand All @@ -16,31 +17,51 @@ impl Contract {
}

#[sv::msg(reply)]
fn clean(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn clean(
&self,
_ctx: ReplyCtx,
_result: SubMsgResult,
_payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[allow(dead_code)]
#[sv::msg(reply, handlers(handler_one, handler_two))]
fn custom_handlers(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn custom_handlers(
&self,
_ctx: ReplyCtx,
_result: SubMsgResult,
_payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[allow(dead_code)]
#[sv::msg(reply, reply_on = success)]
fn reply_on(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn reply_on(&self, _ctx: ReplyCtx, _data: Binary, _payload: Binary) -> StdResult<Response> {
Ok(Response::new())
}

#[allow(dead_code)]
#[sv::msg(reply, reply_on = always)]
fn reply_on_always(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn reply_on_always(
&self,
_ctx: ReplyCtx,
_result: SubMsgResult,
_payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[allow(dead_code)]
#[sv::msg(reply, handlers(reply_on), reply_on = failure)]
fn both_parameters(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn both_parameters(
&self,
_ctx: ReplyCtx,
_error: String,
_payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}
}
Expand Down

0 comments on commit 4f359ed

Please sign in to comment.