sylvia_derive/types/
msg_type.rs

1use proc_macro2::TokenStream;
2use proc_macro_error::emit_error;
3use quote::quote;
4use syn::fold::Fold;
5use syn::parse::Error;
6use syn::{parse_quote, GenericParam, Ident, Result, Type};
7
8use crate::crate_module;
9use crate::fold::StripSelfPath;
10use crate::parser::attributes::msg::MsgType;
11use crate::parser::Customs;
12
13impl MsgType {
14    pub fn new(msg_type: &Ident) -> Result<Self> {
15        match msg_type.to_string().as_str() {
16            "exec" => Ok(Self::Exec),
17            "query" => Ok(Self::Query ),
18            "instantiate" => Ok(Self::Instantiate),
19            "migrate" => Ok(Self::Migrate),
20            "reply" => Ok(Self::Reply ),
21            "sudo" => Ok(Self::Sudo),
22            _ => Err(Error::new(
23                msg_type.span(),
24                "Invalid message type, expected one of: `exec`, `query`, `instantiate`, `migrate`, `reply` or `sudo`.",
25            ))
26        }
27    }
28
29    pub fn emit_ctx_type(self, query_type: &Type) -> TokenStream {
30        use MsgType::*;
31
32        let sylvia = crate_module();
33
34        match self {
35            Exec | Instantiate => quote! {
36                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env, #sylvia ::cw_std::MessageInfo)
37            },
38            Migrate | Reply | Sudo => quote! {
39                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env)
40            },
41            Query => quote! {
42                (#sylvia ::cw_std::Deps< #query_type >, #sylvia ::cw_std::Env)
43            },
44        }
45    }
46
47    pub fn emit_ctx_dispatch_values(self, customs: &Customs) -> TokenStream {
48        use MsgType::*;
49
50        match (self, customs.has_query) {
51            (Exec, true) => quote! {
52                (ctx.0.into_empty(), ctx.1, ctx.2)
53            },
54            (Query, true) | (Sudo, true) => quote! {
55                (ctx.0.into_empty(), ctx.1)
56            },
57            _ => quote! { ctx },
58        }
59    }
60
61    pub fn emit_ctx_params(self, query_type: &Type) -> TokenStream {
62        use MsgType::*;
63
64        let sylvia = crate_module();
65
66        match self {
67            Exec | Instantiate => quote! {
68                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env, info: #sylvia ::cw_std::MessageInfo
69            },
70            Migrate | Reply | Sudo => quote! {
71                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env
72            },
73            Query => quote! {
74                deps: #sylvia ::cw_std::Deps< #query_type>, env: #sylvia ::cw_std::Env
75            },
76        }
77    }
78
79    pub fn emit_ep_name(self) -> Ident {
80        match self {
81            Self::Exec => parse_quote! { execute },
82            Self::Instantiate => parse_quote! { instantiate },
83            Self::Migrate => parse_quote! { migrate },
84            Self::Sudo => parse_quote! { sudo },
85            Self::Reply => parse_quote! { reply },
86            Self::Query => parse_quote! { query },
87        }
88    }
89
90    pub fn emit_ctx_values(self) -> TokenStream {
91        use MsgType::*;
92
93        match self {
94            Exec | Instantiate => quote! { deps, env, info },
95            Migrate | Reply | Query | Sudo => quote! { deps, env },
96        }
97    }
98
99    /// Emits type which should be returned by dispatch function for this kind of message
100    pub fn emit_result_type(self, msg_type: &Type, err_type: &Type) -> TokenStream {
101        use MsgType::*;
102
103        let sylvia = crate_module();
104
105        match self {
106            Exec | Instantiate | Migrate | Reply | Sudo => {
107                quote! {
108                    std::result::Result< #sylvia:: cw_std::Response <#msg_type>, #err_type>
109                }
110            }
111            Query => quote! {
112                std::result::Result<#sylvia ::cw_std::Binary, #err_type>
113            },
114        }
115    }
116
117    pub fn emit_msg_wrapper_name(&self) -> Ident {
118        match self {
119            MsgType::Exec => parse_quote! { ContractExecMsg },
120            MsgType::Query => parse_quote! { ContractQueryMsg },
121            MsgType::Sudo => parse_quote! { ContractSudoMsg },
122            _ => self.emit_msg_name(),
123        }
124    }
125
126    pub fn emit_msg_name(&self) -> Ident {
127        match self {
128            MsgType::Exec => parse_quote! { ExecMsg },
129            MsgType::Query => parse_quote! { QueryMsg },
130            MsgType::Instantiate => parse_quote! { InstantiateMsg },
131            MsgType::Migrate => parse_quote! { MigrateMsg },
132            MsgType::Reply => parse_quote! { ReplyMsg },
133            MsgType::Sudo => parse_quote! { SudoMsg },
134        }
135    }
136
137    pub fn as_accessor_wrapper_name(&self) -> Type {
138        match self {
139            MsgType::Exec => parse_quote! { ContractExec },
140            MsgType::Query => parse_quote! { ContractQuery },
141            MsgType::Sudo => parse_quote! { ContractSudo },
142            _ => self.as_accessor_name(),
143        }
144    }
145
146    pub fn as_accessor_name(&self) -> Type {
147        match self {
148            MsgType::Instantiate => parse_quote! { Instantiate },
149            MsgType::Exec => parse_quote! { Exec },
150            MsgType::Query => parse_quote! { Query },
151            MsgType::Migrate => parse_quote! { Migrate },
152            MsgType::Sudo => parse_quote! { Sudo },
153            MsgType::Reply => parse_quote! { Reply },
154        }
155    }
156
157    pub fn emit_phantom_variant(&self, generics: &[&GenericParam]) -> TokenStream {
158        match self {
159            _ if generics.is_empty() => quote! {},
160            MsgType::Query => quote! {
161                #[serde(skip)]
162                #[returns(( #(#generics,)* ))]
163                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
164            },
165            _ => quote! {
166                #[serde(skip)]
167                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
168            },
169        }
170    }
171
172    pub fn emit_derive_call(&self) -> TokenStream {
173        let sylvia = crate_module();
174        let cw_schema = quote! { #sylvia:: cw_schema }.to_string();
175        let schemars = quote! { #sylvia:: cw_schema::schemars }.to_string();
176        let serde = quote! { #sylvia:: serde }.to_string();
177
178        match self {
179            MsgType::Query => quote! {
180                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #sylvia:: cw_schema::QueryResponses)]
181                #[schemars(crate = #schemars )]
182                #[query_responses(crate = #cw_schema )]
183                #[serde(crate = #serde )]
184            },
185            _ => quote! {
186                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)]
187                #[schemars(crate = #schemars )]
188                #[serde(crate = #serde )]
189            },
190        }
191    }
192
193    pub fn emit_dispatch_leg(&self, function_name: &Ident, args: &Vec<Ident>) -> TokenStream {
194        use MsgType::*;
195        let sylvia = crate_module();
196
197        match self {
198            Exec | Sudo => quote! {
199                contract.#function_name(Into::into(ctx), #(#args),*).map_err(Into::into)
200            },
201            Query => quote! {
202                #sylvia ::cw_std::to_json_binary(&contract.#function_name(Into::into(ctx), #(#args),*)?).map_err(Into::into)
203            },
204            Instantiate | Migrate | Reply => {
205                emit_error!(function_name.span(), "Internal Error";
206                note = "Dispatch leg should be called only for `Enum` type messages.");
207                quote! {}
208            }
209        }
210    }
211
212    pub fn emit_returns_attribute(&self, return_type: &Option<Type>) -> TokenStream {
213        match (self, return_type) {
214            (MsgType::Query, Some(return_type)) => {
215                let stripped_return_type = StripSelfPath.fold_type(return_type.clone());
216                quote! { #[returns(#stripped_return_type)] }
217            }
218            _ => quote! {},
219        }
220    }
221}