From 100c16c96c79ee3db1e626dc8c2537e44b449c22 Mon Sep 17 00:00:00 2001 From: Kristupas Antanavicius Date: Fri, 10 Mar 2023 17:50:12 +0200 Subject: [PATCH 1/2] Add "return_type()" to Constructor This makes Constructor more nominal with Function, i.e. the constructor can be used as a function in macros: ``` {% macro(func) %} {{ func.return_type() }} {% endmacro %} {% call macro(constructor) %} ``` This is very useful for generating Go bindings, because in Go errors are handled via multiple return values, instead of exceptions. That means that codegen for function return signatures get quite complicated, and being able to re-use the same code for constructors as for regular functions makes it much easier to generate code. --- uniffi_bindgen/src/interface/object.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/uniffi_bindgen/src/interface/object.rs b/uniffi_bindgen/src/interface/object.rs index 8e62bd63b3..2e3270b44b 100644 --- a/uniffi_bindgen/src/interface/object.rs +++ b/uniffi_bindgen/src/interface/object.rs @@ -248,6 +248,7 @@ pub struct Constructor { // avoids a weird circular dependency in the calculation. #[checksum_ignore] pub(super) ffi_func: FfiFunction, + pub(super) return_type: Option, pub(super) attributes: ConstructorAttributes, } @@ -268,6 +269,10 @@ impl Constructor { &self.ffi_func } + pub fn return_type(&self) -> Option<&Type> { + self.return_type.as_ref() + } + pub fn throws(&self) -> bool { self.attributes.get_throws_err().is_some() } @@ -290,6 +295,9 @@ impl Constructor { self.ffi_func.name = format!("{ci_prefix}_{obj_name}_{}", self.name); self.ffi_func.arguments = self.arguments.iter().map(Into::into).collect(); self.ffi_func.return_type = Some(FfiType::RustArcPtr(obj_name.to_string())); + + // this is a bit of a dirty place to put this, but there isn't another "general" pass + self.return_type = Some(Type::Object(obj_name.to_string())); } pub fn iter_types(&self) -> TypeIterator<'_> { @@ -302,6 +310,7 @@ impl Default for Constructor { Constructor { name: String::from("new"), arguments: Vec::new(), + return_type: None, ffi_func: Default::default(), attributes: Default::default(), } @@ -317,6 +326,7 @@ impl APIConverter for weedle::interface::ConstructorInterfaceMember Ok(Constructor { name: String::from(attributes.get_name().unwrap_or("new")), arguments: self.args.body.list.convert(ci)?, + return_type: None, ffi_func: Default::default(), attributes, }) From 8dadd742df08f8d346e4cbfee25579adfbcd5a46 Mon Sep 17 00:00:00 2001 From: Kristupas Antanavicius Date: Tue, 14 Mar 2023 14:10:41 +0200 Subject: [PATCH 2/2] Implement Callable trait --- uniffi_bindgen/src/interface/function.rs | 36 ++++++++++++++++++++++++ uniffi_bindgen/src/interface/mod.rs | 2 +- uniffi_bindgen/src/interface/object.rs | 30 +++++++++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/uniffi_bindgen/src/interface/function.rs b/uniffi_bindgen/src/interface/function.rs index 142d1fad42..5bd8379196 100644 --- a/uniffi_bindgen/src/interface/function.rs +++ b/uniffi_bindgen/src/interface/function.rs @@ -249,6 +249,42 @@ impl APIConverter for weedle::argument::SingleArgument<'_> { } } +/// Implemented by function-like types (Function, Method, Constructor) +pub trait Callable { + fn arguments(&self) -> Vec<&Argument>; + fn return_type(&self) -> Option; + fn throws_type(&self) -> Option; +} + +impl Callable for Function { + fn arguments(&self) -> Vec<&Argument> { + self.arguments() + } + + fn return_type(&self) -> Option { + self.return_type().cloned() + } + + fn throws_type(&self) -> Option { + self.throws_type() + } +} + +// Needed because Askama likes to add extra refs to variables +impl Callable for &T { + fn arguments(&self) -> Vec<&Argument> { + (*self).arguments() + } + + fn return_type(&self) -> Option { + (*self).return_type() + } + + fn throws_type(&self) -> Option { + (*self).throws_type() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/uniffi_bindgen/src/interface/mod.rs b/uniffi_bindgen/src/interface/mod.rs index e3f7e03dc0..610ab14ea7 100644 --- a/uniffi_bindgen/src/interface/mod.rs +++ b/uniffi_bindgen/src/interface/mod.rs @@ -64,7 +64,7 @@ pub use enum_::Enum; mod error; pub use error::Error; mod function; -pub use function::{Argument, Function}; +pub use function::{Argument, Callable, Function}; mod literal; pub use literal::{Literal, Radix}; mod namespace; diff --git a/uniffi_bindgen/src/interface/object.rs b/uniffi_bindgen/src/interface/object.rs index 2e3270b44b..dbe91e1825 100644 --- a/uniffi_bindgen/src/interface/object.rs +++ b/uniffi_bindgen/src/interface/object.rs @@ -65,7 +65,7 @@ use uniffi_meta::Checksum; use super::attributes::{Attribute, ConstructorAttributes, InterfaceAttributes, MethodAttributes}; use super::ffi::{FfiArgument, FfiFunction, FfiType}; -use super::function::Argument; +use super::function::{Argument, Callable}; use super::types::{Type, TypeIterator}; use super::{convert_type, APIConverter, ComponentInterface}; @@ -333,6 +333,20 @@ impl APIConverter for weedle::interface::ConstructorInterfaceMember } } +impl Callable for Constructor { + fn arguments(&self) -> Vec<&Argument> { + self.arguments() + } + + fn return_type(&self) -> Option { + self.return_type().cloned() + } + + fn throws_type(&self) -> Option { + self.throws_type() + } +} + // Represents an instance method for an object type. // // The FFI will represent this as a function whose first/self argument is a @@ -489,6 +503,20 @@ impl APIConverter for weedle::interface::OperationInterfaceMember<'_> { } } +impl Callable for Method { + fn arguments(&self) -> Vec<&Argument> { + self.arguments() + } + + fn return_type(&self) -> Option { + self.return_type().cloned() + } + + fn throws_type(&self) -> Option { + self.throws_type() + } +} + #[cfg(test)] mod test { use super::*;