Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_macros / src / export / attributes.rs
blobc3edcd59202931690e1a7f29e8a01d4dad2f1555
1 use crate::util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs};
3 use proc_macro2::TokenStream;
4 use quote::ToTokens;
5 use syn::{
6     parse::{Parse, ParseStream},
7     Attribute, LitStr, Meta, PathArguments, PathSegment, Token,
8 };
10 #[derive(Default)]
11 pub struct ExportAttributeArguments {
12     pub(crate) async_runtime: Option<AsyncRuntime>,
13     pub(crate) callback_interface: Option<kw::callback_interface>,
14     pub(crate) constructor: Option<kw::constructor>,
15     // tried to make this a vec but that got messy quickly...
16     pub(crate) trait_debug: Option<kw::Debug>,
17     pub(crate) trait_display: Option<kw::Display>,
18     pub(crate) trait_hash: Option<kw::Hash>,
19     pub(crate) trait_eq: Option<kw::Eq>,
22 impl Parse for ExportAttributeArguments {
23     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
24         parse_comma_separated(input)
25     }
28 impl UniffiAttributeArgs for ExportAttributeArguments {
29     fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
30         let lookahead = input.lookahead1();
31         if lookahead.peek(kw::async_runtime) {
32             let _: kw::async_runtime = input.parse()?;
33             let _: Token![=] = input.parse()?;
34             Ok(Self {
35                 async_runtime: Some(input.parse()?),
36                 ..Self::default()
37             })
38         } else if lookahead.peek(kw::callback_interface) {
39             Ok(Self {
40                 callback_interface: input.parse()?,
41                 ..Self::default()
42             })
43         } else if lookahead.peek(kw::constructor) {
44             Ok(Self {
45                 constructor: input.parse()?,
46                 ..Self::default()
47             })
48         } else if lookahead.peek(kw::Debug) {
49             Ok(Self {
50                 trait_debug: input.parse()?,
51                 ..Self::default()
52             })
53         } else if lookahead.peek(kw::Display) {
54             Ok(Self {
55                 trait_display: input.parse()?,
56                 ..Self::default()
57             })
58         } else if lookahead.peek(kw::Hash) {
59             Ok(Self {
60                 trait_hash: input.parse()?,
61                 ..Self::default()
62             })
63         } else if lookahead.peek(kw::Eq) {
64             Ok(Self {
65                 trait_eq: input.parse()?,
66                 ..Self::default()
67             })
68         } else {
69             Ok(Self::default())
70         }
71     }
73     fn merge(self, other: Self) -> syn::Result<Self> {
74         Ok(Self {
75             async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?,
76             callback_interface: either_attribute_arg(
77                 self.callback_interface,
78                 other.callback_interface,
79             )?,
80             constructor: either_attribute_arg(self.constructor, other.constructor)?,
81             trait_debug: either_attribute_arg(self.trait_debug, other.trait_debug)?,
82             trait_display: either_attribute_arg(self.trait_display, other.trait_display)?,
83             trait_hash: either_attribute_arg(self.trait_hash, other.trait_hash)?,
84             trait_eq: either_attribute_arg(self.trait_eq, other.trait_eq)?,
85         })
86     }
89 pub(crate) enum AsyncRuntime {
90     Tokio(LitStr),
93 impl Parse for AsyncRuntime {
94     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
95         let lit: LitStr = input.parse()?;
96         match lit.value().as_str() {
97             "tokio" => Ok(Self::Tokio(lit)),
98             _ => Err(syn::Error::new_spanned(
99                 lit,
100                 "unknown async runtime, currently only `tokio` is supported",
101             )),
102         }
103     }
106 impl ToTokens for AsyncRuntime {
107     fn to_tokens(&self, tokens: &mut TokenStream) {
108         match self {
109             AsyncRuntime::Tokio(lit) => lit.to_tokens(tokens),
110         }
111     }
114 #[derive(Default)]
115 pub(super) struct ExportedImplFnAttributes {
116     pub constructor: bool,
119 impl ExportedImplFnAttributes {
120     pub fn new(attrs: &[Attribute]) -> syn::Result<Self> {
121         let mut this = Self::default();
122         for attr in attrs {
123             let segs = &attr.path().segments;
125             let fst = segs
126                 .first()
127                 .expect("attributes have at least one path segment");
128             if fst.ident != "uniffi" {
129                 continue;
130             }
131             ensure_no_path_args(fst)?;
133             if let Meta::List(_) | Meta::NameValue(_) = &attr.meta {
134                 return Err(syn::Error::new_spanned(
135                     &attr.meta,
136                     "attribute arguments are not currently recognized in this position",
137                 ));
138             }
140             if segs.len() != 2 {
141                 return Err(syn::Error::new_spanned(
142                     segs,
143                     "unsupported uniffi attribute",
144                 ));
145             }
146             let snd = &segs[1];
147             ensure_no_path_args(snd)?;
149             match snd.ident.to_string().as_str() {
150                 "constructor" => {
151                     if this.constructor {
152                         return Err(syn::Error::new_spanned(
153                             attr,
154                             "duplicate constructor attribute",
155                         ));
156                     }
157                     this.constructor = true;
158                 }
159                 _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")),
160             }
161         }
163         Ok(this)
164     }
167 fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> {
168     if matches!(seg.arguments, PathArguments::None) {
169         Ok(())
170     } else {
171         Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax"))
172     }