jsonrpsee_proc_macros/
attributes.rs1use std::{fmt, iter};
28
29use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree};
30use syn::{
31 parse::{Parse, ParseStream, Parser},
32 punctuated::Punctuated,
33 spanned::Spanned,
34 Attribute, Error, LitStr, Token,
35};
36
37pub(crate) struct AttributeMeta {
38 pub path: syn::Path,
39 pub arguments: Punctuated<Argument, Token![,]>,
40}
41
42pub(crate) struct Argument {
43 pub label: syn::Ident,
44 pub tokens: TokenStream2,
45}
46
47pub struct NameMapping {
48 pub name: String,
49 pub mapped: Option<String>,
50}
51
52pub struct Bracketed<T> {
53 pub list: Punctuated<T, Token![,]>,
54}
55
56pub type Aliases = Bracketed<LitStr>;
57
58impl Parse for Argument {
59 fn parse(input: ParseStream) -> syn::Result<Self> {
60 let label = input.parse()?;
61
62 let mut scope = 0usize;
63
64 let tokens = iter::from_fn(move || {
68 if scope == 0 && input.peek(Token![,]) {
69 return None;
70 }
71
72 if input.peek(Token![<]) {
73 scope += 1;
74 } else if input.peek(Token![>]) {
75 scope = scope.saturating_sub(1);
76 }
77
78 input.parse::<TokenTree>().ok()
79 })
80 .collect();
81
82 Ok(Argument { label, tokens })
83 }
84}
85
86impl Parse for NameMapping {
87 fn parse(input: ParseStream) -> syn::Result<Self> {
88 let name = input.parse::<LitStr>()?.value();
89
90 let mapped = if input.peek(Token![=>]) {
91 input.parse::<Token![=>]>()?;
92
93 Some(input.parse::<LitStr>()?.value())
94 } else {
95 None
96 };
97
98 Ok(NameMapping { name, mapped })
99 }
100}
101
102impl<T: Parse> Parse for Bracketed<T> {
103 fn parse(input: ParseStream) -> syn::Result<Self> {
104 let content;
105
106 syn::bracketed!(content in input);
107
108 let list = content.parse_terminated(Parse::parse, Token![,])?;
109
110 Ok(Bracketed { list })
111 }
112}
113
114fn parenthesized<T: Parse>(input: ParseStream) -> syn::Result<Punctuated<T, Token![,]>> {
115 let content;
116
117 syn::parenthesized!(content in input);
118
119 content.parse_terminated(T::parse, Token![,])
120}
121
122impl AttributeMeta {
123 pub fn parse(attr: Attribute) -> syn::Result<AttributeMeta> {
126 let path = attr.path().clone();
127
128 let arguments = attr.parse_args_with(|input: ParseStream| {
129 input.parse_terminated(Parse::parse, Token![,])
130 })?;
131
132 Ok(AttributeMeta { path, arguments })
133 }
134
135 pub fn retain<const N: usize>(
140 self,
141 allowed: [&str; N],
142 ) -> syn::Result<[Result<Argument, MissingArgument<'_>>; N]> {
143 assert!(
144 N != 0,
145 "Calling `AttributeMeta::retain` with an empty `allowed` list, this is a bug, please report it"
146 );
147
148 let mut result: [Result<Argument, _>; N] =
149 allowed.map(|name| Err(MissingArgument(self.path.span(), name)));
150
151 for argument in self.arguments {
152 if let Some(idx) = allowed.iter().position(|probe| argument.label == probe) {
153 if let Ok(old) = &result[idx] {
156 return Err(Error::new(
157 old.label.span(),
158 format!("Duplicate argument `{}`", old.label),
159 ));
160 }
161
162 result[idx] = Ok(argument);
163 } else {
164 let mut err_str =
165 format!("Unknown argument `{}`, expected one of: `", argument.label);
166
167 err_str.push_str(allowed[0]);
168 err_str.extend(allowed[1..].iter().flat_map(|&label| ["`, `", label]));
169 err_str.push('`');
170
171 return Err(Error::new(argument.label.span(), err_str));
172 }
173 }
174
175 Ok(result)
176 }
177}
178
179pub(crate) struct MissingArgument<'a>(Span, &'a str);
180
181impl fmt::Display for MissingArgument<'_> {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 let MissingArgument(_, missing) = self;
184
185 write!(f, "Missing argument `{missing}`")
186 }
187}
188
189impl From<MissingArgument<'_>> for Error {
190 fn from(missing: MissingArgument) -> Self {
191 Error::new(missing.0, missing)
192 }
193}
194
195impl Argument {
196 pub fn flag(self) -> syn::Result<()> {
198 if self.tokens.is_empty() {
199 Ok(())
200 } else {
201 Err(Error::new(self.tokens.span(), "Expected a flag argument"))
202 }
203 }
204
205 pub fn value<T: Parse>(self) -> syn::Result<T> {
207 fn value_parser<T: Parse>(stream: ParseStream) -> syn::Result<T> {
208 stream.parse::<Token![=]>()?;
209 stream.parse()
210 }
211
212 value_parser.parse2(self.tokens)
213 }
214
215 pub fn group<T>(self) -> syn::Result<Punctuated<T, Token![,]>>
216 where
217 T: Parse,
218 {
219 parenthesized.parse2(self.tokens)
220 }
221
222 pub fn string(self) -> syn::Result<String> {
224 self.value::<LitStr>().map(|lit| lit.value())
225 }
226}
227
228pub(crate) fn optional<T, F>(
229 arg: Result<Argument, MissingArgument>,
230 transform: F,
231) -> syn::Result<Option<T>>
232where
233 F: Fn(Argument) -> syn::Result<T>,
234{
235 arg.ok().map(transform).transpose()
236}