sylvia_derive/types/
interfaces.rs

1use 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/// Wrapper around [ContractMessageAttr] vector.
11#[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}