From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../bindings/swift/gen_swift/callback_interface.rs | 12 +- .../src/bindings/swift/gen_swift/compounds.rs | 5 +- .../src/bindings/swift/gen_swift/executor.rs | 23 --- .../src/bindings/swift/gen_swift/external.rs | 2 +- .../src/bindings/swift/gen_swift/mod.rs | 209 +++++++++++++++++---- .../src/bindings/swift/gen_swift/object.rs | 18 +- .../src/bindings/swift/gen_swift/primitives.rs | 8 +- 7 files changed, 203 insertions(+), 74 deletions(-) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs (limited to 'third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift') diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs index 5d8b37e0af..dab89e0259 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs @@ -6,21 +6,25 @@ use super::CodeType; #[derive(Debug)] pub struct CallbackInterfaceCodeType { - id: String, + name: String, } impl CallbackInterfaceCodeType { - pub fn new(id: String) -> Self { - Self { id } + pub fn new(name: String) -> Self { + Self { name } } } impl CodeType for CallbackInterfaceCodeType { fn type_label(&self) -> String { - super::SwiftCodeOracle.class_name(&self.id) + super::SwiftCodeOracle.class_name(&self.name) } fn canonical_name(&self) -> String { format!("CallbackInterface{}", self.type_label()) } + + fn initialization_fn(&self) -> Option { + Some(format!("uniffiCallbackInit{}", self.name)) + } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs index 8e6dddf3f9..d89fdfd386 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs @@ -30,8 +30,9 @@ impl CodeType for OptionalCodeType { fn literal(&self, literal: &Literal) -> String { match literal { - Literal::Null => "nil".into(), - _ => super::SwiftCodeOracle.find(&self.inner).literal(literal), + Literal::None => "nil".into(), + Literal::Some { inner } => super::SwiftCodeOracle.find(&self.inner).literal(inner), + _ => panic!("Invalid literal for Optional type: {literal:?}"), } } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs deleted file mode 100644 index b488b004cf..0000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs +++ /dev/null @@ -1,23 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use super::CodeType; - -#[derive(Debug)] -pub struct ForeignExecutorCodeType; - -impl CodeType for ForeignExecutorCodeType { - fn type_label(&self) -> String { - // On Swift, we define a struct to represent a ForeignExecutor - "UniFfiForeignExecutor".into() - } - - fn canonical_name(&self) -> String { - "ForeignExecutor".into() - } - - fn initialization_fn(&self) -> Option { - Some("uniffiInitForeignExecutor".into()) - } -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs index 0b6728ba84..3960b7aae1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs @@ -17,7 +17,7 @@ impl ExternalCodeType { impl CodeType for ExternalCodeType { fn type_label(&self) -> String { - self.name.clone() + super::SwiftCodeOracle.class_name(&self.name) } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs index 12db4afc66..16c1625123 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs @@ -10,25 +10,49 @@ use std::fmt::Debug; use anyhow::{Context, Result}; use askama::Template; -use heck::{ToLowerCamelCase, ToUpperCamelCase}; +use camino::Utf8Path; +use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase}; use serde::{Deserialize, Serialize}; use super::Bindings; use crate::backend::TemplateExpression; +use crate::bindings::swift; use crate::interface::*; -use crate::BindingsConfig; +use crate::{BindingGenerator, BindingsConfig}; mod callback_interface; mod compounds; mod custom; mod enum_; -mod executor; mod external; mod miscellany; mod object; mod primitives; mod record; +pub struct SwiftBindingGenerator; +impl BindingGenerator for SwiftBindingGenerator { + type Config = Config; + + fn write_bindings( + &self, + ci: &ComponentInterface, + config: &Config, + out_dir: &Utf8Path, + try_format_code: bool, + ) -> Result<()> { + swift::write_bindings(config, ci, out_dir, try_format_code) + } + + fn check_library_path( + &self, + _library_path: &Utf8Path, + _cdylib_name: Option<&str>, + ) -> Result<()> { + Ok(()) + } +} + /// A trait tor the implementation. trait CodeType: Debug { /// The language specific label used to reference this type. This will be used in @@ -196,6 +220,8 @@ pub struct Config { ffi_module_filename: Option, generate_module_map: Option, omit_argument_labels: Option, + generate_immutable_records: Option, + experimental_sendable_value_types: Option, #[serde(default)] custom_types: HashMap, } @@ -261,6 +287,16 @@ impl Config { pub fn omit_argument_labels(&self) -> bool { self.omit_argument_labels.unwrap_or(false) } + + /// Whether to generate immutable records (`let` instead of `var`) + pub fn generate_immutable_records(&self) -> bool { + self.generate_immutable_records.unwrap_or(false) + } + + /// Whether to mark value types as 'Sendable' + pub fn experimental_sendable_value_types(&self) -> bool { + self.experimental_sendable_value_types.unwrap_or(false) + } } impl BindingsConfig for Config { @@ -400,7 +436,6 @@ pub struct SwiftWrapper<'a> { ci: &'a ComponentInterface, type_helper_code: String, type_imports: BTreeSet, - has_async_fns: bool, } impl<'a> SwiftWrapper<'a> { pub fn new(config: Config, ci: &'a ComponentInterface) -> Self { @@ -412,7 +447,6 @@ impl<'a> SwiftWrapper<'a> { ci, type_helper_code, type_imports, - has_async_fns: ci.has_async_fns(), } } @@ -425,10 +459,6 @@ impl<'a> SwiftWrapper<'a> { .iter_types() .map(|t| SwiftCodeOracle.find(t)) .filter_map(|ct| ct.initialization_fn()) - .chain( - self.has_async_fns - .then(|| "uniffiInitContinuationCallback".into()), - ) .collect() } } @@ -464,12 +494,11 @@ impl SwiftCodeOracle { Type::Duration => Box::new(miscellany::DurationCodeType), Type::Enum { name, .. } => Box::new(enum_::EnumCodeType::new(name)), - Type::Object { name, .. } => Box::new(object::ObjectCodeType::new(name)), + Type::Object { name, imp, .. } => Box::new(object::ObjectCodeType::new(name, imp)), Type::Record { name, .. } => Box::new(record::RecordCodeType::new(name)), Type::CallbackInterface { name, .. } => { Box::new(callback_interface::CallbackInterfaceCodeType::new(name)) } - Type::ForeignExecutor => Box::new(executor::ForeignExecutorCodeType), Type::Optional { inner_type } => { Box::new(compounds::OptionalCodeType::new(*inner_type)) } @@ -509,7 +538,22 @@ impl SwiftCodeOracle { nm.to_string().to_lower_camel_case() } - fn ffi_type_label_raw(&self, ffi_type: &FfiType) -> String { + /// Get the idiomatic Swift rendering of an FFI callback function name + fn ffi_callback_name(&self, nm: &str) -> String { + format!("Uniffi{}", nm.to_upper_camel_case()) + } + + /// Get the idiomatic Swift rendering of an FFI struct name + fn ffi_struct_name(&self, nm: &str) -> String { + format!("Uniffi{}", nm.to_upper_camel_case()) + } + + /// Get the idiomatic Swift rendering of an if guard name + fn if_guard_name(&self, nm: &str) -> String { + format!("UNIFFI_FFIDEF_{}", nm.to_shouty_snake_case()) + } + + fn ffi_type_label(&self, ffi_type: &FfiType) -> String { match ffi_type { FfiType::Int8 => "Int8".into(), FfiType::UInt8 => "UInt8".into(), @@ -521,40 +565,74 @@ impl SwiftCodeOracle { FfiType::UInt64 => "UInt64".into(), FfiType::Float32 => "Float".into(), FfiType::Float64 => "Double".into(), + FfiType::Handle => "UInt64".into(), FfiType::RustArcPtr(_) => "UnsafeMutableRawPointer".into(), FfiType::RustBuffer(_) => "RustBuffer".into(), + FfiType::RustCallStatus => "RustCallStatus".into(), FfiType::ForeignBytes => "ForeignBytes".into(), - FfiType::ForeignCallback => "ForeignCallback".into(), - FfiType::ForeignExecutorHandle => "Int".into(), - FfiType::ForeignExecutorCallback => "ForeignExecutorCallback".into(), - FfiType::RustFutureContinuationCallback => "UniFfiRustFutureContinuation".into(), - FfiType::RustFutureHandle | FfiType::RustFutureContinuationData => { - "UnsafeMutableRawPointer".into() + // Note: @escaping is required for Swift versions before 5.7 for callbacks passed into + // async functions. Swift 5.7 and later does not require it. We should probably remove + // it once we upgrade our minimum requirement to 5.7 or later. + FfiType::Callback(name) => format!("@escaping {}", self.ffi_callback_name(name)), + FfiType::Struct(name) => self.ffi_struct_name(name), + FfiType::Reference(inner) => { + format!("UnsafeMutablePointer<{}>", self.ffi_type_label(inner)) } + FfiType::VoidPointer => "UnsafeMutableRawPointer".into(), } } - fn ffi_type_label(&self, ffi_type: &FfiType) -> String { - match ffi_type { - FfiType::ForeignCallback - | FfiType::ForeignExecutorCallback - | FfiType::RustFutureHandle - | FfiType::RustFutureContinuationCallback - | FfiType::RustFutureContinuationData => { - format!("{} _Nonnull", self.ffi_type_label_raw(ffi_type)) - } - _ => self.ffi_type_label_raw(ffi_type), + /// Default values for FFI types + /// + /// Used to set a default return value when returning an error + fn ffi_default_value(&self, return_type: Option<&FfiType>) -> String { + match return_type { + Some(t) => match t { + FfiType::UInt8 + | FfiType::Int8 + | FfiType::UInt16 + | FfiType::Int16 + | FfiType::UInt32 + | FfiType::Int32 + | FfiType::UInt64 + | FfiType::Int64 => "0".to_owned(), + FfiType::Float32 | FfiType::Float64 => "0.0".to_owned(), + FfiType::RustArcPtr(_) => "nil".to_owned(), + FfiType::RustBuffer(_) => "RustBuffer.empty()".to_owned(), + _ => unimplemented!("FFI return type: {t:?}"), + }, + // When we need to use a value for void returns, we use a `u8` placeholder + None => "0".to_owned(), } } fn ffi_canonical_name(&self, ffi_type: &FfiType) -> String { - self.ffi_type_label_raw(ffi_type) + self.ffi_type_label(ffi_type) + } + + /// Get the name of the protocol and class name for an object. + /// + /// If we support callback interfaces, the protocol name is the object name, and the class name is derived from that. + /// Otherwise, the class name is the object name and the protocol name is derived from that. + /// + /// This split determines what types `FfiConverter.lower()` inputs. If we support callback + /// interfaces, `lower` must lower anything that implements the protocol. If not, then lower + /// only lowers the concrete class. + fn object_names(&self, obj: &Object) -> (String, String) { + let class_name = self.class_name(obj.name()); + if obj.has_callback_interface() { + let impl_name = format!("{class_name}Impl"); + (class_name, impl_name) + } else { + (format!("{class_name}Protocol"), class_name) + } } } pub mod filters { use super::*; pub use crate::backend::filters::*; + use uniffi_meta::LiteralMetadata; fn oracle() -> &'static SwiftCodeOracle { &SwiftCodeOracle @@ -564,6 +642,13 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).type_label()) } + pub fn return_type_name(as_type: Option<&impl AsType>) -> Result { + Ok(match as_type { + Some(as_type) => oracle().find(&as_type.as_type()).type_label(), + None => "()".to_owned(), + }) + } + pub fn canonical_name(as_type: &impl AsType) -> Result { Ok(oracle().find(&as_type.as_type()).canonical_name()) } @@ -572,6 +657,15 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).ffi_converter_name()) } + pub fn ffi_error_converter_name(as_type: &impl AsType) -> Result { + // special handling for types used as errors. + let mut name = oracle().find(&as_type.as_type()).ffi_converter_name(); + if matches!(&as_type.as_type(), Type::Object { .. }) { + name.push_str("__as_error") + } + Ok(name) + } + pub fn lower_fn(as_type: &impl AsType) -> Result { Ok(oracle().find(&as_type.as_type()).lower()) } @@ -595,6 +689,16 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).literal(literal)) } + // Get the idiomatic Swift rendering of an individual enum variant's discriminant + pub fn variant_discr_literal(e: &Enum, index: &usize) -> Result { + let literal = e.variant_discr(*index).expect("invalid index"); + match literal { + LiteralMetadata::UInt(v, _, _) => Ok(v.to_string()), + LiteralMetadata::Int(v, _, _) => Ok(v.to_string()), + _ => unreachable!("expected an UInt!"), + } + } + /// Get the Swift type for an FFIType pub fn ffi_type_name(ffi_type: &FfiType) -> Result { Ok(oracle().ffi_type_label(ffi_type)) @@ -604,6 +708,10 @@ pub mod filters { Ok(oracle().ffi_canonical_name(ffi_type)) } + pub fn ffi_default_value(return_type: Option) -> Result { + Ok(oracle().ffi_default_value(return_type.as_ref())) + } + /// Like `ffi_type_name`, but used in `BridgingHeaderTemplate.h` which uses a slightly different /// names. pub fn header_ffi_type_name(ffi_type: &FfiType) -> Result { @@ -618,18 +726,17 @@ pub mod filters { FfiType::UInt64 => "uint64_t".into(), FfiType::Float32 => "float".into(), FfiType::Float64 => "double".into(), + FfiType::Handle => "uint64_t".into(), FfiType::RustArcPtr(_) => "void*_Nonnull".into(), FfiType::RustBuffer(_) => "RustBuffer".into(), + FfiType::RustCallStatus => "RustCallStatus".into(), FfiType::ForeignBytes => "ForeignBytes".into(), - FfiType::ForeignCallback => "ForeignCallback _Nonnull".into(), - FfiType::ForeignExecutorCallback => "UniFfiForeignExecutorCallback _Nonnull".into(), - FfiType::ForeignExecutorHandle => "size_t".into(), - FfiType::RustFutureContinuationCallback => { - "UniFfiRustFutureContinuation _Nonnull".into() - } - FfiType::RustFutureHandle | FfiType::RustFutureContinuationData => { - "void* _Nonnull".into() + FfiType::Callback(name) => { + format!("{} _Nonnull", SwiftCodeOracle.ffi_callback_name(name)) } + FfiType::Struct(name) => SwiftCodeOracle.ffi_struct_name(name), + FfiType::Reference(inner) => format!("{}* _Nonnull", header_ffi_type_name(inner)?), + FfiType::VoidPointer => "void* _Nonnull".into(), }) } @@ -664,6 +771,30 @@ pub mod filters { Ok(oracle().enum_variant_name(nm)) } + /// Get the idiomatic Swift rendering of an FFI callback function name + pub fn ffi_callback_name(nm: &str) -> Result { + Ok(oracle().ffi_callback_name(nm)) + } + + /// Get the idiomatic Swift rendering of an FFI struct name + pub fn ffi_struct_name(nm: &str) -> Result { + Ok(oracle().ffi_struct_name(nm)) + } + + /// Get the idiomatic Swift rendering of an if guard name + pub fn if_guard_name(nm: &str) -> Result { + Ok(oracle().if_guard_name(nm)) + } + + /// Get the idiomatic Swift rendering of docstring + pub fn docstring(docstring: &str, spaces: &i32) -> Result { + let middle = textwrap::indent(&textwrap::dedent(docstring), " * "); + let wrapped = format!("/**\n{middle}\n */"); + + let spaces = usize::try_from(*spaces).unwrap_or_default(); + Ok(textwrap::indent(&wrapped, &" ".repeat(spaces))) + } + pub fn error_handler(result: &ResultType) -> Result { Ok(match &result.throws_type { Some(t) => format!("{}.lift", ffi_converter_name(t)?), @@ -685,4 +816,8 @@ pub mod filters { } )) } + + pub fn object_names(obj: &Object) -> Result<(String, String), askama::Error> { + Ok(SwiftCodeOracle.object_names(obj)) + } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs index ea140c998d..d4497a7b19 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs @@ -3,24 +3,32 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::CodeType; +use crate::interface::ObjectImpl; #[derive(Debug)] pub struct ObjectCodeType { - id: String, + name: String, + imp: ObjectImpl, } impl ObjectCodeType { - pub fn new(id: String) -> Self { - Self { id } + pub fn new(name: String, imp: ObjectImpl) -> Self { + Self { name, imp } } } impl CodeType for ObjectCodeType { fn type_label(&self) -> String { - super::SwiftCodeOracle.class_name(&self.id) + super::SwiftCodeOracle.class_name(&self.name) } fn canonical_name(&self) -> String { - format!("Type{}", self.id) + format!("Type{}", self.name) + } + + fn initialization_fn(&self) -> Option { + self.imp + .has_callback_interface() + .then(|| format!("uniffiCallbackInit{}", self.name)) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs index 86424658a3..e0c670520e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs @@ -9,7 +9,11 @@ use paste::paste; fn render_literal(literal: &Literal) -> String { fn typed_number(type_: &Type, num_str: String) -> String { - match type_ { + let unwrapped_type = match type_ { + Type::Optional { inner_type } => inner_type, + t => t, + }; + match unwrapped_type { // special case Int32. Type::Int32 => num_str, // otherwise use constructor e.g. UInt8(x) @@ -29,7 +33,7 @@ fn render_literal(literal: &Literal) -> String { super::SwiftCodeOracle.find(type_).type_label() ) } - _ => panic!("Unexpected literal: {num_str} is not a number"), + _ => panic!("Unexpected literal: {num_str} for type: {type_:?}"), } } -- cgit v1.2.3