|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 4 | + |
| 5 | +//! General handling for the derive and udl_derive macros |
| 6 | +
|
| 7 | +use crate::util::kw; |
| 8 | +use proc_macro2::{Ident, Span, TokenStream}; |
| 9 | +use quote::{quote, ToTokens}; |
| 10 | +use syn::parse::{Parse, ParseStream}; |
| 11 | + |
| 12 | +pub enum DeriveKind { |
| 13 | + Record(kw::Record), |
| 14 | + Enum(kw::Enum), |
| 15 | + Error(kw::Error), |
| 16 | + Object(kw::Object), |
| 17 | +} |
| 18 | + |
| 19 | +impl Parse for DeriveKind { |
| 20 | + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { |
| 21 | + let lookahead = input.lookahead1(); |
| 22 | + if lookahead.peek(kw::Record) { |
| 23 | + Ok(Self::Record(input.parse()?)) |
| 24 | + } else if lookahead.peek(kw::Enum) { |
| 25 | + Ok(Self::Enum(input.parse()?)) |
| 26 | + } else if lookahead.peek(kw::Error) { |
| 27 | + Ok(Self::Error(input.parse()?)) |
| 28 | + } else if lookahead.peek(kw::Object) { |
| 29 | + Ok(Self::Object(input.parse()?)) |
| 30 | + } else { |
| 31 | + Err(lookahead.error()) |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +pub struct DeriveContext { |
| 37 | + /// Should we implement FFI traits for the local UniFfiTag only? |
| 38 | + pub local_tag: bool, |
| 39 | + /// Should we generate a metadata symbol? |
| 40 | + pub generate_metadata: bool, |
| 41 | +} |
| 42 | + |
| 43 | +/// default() is used to construct a DeriveContext for a regular `derive` invocation |
| 44 | +impl Default for DeriveContext { |
| 45 | + fn default() -> Self { |
| 46 | + Self { |
| 47 | + local_tag: false, |
| 48 | + generate_metadata: true, |
| 49 | + } |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +impl DeriveContext { |
| 54 | + /// Construct the derive context for `udl_derive` |
| 55 | + pub fn udl_derive() -> Self { |
| 56 | + Self { |
| 57 | + local_tag: true, |
| 58 | + generate_metadata: false, |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + /// Generate the impl header for a FFI trait |
| 63 | + /// |
| 64 | + /// This will output something like `impl<UT> FfiConverter<UT> for #type`. The caller is |
| 65 | + /// responsible for providing the body if the impl block. |
| 66 | + pub fn ffi_impl_header(&self, trait_name: &str, ident: &impl ToTokens) -> TokenStream { |
| 67 | + let trait_name = Ident::new(trait_name, Span::call_site()); |
| 68 | + if self.local_tag { |
| 69 | + quote! { impl ::uniffi::#trait_name<crate::UniFfiTag> for #ident } |
| 70 | + } else { |
| 71 | + quote! { impl<T> ::uniffi::#trait_name<T> for #ident } |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + /// Generate a call to `derive_ffi_traits!` that will derive all the FFI traits |
| 76 | + pub fn derive_all_ffi_traits(&self, ty: &Ident) -> TokenStream { |
| 77 | + if self.local_tag { |
| 78 | + quote! { ::uniffi::derive_ffi_traits!(local #ty); } |
| 79 | + } else { |
| 80 | + quote! { ::uniffi::derive_ffi_traits!(blanket #ty); } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + /// Generate a call to `derive_ffi_traits!` that will derive some of the FFI traits |
| 85 | + pub fn derive_ffi_traits(&self, ty: impl ToTokens, trait_names: &[&str]) -> TokenStream { |
| 86 | + let trait_idents = trait_names |
| 87 | + .iter() |
| 88 | + .map(|name| Ident::new(name, Span::call_site())); |
| 89 | + if self.local_tag { |
| 90 | + quote! { |
| 91 | + #( |
| 92 | + ::uniffi::derive_ffi_traits!(impl #trait_idents<crate::UniFfiTag> for #ty); |
| 93 | + )* |
| 94 | + } |
| 95 | + } else { |
| 96 | + quote! { |
| 97 | + #( |
| 98 | + ::uniffi::derive_ffi_traits!(impl<UT> #trait_idents<UT> for #ty); |
| 99 | + )* |
| 100 | + } |
| 101 | + } |
| 102 | + } |
| 103 | +} |
0 commit comments