sylvia_derive/interface/communication/
enum_msg.rs1use crate::parser::attributes::MsgAttrForwarding;
2use crate::parser::{Custom, MsgType, ParsedSylviaAttributes};
3use crate::types::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
4use crate::types::msg_variant::MsgVariants;
5use crate::utils::emit_bracketed_generics;
6use proc_macro2::TokenStream;
7use quote::quote;
8use syn::{parse_quote, Ident, ItemTrait, Type};
9
10pub struct EnumMessage<'a> {
12 source: &'a ItemTrait,
13 variants: MsgVariants<'a, Ident>,
14 associated_types: &'a AssociatedTypes<'a>,
15 msg_ty: MsgType,
16 resp_type: Type,
17 query_type: Type,
18 msg_attrs_to_forward: Vec<MsgAttrForwarding>,
19}
20
21impl<'a> EnumMessage<'a> {
22 pub fn new(
23 source: &'a ItemTrait,
24 msg_ty: MsgType,
25 custom: &'a Custom,
26 variants: MsgVariants<'a, Ident>,
27 associated_types: &'a AssociatedTypes<'a>,
28 ) -> Self {
29 let trait_name = &source.ident;
30 let associated_exec =
31 associated_types.emit_contract_custom_type_accessor(trait_name, EXEC_TYPE);
32 let associated_query =
33 associated_types.emit_contract_custom_type_accessor(trait_name, QUERY_TYPE);
34
35 let resp_type = custom
36 .msg
37 .clone()
38 .or(associated_exec)
39 .unwrap_or_else(Custom::default_type);
40
41 let query_type = custom
42 .query
43 .clone()
44 .or(associated_query)
45 .unwrap_or_else(Custom::default_type);
46
47 let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
48 .msg_attrs_forward
49 .into_iter()
50 .filter(|attr| attr.msg_type == msg_ty)
51 .collect();
52
53 Self {
54 source,
55 variants,
56 associated_types,
57 msg_ty,
58 resp_type,
59 query_type,
60 msg_attrs_to_forward,
61 }
62 }
63
64 pub fn emit(&self) -> TokenStream {
65 let Self {
66 source,
67 variants,
68 associated_types,
69 msg_ty,
70 resp_type,
71 query_type,
72 msg_attrs_to_forward,
73 } = self;
74
75 let trait_name = &source.ident;
76 let enum_name = msg_ty.emit_msg_name();
77 let unique_enum_name =
78 Ident::new(&format!("{}{}", trait_name, enum_name), enum_name.span());
79
80 let match_arms = variants.emit_dispatch_legs();
81 let mut msgs = variants.as_names_snake_cased();
82 msgs.sort();
83 let msgs_cnt = msgs.len();
84 let variants_constructors = variants.emit_constructors();
85 let msg_variants = variants.emit();
86
87 let ctx_type = msg_ty.emit_ctx_type(query_type);
88 let dispatch_type = msg_ty.emit_result_type(resp_type, &parse_quote!(ContractT::Error));
89
90 let used_generics = variants.used_generics();
91 let unused_generics = variants.unused_generics();
92 let where_predicates = associated_types
93 .without_error()
94 .map(ItemType::as_where_predicate);
95 let where_clause = variants.where_clause();
96 let contract_predicate = associated_types.emit_contract_predicate(trait_name);
97
98 let phantom_variant = variants.emit_phantom_variant();
99 let phatom_match_arm = variants.emit_phantom_match_arm();
100 let bracketed_used_generics = emit_bracketed_generics(used_generics);
101
102 let ep_name = msg_ty.emit_ep_name();
103 let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), enum_name.span());
104 let derive_call = msg_ty.emit_derive_call();
105 let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
106
107 quote! {
108 #[allow(clippy::derive_partial_eq_without_eq)]
109 #derive_call
110 #( #[ #msg_attrs_to_forward ] )*
111 #[serde(rename_all="snake_case")]
112 pub enum #unique_enum_name #bracketed_used_generics {
113 #(#msg_variants,)*
114 #phantom_variant
115 }
116 pub type #enum_name #bracketed_used_generics = #unique_enum_name #bracketed_used_generics;
117
118 impl #bracketed_used_generics #unique_enum_name #bracketed_used_generics #where_clause {
119 pub fn dispatch<ContractT, #(#unused_generics,)*>(self, contract: &ContractT, ctx: #ctx_type)
120 -> #dispatch_type
121 where
122 #(#where_predicates,)*
123 #contract_predicate
124 {
125 use #unique_enum_name::*;
126
127 match self {
128 #(#match_arms,)*
129 #phatom_match_arm
130 }
131 }
132 #(#variants_constructors)*
133 }
134
135 pub const fn #messages_fn_name () -> [&'static str; #msgs_cnt] {
136 [#(#msgs,)*]
137 }
138 }
139 }
140}