diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /third_party/rust/uniffi_macros/src/export/attributes.rs | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/uniffi_macros/src/export/attributes.rs | 306 |
1 files changed, 268 insertions, 38 deletions
diff --git a/third_party/rust/uniffi_macros/src/export/attributes.rs b/third_party/rust/uniffi_macros/src/export/attributes.rs index c3edcd5920..be7e8902e4 100644 --- a/third_party/rust/uniffi_macros/src/export/attributes.rs +++ b/third_party/rust/uniffi_macros/src/export/attributes.rs @@ -1,31 +1,33 @@ -use crate::util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs}; +use std::collections::{HashMap, HashSet}; + +use crate::{ + default::DefaultValue, + util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs}, +}; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{ + parenthesized, parse::{Parse, ParseStream}, - Attribute, LitStr, Meta, PathArguments, PathSegment, Token, + Attribute, Ident, LitStr, Meta, PathArguments, PathSegment, Token, }; +use uniffi_meta::UniffiTraitDiscriminants; #[derive(Default)] -pub struct ExportAttributeArguments { +pub struct ExportTraitArgs { pub(crate) async_runtime: Option<AsyncRuntime>, pub(crate) callback_interface: Option<kw::callback_interface>, - pub(crate) constructor: Option<kw::constructor>, - // tried to make this a vec but that got messy quickly... - pub(crate) trait_debug: Option<kw::Debug>, - pub(crate) trait_display: Option<kw::Display>, - pub(crate) trait_hash: Option<kw::Hash>, - pub(crate) trait_eq: Option<kw::Eq>, + pub(crate) with_foreign: Option<kw::with_foreign>, } -impl Parse for ExportAttributeArguments { +impl Parse for ExportTraitArgs { fn parse(input: ParseStream<'_>) -> syn::Result<Self> { parse_comma_separated(input) } } -impl UniffiAttributeArgs for ExportAttributeArguments { +impl UniffiAttributeArgs for ExportTraitArgs { fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { let lookahead = input.lookahead1(); if lookahead.peek(kw::async_runtime) { @@ -40,52 +42,175 @@ impl UniffiAttributeArgs for ExportAttributeArguments { callback_interface: input.parse()?, ..Self::default() }) - } else if lookahead.peek(kw::constructor) { + } else if lookahead.peek(kw::with_foreign) { Ok(Self { - constructor: input.parse()?, + with_foreign: input.parse()?, ..Self::default() }) - } else if lookahead.peek(kw::Debug) { + } else { + Ok(Self::default()) + } + } + + fn merge(self, other: Self) -> syn::Result<Self> { + let merged = Self { + async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, + callback_interface: either_attribute_arg( + self.callback_interface, + other.callback_interface, + )?, + with_foreign: either_attribute_arg(self.with_foreign, other.with_foreign)?, + }; + if merged.callback_interface.is_some() && merged.with_foreign.is_some() { + return Err(syn::Error::new( + merged.callback_interface.unwrap().span, + "`callback_interface` and `with_foreign` are mutually exclusive", + )); + } + Ok(merged) + } +} + +#[derive(Clone, Default)] +pub struct ExportFnArgs { + pub(crate) async_runtime: Option<AsyncRuntime>, + pub(crate) name: Option<String>, + pub(crate) defaults: DefaultMap, +} + +impl Parse for ExportFnArgs { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + parse_comma_separated(input) + } +} + +impl UniffiAttributeArgs for ExportFnArgs { + fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::async_runtime) { + let _: kw::async_runtime = input.parse()?; + let _: Token![=] = input.parse()?; Ok(Self { - trait_debug: input.parse()?, + async_runtime: Some(input.parse()?), ..Self::default() }) - } else if lookahead.peek(kw::Display) { + } else if lookahead.peek(kw::name) { + let _: kw::name = input.parse()?; + let _: Token![=] = input.parse()?; + let name = Some(input.parse::<LitStr>()?.value()); Ok(Self { - trait_display: input.parse()?, + name, ..Self::default() }) - } else if lookahead.peek(kw::Hash) { + } else if lookahead.peek(kw::default) { Ok(Self { - trait_hash: input.parse()?, + defaults: DefaultMap::parse(input)?, ..Self::default() }) - } else if lookahead.peek(kw::Eq) { + } else { + Err(syn::Error::new( + input.span(), + format!("uniffi::export attribute `{input}` is not supported here."), + )) + } + } + + fn merge(self, other: Self) -> syn::Result<Self> { + Ok(Self { + async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, + name: either_attribute_arg(self.name, other.name)?, + defaults: self.defaults.merge(other.defaults), + }) + } +} + +#[derive(Default)] +pub struct ExportImplArgs { + pub(crate) async_runtime: Option<AsyncRuntime>, +} + +impl Parse for ExportImplArgs { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + parse_comma_separated(input) + } +} + +impl UniffiAttributeArgs for ExportImplArgs { + fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::async_runtime) { + let _: kw::async_runtime = input.parse()?; + let _: Token![=] = input.parse()?; Ok(Self { - trait_eq: input.parse()?, - ..Self::default() + async_runtime: Some(input.parse()?), }) } else { - Ok(Self::default()) + Err(syn::Error::new( + input.span(), + format!("uniffi::export attribute `{input}` is not supported here."), + )) } } fn merge(self, other: Self) -> syn::Result<Self> { Ok(Self { async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, - callback_interface: either_attribute_arg( - self.callback_interface, - other.callback_interface, - )?, - constructor: either_attribute_arg(self.constructor, other.constructor)?, - trait_debug: either_attribute_arg(self.trait_debug, other.trait_debug)?, - trait_display: either_attribute_arg(self.trait_display, other.trait_display)?, - trait_hash: either_attribute_arg(self.trait_hash, other.trait_hash)?, - trait_eq: either_attribute_arg(self.trait_eq, other.trait_eq)?, }) } } +#[derive(Default)] +pub struct ExportStructArgs { + pub(crate) traits: HashSet<UniffiTraitDiscriminants>, +} + +impl Parse for ExportStructArgs { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + parse_comma_separated(input) + } +} + +impl UniffiAttributeArgs for ExportStructArgs { + fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::Debug) { + input.parse::<Option<kw::Debug>>()?; + Ok(Self { + traits: HashSet::from([UniffiTraitDiscriminants::Debug]), + }) + } else if lookahead.peek(kw::Display) { + input.parse::<Option<kw::Display>>()?; + Ok(Self { + traits: HashSet::from([UniffiTraitDiscriminants::Display]), + }) + } else if lookahead.peek(kw::Hash) { + input.parse::<Option<kw::Hash>>()?; + Ok(Self { + traits: HashSet::from([UniffiTraitDiscriminants::Hash]), + }) + } else if lookahead.peek(kw::Eq) { + input.parse::<Option<kw::Eq>>()?; + Ok(Self { + traits: HashSet::from([UniffiTraitDiscriminants::Eq]), + }) + } else { + Err(syn::Error::new( + input.span(), + format!( + "uniffi::export struct attributes must be builtin trait names; `{input}` is invalid" + ), + )) + } + } + + fn merge(self, other: Self) -> syn::Result<Self> { + let mut traits = self.traits; + traits.extend(other.traits); + Ok(Self { traits }) + } +} + +#[derive(Clone)] pub(crate) enum AsyncRuntime { Tokio(LitStr), } @@ -111,9 +236,57 @@ impl ToTokens for AsyncRuntime { } } +/// Arguments for function inside an impl block +/// +/// This stores the parsed arguments for `uniffi::constructor` and `uniffi::method` +#[derive(Clone, Default)] +pub struct ExportedImplFnArgs { + pub(crate) name: Option<String>, + pub(crate) defaults: DefaultMap, +} + +impl Parse for ExportedImplFnArgs { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + parse_comma_separated(input) + } +} + +impl UniffiAttributeArgs for ExportedImplFnArgs { + fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::name) { + let _: kw::name = input.parse()?; + let _: Token![=] = input.parse()?; + let name = Some(input.parse::<LitStr>()?.value()); + Ok(Self { + name, + ..Self::default() + }) + } else if lookahead.peek(kw::default) { + Ok(Self { + defaults: DefaultMap::parse(input)?, + ..Self::default() + }) + } else { + Err(syn::Error::new( + input.span(), + format!("uniffi::constructor/method attribute `{input}` is not supported here."), + )) + } + } + + fn merge(self, other: Self) -> syn::Result<Self> { + Ok(Self { + name: either_attribute_arg(self.name, other.name)?, + defaults: self.defaults.merge(other.defaults), + }) + } +} + #[derive(Default)] pub(super) struct ExportedImplFnAttributes { pub constructor: bool, + pub args: ExportedImplFnArgs, } impl ExportedImplFnAttributes { @@ -130,12 +303,11 @@ impl ExportedImplFnAttributes { } ensure_no_path_args(fst)?; - if let Meta::List(_) | Meta::NameValue(_) = &attr.meta { - return Err(syn::Error::new_spanned( - &attr.meta, - "attribute arguments are not currently recognized in this position", - )); - } + let args = match &attr.meta { + Meta::List(_) => attr.parse_args::<ExportedImplFnArgs>()?, + _ => Default::default(), + }; + this.args = args; if segs.len() != 2 { return Err(syn::Error::new_spanned( @@ -156,6 +328,14 @@ impl ExportedImplFnAttributes { } this.constructor = true; } + "method" => { + if this.constructor { + return Err(syn::Error::new_spanned( + attr, + "confused constructor/method attributes", + )); + } + } _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")), } } @@ -171,3 +351,53 @@ fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> { Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax")) } } + +/// Maps arguments to defaults for functions +#[derive(Clone, Default)] +pub struct DefaultMap { + map: HashMap<Ident, DefaultValue>, +} + +impl DefaultMap { + pub fn merge(self, other: Self) -> Self { + let mut map = self.map; + map.extend(other.map); + Self { map } + } + + pub fn remove(&mut self, ident: &Ident) -> Option<DefaultValue> { + self.map.remove(ident) + } + + pub fn idents(&self) -> Vec<&Ident> { + self.map.keys().collect() + } +} + +impl Parse for DefaultMap { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let _: kw::default = input.parse()?; + let content; + let _ = parenthesized!(content in input); + let pairs = content.parse_terminated(DefaultPair::parse, Token![,])?; + Ok(Self { + map: pairs.into_iter().map(|p| (p.name, p.value)).collect(), + }) + } +} + +pub struct DefaultPair { + pub name: Ident, + pub eq_token: Token![=], + pub value: DefaultValue, +} + +impl Parse for DefaultPair { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + Ok(Self { + name: input.parse()?, + eq_token: input.parse()?, + value: input.parse()?, + }) + } +} |