sylvia_derive/types/
interfaces.rs1use proc_macro2::{Ident, TokenStream};
2use quote::quote;
3use syn::spanned::Spanned;
4use syn::{ItemImpl, Path, Type};
5
6use crate::crate_module;
7use crate::parser::attributes::msg::MsgType;
8use crate::parser::{ContractMessageAttr, ParsedSylviaAttributes};
9
10#[derive(Debug, Default)]
12pub struct Interfaces {
13 interfaces: Vec<ContractMessageAttr>,
14}
15
16impl Interfaces {
17 pub fn new(source: &ItemImpl) -> Self {
18 let interfaces = ParsedSylviaAttributes::new(source.attrs.iter()).messages_attrs;
19 Self { interfaces }
20 }
21
22 pub fn emit_glue_message_variants(
23 &self,
24 msg_ty: &MsgType,
25 contract: &Type,
26 ) -> Vec<TokenStream> {
27 self.interfaces
28 .iter()
29 .map(|interface| {
30 let ContractMessageAttr {
31 module, variant, ..
32 } = interface;
33
34 let interface_enum = quote! { < #contract as #module ::sv::InterfaceMessagesApi> };
35 let type_name = msg_ty.as_accessor_name();
36
37 quote! { #variant ( #interface_enum :: #type_name) }
38 })
39 .collect()
40 }
41
42 pub fn emit_glue_message_types(&self, msg_ty: &MsgType, contract: &Type) -> Vec<TokenStream> {
43 self.interfaces
44 .iter()
45 .map(|interface| {
46 let ContractMessageAttr { module, .. } = interface;
47
48 let interface_enum = quote! { < #contract as #module ::sv::InterfaceMessagesApi> };
49 let type_name = msg_ty.as_accessor_name();
50
51 quote! { #interface_enum :: #type_name }
52 })
53 .collect()
54 }
55
56 pub fn emit_messages_call(&self, msg_ty: &MsgType) -> Vec<TokenStream> {
57 self.interfaces
58 .iter()
59 .map(|interface| {
60 let ContractMessageAttr { module, .. } = interface;
61
62 let ep_name = msg_ty.emit_ep_name();
63 let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), module.span());
64 quote! {
65 &#module ::sv:: #messages_fn_name()
66 }
67 })
68 .collect()
69 }
70
71 pub fn emit_deserialization_attempts(&self, msg_ty: &MsgType) -> Vec<TokenStream> {
72 self.interfaces
73 .iter()
74 .map(|interface| {
75 let ContractMessageAttr {
76 module, variant, ..
77 } = interface;
78 let ep_name = msg_ty.emit_ep_name();
79 let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), module.span());
80
81 quote! {
82 let msgs = &#module ::sv:: #messages_fn_name();
83 if msgs.into_iter().any(|msg| msg == &recv_msg_name) {
84 match val.deserialize_into() {
85 Ok(msg) => return Ok(Self:: #variant (msg)),
86 Err(err) => return Err(D::Error::custom(err)).map(Self:: #variant),
87 };
88 }
89 }
90 })
91 .collect()
92 }
93
94 pub fn emit_response_schemas_calls(
95 &self,
96 msg_ty: &MsgType,
97 contract: &Type,
98 ) -> Vec<TokenStream> {
99 self.interfaces
100 .iter()
101 .map(|interface| {
102 let ContractMessageAttr {
103 module, ..
104 } = interface;
105
106 let type_name = msg_ty.as_accessor_name();
107 quote! {
108 <#contract as #module ::sv::InterfaceMessagesApi> :: #type_name :: response_schemas_impl()
109 }
110 })
111 .collect()
112 }
113
114 pub fn emit_dispatch_arms(&self, msg_ty: &MsgType) -> Vec<TokenStream> {
115 let sylvia = crate_module();
116 let contract_enum_name = msg_ty.emit_msg_wrapper_name();
117
118 self.interfaces.iter().map(|interface| {
119 let ContractMessageAttr {
120 variant,
121 customs,
122 ..
123 } = interface;
124
125 let ctx = msg_ty.emit_ctx_dispatch_values(customs);
126
127 match (msg_ty, customs.has_msg) {
128 (MsgType::Exec, true) | (MsgType::Sudo, true) => quote! {
129 #contract_enum_name:: #variant(msg) => #sylvia ::into_response::IntoResponse::into_response(msg.dispatch(contract, Into::into( #ctx ))?).map_err(Into::into)
130 },
131 _ => quote! {
132 #contract_enum_name :: #variant(msg) => msg.dispatch(contract, Into::into( #ctx ))
133 },
134 }
135 }).collect()
136 }
137
138 pub fn variants_names(&self) -> impl Iterator<Item = &Ident> {
139 self.interfaces.iter().map(|interface| &interface.variant)
140 }
141
142 pub fn variants_modules(&self) -> impl Iterator<Item = &Path> {
143 self.interfaces.iter().map(|interface| &interface.module)
144 }
145}