sylvia_derive/parser/attributes/
msg.rs1use proc_macro_error::emit_error;
2use syn::parse::{Error, Parse, ParseStream, Parser};
3use syn::{bracketed, Ident, MetaList, Result, Token};
4
5#[derive(PartialEq, Eq, Debug, Clone, Copy)]
8pub enum MsgType {
9 Exec,
10 Query,
11 Instantiate,
12 Migrate,
13 Reply,
14 Sudo,
15}
16
17#[derive(Default)]
19struct ArgumentParser {
20 pub query_resp_type: Option<Ident>,
21 pub reply_handlers: Vec<Ident>,
22 pub reply_on: Option<ReplyOn>,
23}
24
25impl Parse for ArgumentParser {
26 fn parse(input: ParseStream) -> Result<Self> {
27 let mut result = Self::default();
28
29 while input.peek2(Ident) {
30 let _: Token![,] = input.parse()?;
31 let arg_type: Ident = input.parse()?;
32 match arg_type.to_string().as_str() {
33 "resp" => {
34 let _: Token![=] = input.parse()?;
35 let resp_type: Ident = input.parse()?;
36 result.query_resp_type = Some(resp_type);
37 }
38 "handlers" => {
39 let _: Token![=] = input.parse()?;
40 let handlers_content;
41 bracketed!(handlers_content in input);
42
43 while !handlers_content.is_empty() {
44 let handler = handlers_content.parse::<Ident>()?;
45 result.reply_handlers.push(handler);
46 if !handlers_content.peek(Token![,]) {
47 break;
48 }
49 let _: Token![,] = handlers_content.parse()?;
50 }
51 }
52 "reply_on" => {
53 let _: Token![=] = input.parse()?;
54 let reply_on: Ident = input.parse()?;
55 let reply_on = ReplyOn::new(reply_on)?;
56 result.reply_on = Some(reply_on);
57 }
58 _ => {
59 return Err(Error::new(
60 arg_type.span(),
61 "Invalid argument type, expected `resp`, `handlers`, `reply_on` or no argument.",
62 ))
63 }
64 }
65 }
66 Ok(result)
67 }
68}
69
70#[derive(Copy, Debug, Default, Clone, PartialEq)]
72pub enum ReplyOn {
73 Success,
74 Error,
75 #[default]
76 Always,
77}
78
79impl std::fmt::Display for ReplyOn {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 match self {
82 ReplyOn::Success => f.write_str("success"),
83 ReplyOn::Error => f.write_str("error"),
84 ReplyOn::Always => f.write_str("always"),
85 }
86 }
87}
88
89impl ReplyOn {
90 pub fn new(reply_on: Ident) -> Result<Self> {
91 match reply_on.to_string().as_str() {
92 "success" => Ok(Self::Success),
93 "error" => Ok(Self::Error),
94 "always" => Ok(Self::Always),
95 _ => Err(Error::new(
96 reply_on.span(),
97 "Invalid argument type, expected one of `success`, `error` or `always`.",
98 )),
99 }
100 }
101
102 pub fn excludes(&self, other: &Self) -> bool {
105 let are_equal = self == other;
106 let is_any_always = self == &ReplyOn::Always || other == &ReplyOn::Always;
107
108 are_equal || is_any_always
109 }
110}
111
112#[derive(Debug, Clone)]
114pub struct MsgAttr {
115 msg_type: MsgType,
116 query_resp_type: Option<Ident>,
117 reply_handlers: Vec<Ident>,
118 reply_on: ReplyOn,
119}
120
121impl MsgAttr {
122 pub fn new(attr: &MetaList) -> Result<Self> {
123 MsgAttr::parse.parse2(attr.tokens.clone()).map_err(|err| {
124 emit_error!(err.span(), err);
125 err
126 })
127 }
128
129 pub fn msg_type(&self) -> MsgType {
130 self.msg_type
131 }
132
133 pub fn resp_type(&self) -> &Option<Ident> {
134 &self.query_resp_type
135 }
136
137 pub fn handlers(&self) -> &[Ident] {
138 &self.reply_handlers
139 }
140
141 pub fn reply_on(&self) -> ReplyOn {
142 self.reply_on
143 }
144}
145
146impl PartialEq<MsgType> for MsgAttr {
147 fn eq(&self, other: &MsgType) -> bool {
148 self.msg_type() == *other
149 }
150}
151
152impl Parse for MsgAttr {
153 fn parse(input: ParseStream) -> Result<Self> {
154 let msg_type: Ident = input.parse()?;
155 let msg_type = MsgType::new(&msg_type)?;
156 let ArgumentParser {
157 query_resp_type,
158 reply_handlers,
159 reply_on,
160 } = ArgumentParser::parse(input)?;
161
162 Ok(Self {
163 msg_type,
164 query_resp_type,
165 reply_handlers,
166 reply_on: reply_on.unwrap_or_default(),
167 })
168 }
169}