1 use crate::util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs};
3 use proc_macro2::TokenStream;
6 parse::{Parse, ParseStream},
7 Attribute, LitStr, Meta, PathArguments, PathSegment, Token,
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)
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()?;
35 async_runtime: Some(input.parse()?),
38 } else if lookahead.peek(kw::callback_interface) {
40 callback_interface: input.parse()?,
43 } else if lookahead.peek(kw::constructor) {
45 constructor: input.parse()?,
48 } else if lookahead.peek(kw::Debug) {
50 trait_debug: input.parse()?,
53 } else if lookahead.peek(kw::Display) {
55 trait_display: input.parse()?,
58 } else if lookahead.peek(kw::Hash) {
60 trait_hash: input.parse()?,
63 } else if lookahead.peek(kw::Eq) {
65 trait_eq: input.parse()?,
73 fn merge(self, other: Self) -> syn::Result<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,
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)?,
89 pub(crate) enum AsyncRuntime {
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(
100 "unknown async runtime, currently only `tokio` is supported",
106 impl ToTokens for AsyncRuntime {
107 fn to_tokens(&self, tokens: &mut TokenStream) {
109 AsyncRuntime::Tokio(lit) => lit.to_tokens(tokens),
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();
123 let segs = &attr.path().segments;
127 .expect("attributes have at least one path segment");
128 if fst.ident != "uniffi" {
131 ensure_no_path_args(fst)?;
133 if let Meta::List(_) | Meta::NameValue(_) = &attr.meta {
134 return Err(syn::Error::new_spanned(
136 "attribute arguments are not currently recognized in this position",
141 return Err(syn::Error::new_spanned(
143 "unsupported uniffi attribute",
147 ensure_no_path_args(snd)?;
149 match snd.ident.to_string().as_str() {
151 if this.constructor {
152 return Err(syn::Error::new_spanned(
154 "duplicate constructor attribute",
157 this.constructor = true;
159 _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")),
167 fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> {
168 if matches!(seg.arguments, PathArguments::None) {
171 Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax"))