sylvia_derive/contract/communication/
enum_msg.rs1use crate::crate_module;
2use crate::parser::attributes::MsgAttrForwarding;
3use crate::parser::variant_descs::AsVariantDescs;
4use crate::parser::{ContractErrorAttr, Custom, MsgType, ParsedSylviaAttributes};
5use crate::types::msg_variant::MsgVariants;
6use crate::utils::emit_bracketed_generics;
7use proc_macro2::TokenStream;
8use quote::quote;
9use syn::spanned::Spanned;
10use syn::{GenericParam, Ident, ItemImpl, Type, WhereClause};
11
12pub struct EnumMessage<'a> {
14 variants: MsgVariants<'a, GenericParam>,
15 msg_ty: MsgType,
16 contract: &'a Type,
17 error: &'a ContractErrorAttr,
18 custom: &'a Custom,
19 where_clause: &'a Option<WhereClause>,
20 msg_attrs_to_forward: Vec<MsgAttrForwarding>,
21}
22
23impl<'a> EnumMessage<'a> {
24 pub fn new(
25 source: &'a ItemImpl,
26 msg_ty: MsgType,
27 generics: &'a [&'a GenericParam],
28 error: &'a ContractErrorAttr,
29 custom: &'a Custom,
30 ) -> Self {
31 let where_clause = &source.generics.where_clause;
32 let variants = MsgVariants::new(source.as_variants(), msg_ty, generics, where_clause);
33 let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
34 .msg_attrs_forward
35 .into_iter()
36 .filter(|attr| attr.msg_type == msg_ty)
37 .collect();
38
39 Self {
40 variants,
41 msg_ty,
42 contract: &source.self_ty,
43 error,
44 custom,
45 where_clause,
46 msg_attrs_to_forward,
47 }
48 }
49
50 pub fn emit(&self) -> TokenStream {
51 let sylvia = crate_module();
52
53 let Self {
54 variants,
55 msg_ty,
56 contract,
57 error,
58 custom,
59 where_clause,
60 msg_attrs_to_forward,
61 ..
62 } = self;
63
64 let enum_name = msg_ty.emit_msg_name();
65 let match_arms = variants.emit_dispatch_legs();
66 let unused_generics = variants.unused_generics();
67 let bracketed_unused_generics = emit_bracketed_generics(unused_generics);
68 let used_generics = variants.used_generics();
69 let bracketed_used_generics = emit_bracketed_generics(used_generics);
70
71 let mut variant_names = variants.as_names_snake_cased();
72 variant_names.sort();
73 let variants_cnt = variant_names.len();
74 let variants_constructors = variants.emit_constructors();
75 let variants = variants.emit();
76
77 let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default());
78 let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error);
79 let derive_call = msg_ty.emit_derive_call();
80 let ep_name = msg_ty.emit_ep_name();
81 let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span());
82
83 let phantom_variant = msg_ty.emit_phantom_variant(used_generics);
84 let phantom_match_arm = match !used_generics.is_empty() {
85 true => quote! {
86 _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into),
87 },
88 false => quote! {},
89 };
90 let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
91
92 quote! {
93 #[allow(clippy::derive_partial_eq_without_eq)]
94 #derive_call
95 #( #[ #msg_attrs_to_forward ] )*
96 #[serde(rename_all="snake_case")]
97 pub enum #enum_name #bracketed_used_generics {
98 #(#variants,)*
99 #phantom_variant
100 }
101
102 impl #bracketed_used_generics #enum_name #bracketed_used_generics {
103 pub fn dispatch #bracketed_unused_generics (self, contract: &#contract, ctx: #ctx_type) -> #ret_type #where_clause {
104 use #enum_name::*;
105
106 match self {
107 #(#match_arms,)*
108 #phantom_match_arm
109 }
110 }
111
112 #(#variants_constructors)*
113 }
114
115 pub const fn #messages_fn_name () -> [&'static str; #variants_cnt] {
116 [#(#variant_names,)*]
117 }
118 }
119 }
120}