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 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}