Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_bindgen / src / interface / function.rs
blob2d18288c1c6febccba014fe6ac5cce80688276b0
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/. */
5 //! # Function definitions for a `ComponentInterface`.
6 //!
7 //! This module converts function definitions from UDL into structures that
8 //! can be added to a `ComponentInterface`. A declaration in the UDL like this:
9 //!
10 //! ```
11 //! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##"
12 //! namespace example {
13 //!     string hello();
14 //! };
15 //! # "##, "crate_name")?;
16 //! # Ok::<(), anyhow::Error>(())
17 //! ```
18 //!
19 //! Will result in a [`Function`] member being added to the resulting [`crate::ComponentInterface`]:
20 //!
21 //! ```
22 //! # use uniffi_bindgen::interface::Type;
23 //! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##"
24 //! # namespace example {
25 //! #     string hello();
26 //! # };
27 //! # "##, "crate_name")?;
28 //! let func = ci.get_function_definition("hello").unwrap();
29 //! assert_eq!(func.name(), "hello");
30 //! assert!(matches!(func.return_type(), Some(Type::String)));
31 //! assert_eq!(func.arguments().len(), 0);
32 //! # Ok::<(), anyhow::Error>(())
33 //! ```
35 use anyhow::Result;
37 use super::ffi::{FfiArgument, FfiFunction, FfiType};
38 use super::{AsType, ComponentInterface, Literal, ObjectImpl, Type, TypeIterator};
39 use uniffi_meta::Checksum;
41 /// Represents a standalone function.
42 ///
43 /// Each `Function` corresponds to a standalone function in the rust module,
44 /// and has a corresponding standalone function in the foreign language bindings.
45 ///
46 /// In the FFI, this will be a standalone function with appropriately lowered types.
47 #[derive(Debug, Clone, Checksum)]
48 pub struct Function {
49     pub(super) name: String,
50     pub(super) module_path: String,
51     pub(super) is_async: bool,
52     pub(super) arguments: Vec<Argument>,
53     pub(super) return_type: Option<Type>,
54     // We don't include the FFIFunc in the hash calculation, because:
55     //  - it is entirely determined by the other fields,
56     //    so excluding it is safe.
57     //  - its `name` property includes a checksum derived from the very
58     //    hash value we're trying to calculate here, so excluding it
59     //    avoids a weird circular dependency in the calculation.
60     #[checksum_ignore]
61     pub(super) ffi_func: FfiFunction,
62     pub(super) throws: Option<Type>,
63     pub(super) checksum_fn_name: String,
64     // Force a checksum value, or we'll fallback to the trait.
65     #[checksum_ignore]
66     pub(super) checksum: Option<u16>,
69 impl Function {
70     pub fn name(&self) -> &str {
71         &self.name
72     }
74     pub fn is_async(&self) -> bool {
75         self.is_async
76     }
78     pub fn arguments(&self) -> Vec<&Argument> {
79         self.arguments.iter().collect()
80     }
82     pub fn full_arguments(&self) -> Vec<Argument> {
83         self.arguments.to_vec()
84     }
86     pub fn return_type(&self) -> Option<&Type> {
87         self.return_type.as_ref()
88     }
90     pub fn ffi_func(&self) -> &FfiFunction {
91         &self.ffi_func
92     }
94     pub fn checksum_fn_name(&self) -> &str {
95         &self.checksum_fn_name
96     }
98     pub fn checksum(&self) -> u16 {
99         self.checksum.unwrap_or_else(|| uniffi_meta::checksum(self))
100     }
102     pub fn throws(&self) -> bool {
103         self.throws.is_some()
104     }
106     pub fn throws_name(&self) -> Option<&str> {
107         super::throws_name(&self.throws)
108     }
110     pub fn throws_type(&self) -> Option<&Type> {
111         self.throws.as_ref()
112     }
114     pub fn derive_ffi_func(&mut self) -> Result<()> {
115         assert!(!self.ffi_func.name.is_empty());
116         self.ffi_func.init(
117             self.return_type.as_ref().map(Into::into),
118             self.arguments.iter().map(Into::into),
119         );
120         Ok(())
121     }
123     pub fn iter_types(&self) -> TypeIterator<'_> {
124         Box::new(
125             self.arguments
126                 .iter()
127                 .flat_map(Argument::iter_types)
128                 .chain(self.return_type.iter().flat_map(Type::iter_types)),
129         )
130     }
133 impl From<uniffi_meta::FnParamMetadata> for Argument {
134     fn from(meta: uniffi_meta::FnParamMetadata) -> Self {
135         Argument {
136             name: meta.name,
137             type_: meta.ty,
138             by_ref: meta.by_ref,
139             optional: meta.optional,
140             default: meta.default,
141         }
142     }
145 impl From<uniffi_meta::FnMetadata> for Function {
146     fn from(meta: uniffi_meta::FnMetadata) -> Self {
147         let ffi_name = meta.ffi_symbol_name();
148         let checksum_fn_name = meta.checksum_symbol_name();
149         let is_async = meta.is_async;
150         let return_type = meta.return_type.map(Into::into);
151         let arguments = meta.inputs.into_iter().map(Into::into).collect();
153         let ffi_func = FfiFunction {
154             name: ffi_name,
155             is_async,
156             ..FfiFunction::default()
157         };
159         Self {
160             name: meta.name,
161             module_path: meta.module_path,
162             is_async,
163             arguments,
164             return_type,
165             ffi_func,
166             throws: meta.throws,
167             checksum_fn_name,
168             checksum: meta.checksum,
169         }
170     }
173 /// Represents an argument to a function/constructor/method call.
175 /// Each argument has a name and a type, along with some optional metadata.
176 #[derive(Debug, Clone, Checksum)]
177 pub struct Argument {
178     pub(super) name: String,
179     pub(super) type_: Type,
180     pub(super) by_ref: bool,
181     pub(super) optional: bool,
182     pub(super) default: Option<Literal>,
185 impl Argument {
186     pub fn name(&self) -> &str {
187         &self.name
188     }
190     pub fn by_ref(&self) -> bool {
191         self.by_ref
192     }
194     pub fn is_trait_ref(&self) -> bool {
195         matches!(&self.type_, Type::Object { imp, .. } if *imp == ObjectImpl::Trait)
196     }
198     pub fn default_value(&self) -> Option<&Literal> {
199         self.default.as_ref()
200     }
202     pub fn iter_types(&self) -> TypeIterator<'_> {
203         self.type_.iter_types()
204     }
207 impl AsType for Argument {
208     fn as_type(&self) -> Type {
209         self.type_.clone()
210     }
213 impl From<&Argument> for FfiArgument {
214     fn from(a: &Argument) -> FfiArgument {
215         FfiArgument {
216             name: a.name.clone(),
217             type_: (&a.type_).into(),
218         }
219     }
222 /// Combines the return and throws type of a function/method
223 #[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
224 pub struct ResultType {
225     pub return_type: Option<Type>,
226     pub throws_type: Option<Type>,
229 impl ResultType {
230     /// Get the `T` parameters for the `FutureCallback<T>` for this ResultType
231     pub fn future_callback_param(&self) -> FfiType {
232         match &self.return_type {
233             Some(t) => t.into(),
234             None => FfiType::UInt8,
235         }
236     }
239 /// Implemented by function-like types (Function, Method, Constructor)
240 pub trait Callable {
241     fn arguments(&self) -> Vec<&Argument>;
242     fn return_type(&self) -> Option<Type>;
243     fn throws_type(&self) -> Option<Type>;
244     fn is_async(&self) -> bool;
245     fn result_type(&self) -> ResultType {
246         ResultType {
247             return_type: self.return_type(),
248             throws_type: self.throws_type(),
249         }
250     }
252     // Quick way to get the rust future scaffolding function that corresponds to our return type.
254     fn ffi_rust_future_poll(&self, ci: &ComponentInterface) -> String {
255         ci.ffi_rust_future_poll(self.return_type().map(Into::into))
256             .name()
257             .to_owned()
258     }
260     fn ffi_rust_future_cancel(&self, ci: &ComponentInterface) -> String {
261         ci.ffi_rust_future_cancel(self.return_type().map(Into::into))
262             .name()
263             .to_owned()
264     }
266     fn ffi_rust_future_complete(&self, ci: &ComponentInterface) -> String {
267         ci.ffi_rust_future_complete(self.return_type().map(Into::into))
268             .name()
269             .to_owned()
270     }
272     fn ffi_rust_future_free(&self, ci: &ComponentInterface) -> String {
273         ci.ffi_rust_future_free(self.return_type().map(Into::into))
274             .name()
275             .to_owned()
276     }
279 impl Callable for Function {
280     fn arguments(&self) -> Vec<&Argument> {
281         self.arguments()
282     }
284     fn return_type(&self) -> Option<Type> {
285         self.return_type().cloned()
286     }
288     fn throws_type(&self) -> Option<Type> {
289         self.throws_type().cloned()
290     }
292     fn is_async(&self) -> bool {
293         self.is_async
294     }
297 // Needed because Askama likes to add extra refs to variables
298 impl<T: Callable> Callable for &T {
299     fn arguments(&self) -> Vec<&Argument> {
300         (*self).arguments()
301     }
303     fn return_type(&self) -> Option<Type> {
304         (*self).return_type()
305     }
307     fn throws_type(&self) -> Option<Type> {
308         (*self).throws_type()
309     }
311     fn is_async(&self) -> bool {
312         (*self).is_async()
313     }
316 #[cfg(test)]
317 mod test {
318     use super::super::ComponentInterface;
319     use super::*;
321     #[test]
322     fn test_minimal_and_rich_function() -> Result<()> {
323         let ci = ComponentInterface::from_webidl(
324             r#"
325             namespace test {
326                 void minimal();
327                 [Throws=TestError]
328                 sequence<string?> rich(u32 arg1, TestDict arg2);
329             };
330             [Error]
331             enum TestError { "err" };
332             dictionary TestDict {
333                 u32 field;
334             };
335         "#,
336             "crate_name",
337         )?;
339         let func1 = ci.get_function_definition("minimal").unwrap();
340         assert_eq!(func1.name(), "minimal");
341         assert!(func1.return_type().is_none());
342         assert!(func1.throws_type().is_none());
343         assert_eq!(func1.arguments().len(), 0);
345         let func2 = ci.get_function_definition("rich").unwrap();
346         assert_eq!(func2.name(), "rich");
347         assert_eq!(
348             func2.return_type().unwrap(),
349             &Type::Sequence {
350                 inner_type: Box::new(Type::Optional {
351                     inner_type: Box::new(Type::String)
352                 })
353             }
354         );
355         assert!(
356             matches!(func2.throws_type(), Some(Type::Enum { name, .. }) if name == "TestError" && ci.is_name_used_as_error(name))
357         );
358         assert_eq!(func2.arguments().len(), 2);
359         assert_eq!(func2.arguments()[0].name(), "arg1");
360         assert_eq!(func2.arguments()[0].as_type(), Type::UInt32);
361         assert_eq!(func2.arguments()[1].name(), "arg2");
362         assert!(
363             matches!(func2.arguments()[1].as_type(), Type::Record { name, .. } if name == "TestDict")
364         );
365         Ok(())
366     }