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