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 use proc_macro2::{Ident, TokenStream};
6 use quote::quote;
7 use syn::ext::IdentExt;
8
9 use super::gen_ffi_function;
10 use crate::export::ExportedImplFnArgs;
11 use crate::fnsig::FnSignature;
12 use crate::util::extract_docstring;
13 use uniffi_meta::UniffiTraitDiscriminants;
14
expand_uniffi_trait_export( self_ident: Ident, uniffi_traits: Vec<UniffiTraitDiscriminants>, ) -> syn::Result<TokenStream>15 pub(crate) fn expand_uniffi_trait_export(
16 self_ident: Ident,
17 uniffi_traits: Vec<UniffiTraitDiscriminants>,
18 ) -> syn::Result<TokenStream> {
19 let udl_mode = false;
20 let mut impl_items = Vec::new();
21 let mut global_items = Vec::new();
22 for trait_id in uniffi_traits {
23 match trait_id {
24 UniffiTraitDiscriminants::Debug => {
25 let method = quote! {
26 fn uniffi_trait_debug(&self) -> String {
27 ::uniffi::deps::static_assertions::assert_impl_all!(#self_ident: ::std::fmt::Debug);
28 format!("{:?}", self)
29 }
30 };
31 let (ffi_func, method_meta) =
32 process_uniffi_trait_method(&method, &self_ident, udl_mode)?;
33 // metadata for the trait - which includes metadata for the method.
34 let discr = UniffiTraitDiscriminants::Debug as u8;
35 let trait_meta = crate::util::create_metadata_items(
36 "uniffi_trait",
37 &format!("{}_Debug", self_ident.unraw()),
38 quote! {
39 ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::UNIFFI_TRAIT)
40 .concat_value(#discr)
41 .concat(#method_meta)
42 },
43 None,
44 );
45 impl_items.push(method);
46 global_items.push(ffi_func);
47 global_items.push(trait_meta);
48 }
49 UniffiTraitDiscriminants::Display => {
50 let method = quote! {
51 fn uniffi_trait_display(&self) -> String {
52 ::uniffi::deps::static_assertions::assert_impl_all!(#self_ident: ::std::fmt::Display);
53 format!("{}", self)
54 }
55 };
56 let (ffi_func, method_meta) =
57 process_uniffi_trait_method(&method, &self_ident, udl_mode)?;
58 // metadata for the trait - which includes metadata for the method.
59 let discr = UniffiTraitDiscriminants::Display as u8;
60 let trait_meta = crate::util::create_metadata_items(
61 "uniffi_trait",
62 &format!("{}_Display", self_ident.unraw()),
63 quote! {
64 ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::UNIFFI_TRAIT)
65 .concat_value(#discr)
66 .concat(#method_meta)
67 },
68 None,
69 );
70 impl_items.push(method);
71 global_items.push(ffi_func);
72 global_items.push(trait_meta);
73 }
74 UniffiTraitDiscriminants::Hash => {
75 let method = quote! {
76 fn uniffi_trait_hash(&self) -> u64 {
77 use ::std::hash::{Hash, Hasher};
78 ::uniffi::deps::static_assertions::assert_impl_all!(#self_ident: Hash);
79 let mut s = ::std::collections::hash_map::DefaultHasher::new();
80 Hash::hash(self, &mut s);
81 s.finish()
82 }
83 };
84 let (ffi_func, method_meta) =
85 process_uniffi_trait_method(&method, &self_ident, udl_mode)?;
86 // metadata for the trait - which includes metadata for the hash method.
87 let discr = UniffiTraitDiscriminants::Hash as u8;
88 let trait_meta = crate::util::create_metadata_items(
89 "uniffi_trait",
90 &format!("{}_Hash", self_ident.unraw()),
91 quote! {
92 ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::UNIFFI_TRAIT)
93 .concat_value(#discr)
94 .concat(#method_meta)
95 },
96 None,
97 );
98 impl_items.push(method);
99 global_items.push(ffi_func);
100 global_items.push(trait_meta);
101 }
102 UniffiTraitDiscriminants::Eq => {
103 let method_eq = quote! {
104 fn uniffi_trait_eq_eq(&self, other: &#self_ident) -> bool {
105 use ::std::cmp::PartialEq;
106 uniffi::deps::static_assertions::assert_impl_all!(#self_ident: PartialEq); // This object has a trait method which requires `PartialEq` be implemented.
107 PartialEq::eq(self, other)
108 }
109 };
110 let method_ne = quote! {
111 fn uniffi_trait_eq_ne(&self, other: &#self_ident) -> bool {
112 use ::std::cmp::PartialEq;
113 uniffi::deps::static_assertions::assert_impl_all!(#self_ident: PartialEq); // This object has a trait method which requires `PartialEq` be implemented.
114 PartialEq::ne(self, other)
115 }
116 };
117 let (ffi_func_eq, method_meta_eq) =
118 process_uniffi_trait_method(&method_eq, &self_ident, udl_mode)?;
119 let (ffi_func_ne, method_meta_ne) =
120 process_uniffi_trait_method(&method_ne, &self_ident, udl_mode)?;
121 // metadata for the trait itself.
122 let discr = UniffiTraitDiscriminants::Eq as u8;
123 let trait_meta = crate::util::create_metadata_items(
124 "uniffi_trait",
125 &format!("{}_Eq", self_ident.unraw()),
126 quote! {
127 ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::UNIFFI_TRAIT)
128 .concat_value(#discr)
129 .concat(#method_meta_eq)
130 .concat(#method_meta_ne)
131 },
132 None,
133 );
134 impl_items.push(method_eq);
135 impl_items.push(method_ne);
136 global_items.push(ffi_func_eq);
137 global_items.push(ffi_func_ne);
138 global_items.push(trait_meta);
139 }
140 }
141 }
142 Ok(quote! {
143 #[doc(hidden)]
144 impl #self_ident {
145 #(#impl_items)*
146 }
147 #(#global_items)*
148 })
149 }
150
process_uniffi_trait_method( method: &TokenStream, self_ident: &Ident, udl_mode: bool, ) -> syn::Result<(TokenStream, TokenStream)>151 fn process_uniffi_trait_method(
152 method: &TokenStream,
153 self_ident: &Ident,
154 udl_mode: bool,
155 ) -> syn::Result<(TokenStream, TokenStream)> {
156 let item = syn::parse(method.clone().into())?;
157
158 let syn::Item::Fn(item) = item else {
159 unreachable!()
160 };
161
162 let docstring = extract_docstring(&item.attrs)?;
163
164 let ffi_func = gen_ffi_function(
165 &FnSignature::new_method(
166 self_ident.clone(),
167 item.sig.clone(),
168 ExportedImplFnArgs::default(),
169 docstring.clone(),
170 )?,
171 &None,
172 udl_mode,
173 )?;
174 // metadata for the method, which will be packed inside metadata for the trait.
175 let method_meta = FnSignature::new_method(
176 self_ident.clone(),
177 item.sig,
178 ExportedImplFnArgs::default(),
179 docstring,
180 )?
181 .metadata_expr()?;
182 Ok((ffi_func, method_meta))
183 }
184