Skip to content

Commit

Permalink
Combine ExportedImplFnArgs and ExportFnArgs
Browse files Browse the repository at this point in the history
These were basically the same, so using 1 struct simplifies the code.

The one difference was that ExportFnArgs allowed an async runtime to be
specified.  Now that the 2 are merged, it's possible to specify an async
runtime for constructors/methods.  If present that runtime will override
the one specified in the impl attribute.
  • Loading branch information
bendk committed Mar 27, 2024
1 parent dddcf4f commit 158704f
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 96 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

## [[UnreleasedUniFFIVersion]] (backend crates: [[UnreleasedBackendVersion]]) - (_[[ReleaseDate]]_)

### What's changed

- The async runtime can be specified for constructors/methods, this will override the runtime specified at the impl block level.

[All changes in [[UnreleasedUniFFIVersion]]](https://github.com/mozilla/uniffi-rs/compare/v0.27.0...HEAD).

## v0.27.0 (backend crates: v0.27.0) - (_2024-03-26_)
Expand Down
6 changes: 3 additions & 3 deletions fixtures/uitests/tests/ui/export_attrs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ error: uniffi::export attribute `callback_interface` is not supported here.
14 | #[uniffi::export(callback_interface)]
| ^^^^^^^^^^^^^^^^^^

error: uniffi::export attribute `with_foreign` is not supported here.
error: attribute `with_foreign` is not supported here.
--> tests/ui/export_attrs.rs:17:18
|
17 | #[uniffi::export(with_foreign)]
Expand All @@ -42,13 +42,13 @@ error: attribute arguments are not currently recognized in this position
34 | #[uniffi(flat_error)]
| ^^^^^^^^^^

error: uniffi::constructor/method attribute `foo = bar` is not supported here.
error: attribute `foo = bar` is not supported here.
--> tests/ui/export_attrs.rs:44:27
|
44 | #[uniffi::constructor(foo = bar)]
| ^^^

error: uniffi::constructor/method attribute `foo` is not supported here.
error: attribute `foo` is not supported here.
--> tests/ui/export_attrs.rs:50:22
|
50 | #[uniffi::method(foo)]
Expand Down
12 changes: 8 additions & 4 deletions uniffi_macros/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use self::{
},
};
use crate::util::{ident_to_string, mod_path};
pub use attributes::{DefaultMap, ExportFnArgs, ExportedImplFnArgs};
pub use attributes::{AsyncRuntime, DefaultMap, ExportFnArgs};
pub use callback_interface::ffi_converter_callback_interface_impl;

// TODO(jplatte): Ensure no generics, …
Expand All @@ -42,7 +42,7 @@ pub(crate) fn expand_export(

match metadata {
ExportItem::Function { sig, args } => {
gen_fn_scaffolding(sig, &args.async_runtime, udl_mode)
gen_fn_scaffolding(sig, args.async_runtime.as_ref(), udl_mode)
}
ExportItem::Impl {
items,
Expand All @@ -65,10 +65,14 @@ pub(crate) fn expand_export(
.into_iter()
.map(|item| match item {
ImplItem::Constructor(sig) => {
gen_constructor_scaffolding(sig, &args.async_runtime, udl_mode)
let async_runtime =
sig.async_runtime.clone().or(args.async_runtime.clone());
gen_constructor_scaffolding(sig, async_runtime.as_ref(), udl_mode)
}
ImplItem::Method(sig) => {
gen_method_scaffolding(sig, &args.async_runtime, udl_mode)
let async_runtime =
sig.async_runtime.clone().or(args.async_runtime.clone());
gen_method_scaffolding(sig, async_runtime.as_ref(), udl_mode)
}
})
.collect::<syn::Result<_>>()?;
Expand Down
58 changes: 7 additions & 51 deletions uniffi_macros/src/export/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ impl UniffiAttributeArgs for ExportTraitArgs {
}
}

/// Attribute arguments for function
///
/// This includes top-level functions, constructors, and methods.
#[derive(Clone, Default)]
pub struct ExportFnArgs {
pub(crate) async_runtime: Option<AsyncRuntime>,
Expand Down Expand Up @@ -110,7 +113,7 @@ impl UniffiAttributeArgs for ExportFnArgs {
} else {
Err(syn::Error::new(
input.span(),
format!("uniffi::export attribute `{input}` is not supported here."),
format!("attribute `{input}` is not supported here."),
))
}
}
Expand Down Expand Up @@ -211,7 +214,7 @@ impl UniffiAttributeArgs for ExportStructArgs {
}

#[derive(Clone)]
pub(crate) enum AsyncRuntime {
pub enum AsyncRuntime {
Tokio(LitStr),
}

Expand All @@ -236,57 +239,10 @@ 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,
pub args: ExportFnArgs,
}

impl ExportedImplFnAttributes {
Expand All @@ -304,7 +260,7 @@ impl ExportedImplFnAttributes {
ensure_no_path_args(fst)?;

let args = match &attr.meta {
Meta::List(_) => attr.parse_args::<ExportedImplFnArgs>()?,
Meta::List(_) => attr.parse_args::<ExportFnArgs>()?,
_ => Default::default(),
};
this.args = args;
Expand Down
5 changes: 2 additions & 3 deletions uniffi_macros/src/export/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use proc_macro2::{Ident, Span};
use quote::ToTokens;

use super::attributes::{
ExportFnArgs, ExportImplArgs, ExportStructArgs, ExportTraitArgs, ExportedImplFnArgs,
ExportedImplFnAttributes,
ExportFnArgs, ExportImplArgs, ExportStructArgs, ExportTraitArgs, ExportedImplFnAttributes,
};
use crate::util::extract_docstring;
use uniffi_meta::UniffiTraitDiscriminants;
Expand Down Expand Up @@ -170,7 +169,7 @@ impl ExportItem {
ImplItem::Method(FnSignature::new_trait_method(
self_ident.clone(),
tim.sig,
ExportedImplFnArgs::default(),
ExportFnArgs::default(),
i as u32,
docstring,
)?)
Expand Down
8 changes: 4 additions & 4 deletions uniffi_macros/src/export/scaffolding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::fnsig::{FnKind, FnSignature};

pub(super) fn gen_fn_scaffolding(
sig: FnSignature,
ar: &Option<AsyncRuntime>,
ar: Option<&AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
if sig.receiver.is_some() {
Expand Down Expand Up @@ -41,7 +41,7 @@ pub(super) fn gen_fn_scaffolding(

pub(super) fn gen_constructor_scaffolding(
sig: FnSignature,
ar: &Option<AsyncRuntime>,
ar: Option<&AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
if sig.receiver.is_some() {
Expand All @@ -63,7 +63,7 @@ pub(super) fn gen_constructor_scaffolding(

pub(super) fn gen_method_scaffolding(
sig: FnSignature,
ar: &Option<AsyncRuntime>,
ar: Option<&AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
let scaffolding_func = if sig.receiver.is_none() {
Expand Down Expand Up @@ -210,7 +210,7 @@ impl ScaffoldingBits {
/// `rust_fn` is the Rust function to call.
pub(super) fn gen_ffi_function(
sig: &FnSignature,
ar: &Option<AsyncRuntime>,
ar: Option<&AsyncRuntime>,
udl_mode: bool,
) -> syn::Result<TokenStream> {
let ScaffoldingBits {
Expand Down
2 changes: 1 addition & 1 deletion uniffi_macros/src/export/trait_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub(super) fn gen_trait_scaffolding(
let impl_tokens: TokenStream = items
.into_iter()
.map(|item| match item {
ImplItem::Method(sig) => gen_method_scaffolding(sig, &None, udl_mode),
ImplItem::Method(sig) => gen_method_scaffolding(sig, None, udl_mode),
_ => unreachable!("traits have no constructors"),
})
.collect::<syn::Result<_>>()?;
Expand Down
8 changes: 4 additions & 4 deletions uniffi_macros/src/export/utrait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use quote::quote;
use syn::ext::IdentExt;

use super::gen_ffi_function;
use crate::export::ExportedImplFnArgs;
use crate::export::ExportFnArgs;
use crate::fnsig::FnSignature;
use crate::util::extract_docstring;
use uniffi_meta::UniffiTraitDiscriminants;
Expand Down Expand Up @@ -165,17 +165,17 @@ fn process_uniffi_trait_method(
&FnSignature::new_method(
self_ident.clone(),
item.sig.clone(),
ExportedImplFnArgs::default(),
ExportFnArgs::default(),
docstring.clone(),
)?,
&None,
None,
udl_mode,
)?;
// metadata for the method, which will be packed inside metadata for the trait.
let method_meta = FnSignature::new_method(
self_ident.clone(),
item.sig,
ExportedImplFnArgs::default(),
ExportFnArgs::default(),
docstring,
)?
.metadata_expr()?;
Expand Down
49 changes: 23 additions & 26 deletions uniffi_macros/src/fnsig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use crate::{
default::{default_value_metadata_calls, DefaultValue},
export::{DefaultMap, ExportFnArgs, ExportedImplFnArgs},
export::{AsyncRuntime, DefaultMap, ExportFnArgs},
util::{create_metadata_items, ident_to_string, mod_path, try_metadata_value_from_usize},
};
use proc_macro2::{Span, TokenStream};
Expand All @@ -20,6 +20,7 @@ pub(crate) struct FnSignature {
// The foreign name for this function, usually == ident.
pub name: String,
pub is_async: bool,
pub async_runtime: Option<AsyncRuntime>,
pub receiver: Option<ReceiverArg>,
pub args: Vec<NamedArg>,
pub return_ty: TokenStream,
Expand All @@ -36,60 +37,46 @@ impl FnSignature {
args: ExportFnArgs,
docstring: String,
) -> syn::Result<Self> {
Self::new(FnKind::Function, sig, args.name, args.defaults, docstring)
Self::new(FnKind::Function, sig, args, docstring)
}

pub(crate) fn new_method(
self_ident: Ident,
sig: syn::Signature,
args: ExportedImplFnArgs,
args: ExportFnArgs,
docstring: String,
) -> syn::Result<Self> {
Self::new(
FnKind::Method { self_ident },
sig,
args.name,
args.defaults,
docstring,
)
Self::new(FnKind::Method { self_ident }, sig, args, docstring)
}

pub(crate) fn new_constructor(
self_ident: Ident,
sig: syn::Signature,
args: ExportedImplFnArgs,
args: ExportFnArgs,
docstring: String,
) -> syn::Result<Self> {
Self::new(
FnKind::Constructor { self_ident },
sig,
args.name,
args.defaults,
docstring,
)
Self::new(FnKind::Constructor { self_ident }, sig, args, docstring)
}

pub(crate) fn new_trait_method(
self_ident: Ident,
sig: syn::Signature,
args: ExportedImplFnArgs,
args: ExportFnArgs,
index: u32,
docstring: String,
) -> syn::Result<Self> {
Self::new(
FnKind::TraitMethod { self_ident, index },
sig,
args.name,
args.defaults,
args,
docstring,
)
}

pub(crate) fn new(
kind: FnKind,
sig: syn::Signature,
name: Option<String>,
mut defaults: DefaultMap,
mut export_fn_args: ExportFnArgs,
docstring: String,
) -> syn::Result<Self> {
let span = sig.span();
Expand All @@ -104,7 +91,7 @@ impl FnSignature {
let mut input_iter = sig
.inputs
.into_iter()
.map(|a| Arg::new(a, &mut defaults))
.map(|a| Arg::new(a, &mut export_fn_args.defaults))
.peekable();

let receiver = input_iter
Expand All @@ -127,20 +114,30 @@ impl FnSignature {
})
.collect::<syn::Result<Vec<_>>>()?;

if let Some(ident) = defaults.idents().first() {
if let Some(ident) = export_fn_args.defaults.idents().first() {
return Err(syn::Error::new(
ident.span(),
format!("Unknown default argument: {}", ident),
));
}

if !is_async && export_fn_args.async_runtime.is_some() {
return Err(syn::Error::new(
export_fn_args.async_runtime.span(),
"Function not async".to_string(),
));
}

Ok(Self {
kind,
span,
mod_path: mod_path()?,
name: name.unwrap_or_else(|| ident_to_string(&ident)),
name: export_fn_args
.name
.unwrap_or_else(|| ident_to_string(&ident)),
ident,
is_async,
async_runtime: export_fn_args.async_runtime,
receiver,
args,
return_ty: output,
Expand Down

0 comments on commit 158704f

Please sign in to comment.