diff options
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin')
7 files changed, 317 insertions, 108 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs index e20020e87c..ae4bffc973 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs @@ -26,6 +26,6 @@ impl CodeType for CallbackInterfaceCodeType { } fn initialization_fn(&self) -> Option<String> { - Some(format!("{}.register", self.ffi_converter_name())) + Some(format!("uniffiCallbackInterface{}.register", self.id)) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs index 4329f32f4c..8d075bbedb 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs @@ -5,55 +5,81 @@ use super::{AsCodeType, CodeType}; use crate::backend::{Literal, Type}; use crate::ComponentInterface; -use paste::paste; -fn render_literal(literal: &Literal, inner: &Type, ci: &ComponentInterface) -> String { - match literal { - Literal::Null => "null".into(), - Literal::EmptySequence => "listOf()".into(), - Literal::EmptyMap => "mapOf()".into(), +#[derive(Debug)] +pub struct OptionalCodeType { + inner: Type, +} - // For optionals - _ => super::KotlinCodeOracle.find(inner).literal(literal, ci), +impl OptionalCodeType { + pub fn new(inner: Type) -> Self { + Self { inner } + } + fn inner(&self) -> &Type { + &self.inner } } -macro_rules! impl_code_type_for_compound { - ($T:ty, $type_label_pattern:literal, $canonical_name_pattern: literal) => { - paste! { - #[derive(Debug)] - pub struct $T { - inner: Type, - } - - impl $T { - pub fn new(inner: Type) -> Self { - Self { inner } - } - fn inner(&self) -> &Type { - &self.inner - } - } - - impl CodeType for $T { - fn type_label(&self, ci: &ComponentInterface) -> String { - format!($type_label_pattern, super::KotlinCodeOracle.find(self.inner()).type_label(ci)) - } - - fn canonical_name(&self) -> String { - format!($canonical_name_pattern, super::KotlinCodeOracle.find(self.inner()).canonical_name()) - } - - fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { - render_literal(literal, self.inner(), ci) - } - } +impl CodeType for OptionalCodeType { + fn type_label(&self, ci: &ComponentInterface) -> String { + format!( + "{}?", + super::KotlinCodeOracle.find(self.inner()).type_label(ci) + ) + } + + fn canonical_name(&self) -> String { + format!( + "Optional{}", + super::KotlinCodeOracle.find(self.inner()).canonical_name() + ) + } + + fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { + match literal { + Literal::None => "null".into(), + Literal::Some { inner } => super::KotlinCodeOracle.find(&self.inner).literal(inner, ci), + _ => panic!("Invalid literal for Optional type: {literal:?}"), } } - } +} -impl_code_type_for_compound!(OptionalCodeType, "{}?", "Optional{}"); -impl_code_type_for_compound!(SequenceCodeType, "List<{}>", "Sequence{}"); +#[derive(Debug)] +pub struct SequenceCodeType { + inner: Type, +} + +impl SequenceCodeType { + pub fn new(inner: Type) -> Self { + Self { inner } + } + fn inner(&self) -> &Type { + &self.inner + } +} + +impl CodeType for SequenceCodeType { + fn type_label(&self, ci: &ComponentInterface) -> String { + format!( + "List<{}>", + super::KotlinCodeOracle.find(self.inner()).type_label(ci) + ) + } + + fn canonical_name(&self) -> String { + format!( + "Sequence{}", + super::KotlinCodeOracle.find(self.inner()).canonical_name() + ) + } + + fn literal(&self, literal: &Literal, _ci: &ComponentInterface) -> String { + match literal { + Literal::EmptySequence => "listOf()".into(), + _ => panic!("Invalid literal for List type: {literal:?}"), + } + } +} #[derive(Debug)] pub struct MapCodeType { @@ -92,7 +118,10 @@ impl CodeType for MapCodeType { ) } - fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { - render_literal(literal, &self.value, ci) + fn literal(&self, literal: &Literal, _ci: &ComponentInterface) -> String { + match literal { + Literal::EmptyMap => "mapOf()".into(), + _ => panic!("Invalid literal for Map type: {literal:?}"), + } } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs deleted file mode 100644 index 154e12a381..0000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs +++ /dev/null @@ -1,24 +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; -use crate::ComponentInterface; - -#[derive(Debug)] -pub struct ForeignExecutorCodeType; - -impl CodeType for ForeignExecutorCodeType { - fn type_label(&self, _ci: &ComponentInterface) -> String { - // Kotlin uses a CoroutineScope for ForeignExecutor - "CoroutineScope".into() - } - - fn canonical_name(&self) -> String { - "ForeignExecutor".into() - } - - fn initialization_fn(&self) -> Option<String> { - Some("FfiConverterForeignExecutor.register".into()) - } -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs index 3ecf09d47f..d55c78f760 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs @@ -17,8 +17,8 @@ impl ExternalCodeType { } impl CodeType for ExternalCodeType { - fn type_label(&self, _ci: &ComponentInterface) -> String { - self.name.clone() + fn type_label(&self, ci: &ComponentInterface) -> String { + super::KotlinCodeOracle.class_name(ci, &self.name) } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs index 1ed0575a9a..c4fc8e0ed6 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs @@ -7,20 +7,21 @@ use std::cell::RefCell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Debug; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use askama::Template; +use camino::Utf8Path; use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase}; use serde::{Deserialize, Serialize}; use crate::backend::TemplateExpression; +use crate::bindings::kotlin; 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; @@ -28,6 +29,28 @@ mod primitives; mod record; mod variant; +pub struct KotlinBindingGenerator; +impl BindingGenerator for KotlinBindingGenerator { + type Config = Config; + + fn write_bindings( + &self, + ci: &ComponentInterface, + config: &Config, + out_dir: &Utf8Path, + try_format_code: bool, + ) -> Result<()> { + kotlin::write_bindings(config, ci, out_dir, try_format_code) + } + + fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()> { + if cdylib_name.is_none() { + bail!("Generate bindings for Kotlin requires a cdylib, but {library_path} was given"); + } + Ok(()) + } +} + trait CodeType: Debug { /// The language specific label used to reference this type. This will be used in /// method signatures and property declarations. @@ -73,10 +96,21 @@ trait CodeType: Debug { pub struct Config { package_name: Option<String>, cdylib_name: Option<String>, + generate_immutable_records: Option<bool>, #[serde(default)] custom_types: HashMap<String, CustomTypeConfig>, #[serde(default)] external_packages: HashMap<String, String>, + #[serde(default)] + android: bool, + #[serde(default)] + android_cleaner: Option<bool>, +} + +impl Config { + pub(crate) fn android_cleaner(&self) -> bool { + self.android_cleaner.unwrap_or(self.android) + } } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -103,6 +137,11 @@ impl Config { "uniffi".into() } } + + /// Whether to generate immutable records (`val` instead of `var`) + pub fn generate_immutable_records(&self) -> bool { + self.generate_immutable_records.unwrap_or(false) + } } impl BindingsConfig for Config { @@ -236,7 +275,6 @@ pub struct KotlinWrapper<'a> { ci: &'a ComponentInterface, type_helper_code: String, type_imports: BTreeSet<ImportRequirement>, - has_async_fns: bool, } impl<'a> KotlinWrapper<'a> { @@ -249,7 +287,6 @@ impl<'a> KotlinWrapper<'a> { ci, type_helper_code, type_imports, - has_async_fns: ci.has_async_fns(), } } @@ -258,10 +295,6 @@ impl<'a> KotlinWrapper<'a> { .iter_types() .map(|t| KotlinCodeOracle.find(t)) .filter_map(|ct| ct.initialization_fn()) - .chain( - self.has_async_fns - .then(|| "uniffiRustFutureContinuationCallback.register".into()), - ) .collect() } @@ -301,7 +334,12 @@ impl KotlinCodeOracle { /// Get the idiomatic Kotlin rendering of a variable name. fn var_name(&self, nm: &str) -> String { - format!("`{}`", nm.to_string().to_lower_camel_case()) + format!("`{}`", self.var_name_raw(nm)) + } + + /// `var_name` without the backticks. Useful for using in `@Structure.FieldOrder`. + pub fn var_name_raw(&self, nm: &str) -> String { + nm.to_string().to_lower_camel_case() } /// Get the idiomatic Kotlin rendering of an individual enum variant. @@ -309,14 +347,78 @@ impl KotlinCodeOracle { nm.to_string().to_shouty_snake_case() } - fn ffi_type_label_by_value(ffi_type: &FfiType) -> String { + /// Get the idiomatic Kotlin 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 Kotlin rendering of an FFI struct name + fn ffi_struct_name(&self, nm: &str) -> String { + format!("Uniffi{}", nm.to_upper_camel_case()) + } + + fn ffi_type_label_by_value(&self, ffi_type: &FfiType) -> String { + match ffi_type { + FfiType::RustBuffer(_) => format!("{}.ByValue", self.ffi_type_label(ffi_type)), + FfiType::Struct(name) => format!("{}.UniffiByValue", self.ffi_struct_name(name)), + _ => self.ffi_type_label(ffi_type), + } + } + + /// FFI type name to use inside structs + /// + /// The main requirement here is that all types must have default values or else the struct + /// won't work in some JNA contexts. + fn ffi_type_label_for_ffi_struct(&self, ffi_type: &FfiType) -> String { + match ffi_type { + // Make callbacks function pointers nullable. This matches the semantics of a C + // function pointer better and allows for `null` as a default value. + FfiType::Callback(name) => format!("{}?", self.ffi_callback_name(name)), + _ => self.ffi_type_label_by_value(ffi_type), + } + } + + /// Default values for FFI + /// + /// This is used to: + /// - Set a default return value for error results + /// - Set a default for structs, which JNA sometimes requires + fn ffi_default_value(&self, ffi_type: &FfiType) -> String { + match ffi_type { + FfiType::UInt8 | FfiType::Int8 => "0.toByte()".to_owned(), + FfiType::UInt16 | FfiType::Int16 => "0.toShort()".to_owned(), + FfiType::UInt32 | FfiType::Int32 => "0".to_owned(), + FfiType::UInt64 | FfiType::Int64 => "0.toLong()".to_owned(), + FfiType::Float32 => "0.0f".to_owned(), + FfiType::Float64 => "0.0".to_owned(), + FfiType::RustArcPtr(_) => "Pointer.NULL".to_owned(), + FfiType::RustBuffer(_) => "RustBuffer.ByValue()".to_owned(), + FfiType::Callback(_) => "null".to_owned(), + FfiType::RustCallStatus => "UniffiRustCallStatus.ByValue()".to_owned(), + _ => unimplemented!("ffi_default_value: {ffi_type:?}"), + } + } + + fn ffi_type_label_by_reference(&self, ffi_type: &FfiType) -> String { match ffi_type { - FfiType::RustBuffer(_) => format!("{}.ByValue", Self::ffi_type_label(ffi_type)), - _ => Self::ffi_type_label(ffi_type), + FfiType::Int8 + | FfiType::UInt8 + | FfiType::Int16 + | FfiType::UInt16 + | FfiType::Int32 + | FfiType::UInt32 + | FfiType::Int64 + | FfiType::UInt64 + | FfiType::Float32 + | FfiType::Float64 => format!("{}ByReference", self.ffi_type_label(ffi_type)), + FfiType::RustArcPtr(_) => "PointerByReference".to_owned(), + // JNA structs default to ByReference + FfiType::RustBuffer(_) | FfiType::Struct(_) => self.ffi_type_label(ffi_type), + _ => panic!("{ffi_type:?} by reference is not implemented"), } } - fn ffi_type_label(ffi_type: &FfiType) -> String { + fn ffi_type_label(&self, ffi_type: &FfiType) -> String { match ffi_type { // Note that unsigned integers in Kotlin are currently experimental, but java.nio.ByteBuffer does not // support them yet. Thus, we use the signed variants to represent both signed and unsigned @@ -327,19 +429,35 @@ impl KotlinCodeOracle { FfiType::Int64 | FfiType::UInt64 => "Long".to_string(), FfiType::Float32 => "Float".to_string(), FfiType::Float64 => "Double".to_string(), + FfiType::Handle => "Long".to_string(), FfiType::RustArcPtr(_) => "Pointer".to_string(), FfiType::RustBuffer(maybe_suffix) => { format!("RustBuffer{}", maybe_suffix.as_deref().unwrap_or_default()) } + FfiType::RustCallStatus => "UniffiRustCallStatus.ByValue".to_string(), FfiType::ForeignBytes => "ForeignBytes.ByValue".to_string(), - FfiType::ForeignCallback => "ForeignCallback".to_string(), - FfiType::ForeignExecutorHandle => "USize".to_string(), - FfiType::ForeignExecutorCallback => "UniFfiForeignExecutorCallback".to_string(), - FfiType::RustFutureHandle => "Pointer".to_string(), - FfiType::RustFutureContinuationCallback => { - "UniFffiRustFutureContinuationCallbackType".to_string() - } - FfiType::RustFutureContinuationData => "USize".to_string(), + FfiType::Callback(name) => self.ffi_callback_name(name), + FfiType::Struct(name) => self.ffi_struct_name(name), + FfiType::Reference(inner) => self.ffi_type_label_by_reference(inner), + FfiType::VoidPointer => "Pointer".to_string(), + } + } + + /// Get the name of the interface and class name for an object. + /// + /// If we support callback interfaces, the interface name is the object name, and the class name is derived from that. + /// Otherwise, the class name is the object name and the interface 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 interface. If not, then lower + /// only lowers the concrete class. + fn object_names(&self, ci: &ComponentInterface, obj: &Object) -> (String, String) { + let class_name = self.class_name(ci, obj.name()); + if obj.has_callback_interface() { + let impl_name = format!("{class_name}Impl"); + (class_name, impl_name) + } else { + (format!("{class_name}Interface"), class_name) } } } @@ -376,12 +494,11 @@ impl<T: AsType> AsCodeType for T { 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)) } @@ -401,6 +518,7 @@ impl<T: AsType> AsCodeType for T { mod filters { use super::*; pub use crate::backend::filters::*; + use uniffi_meta::LiteralMetadata; pub(super) fn type_name( as_ct: &impl AsCodeType, @@ -454,8 +572,52 @@ mod filters { Ok(as_ct.as_codetype().literal(literal, ci)) } + // Get the idiomatic Kotlin rendering of an integer. + fn int_literal(t: &Option<Type>, base10: String) -> Result<String, askama::Error> { + if let Some(t) = t { + match t { + Type::Int8 | Type::Int16 | Type::Int32 | Type::Int64 => Ok(base10), + Type::UInt8 | Type::UInt16 | Type::UInt32 | Type::UInt64 => Ok(base10 + "u"), + _ => Err(askama::Error::Custom(Box::new(UniFFIError::new( + "Only ints are supported.".to_string(), + )))), + } + } else { + Err(askama::Error::Custom(Box::new(UniFFIError::new( + "Enum hasn't defined a repr".to_string(), + )))) + } + } + + // Get the idiomatic Kotlin rendering of an individual enum variant's discriminant + pub fn variant_discr_literal(e: &Enum, index: &usize) -> Result<String, askama::Error> { + let literal = e.variant_discr(*index).expect("invalid index"); + match literal { + // Kotlin doesn't convert between signed and unsigned by default + // so we'll need to make sure we define the type as appropriately + LiteralMetadata::UInt(v, _, _) => int_literal(e.variant_discr_type(), v.to_string()), + LiteralMetadata::Int(v, _, _) => int_literal(e.variant_discr_type(), v.to_string()), + _ => Err(askama::Error::Custom(Box::new(UniFFIError::new( + "Only ints are supported.".to_string(), + )))), + } + } + pub fn ffi_type_name_by_value(type_: &FfiType) -> Result<String, askama::Error> { - Ok(KotlinCodeOracle::ffi_type_label_by_value(type_)) + Ok(KotlinCodeOracle.ffi_type_label_by_value(type_)) + } + + pub fn ffi_type_name_for_ffi_struct(type_: &FfiType) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.ffi_type_label_for_ffi_struct(type_)) + } + + pub fn ffi_default_value(type_: FfiType) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.ffi_default_value(&type_)) + } + + /// Get the idiomatic Kotlin rendering of a function name. + pub fn class_name(nm: &str, ci: &ComponentInterface) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.class_name(ci, nm)) } /// Get the idiomatic Kotlin rendering of a function name. @@ -468,6 +630,11 @@ mod filters { Ok(KotlinCodeOracle.var_name(nm)) } + /// Get the idiomatic Kotlin rendering of a variable name. + pub fn var_name_raw(nm: &str) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.var_name_raw(nm)) + } + /// Get a String representing the name used for an individual enum variant. pub fn variant_name(v: &Variant) -> Result<String, askama::Error> { Ok(KotlinCodeOracle.enum_variant_name(v.name())) @@ -478,13 +645,30 @@ mod filters { Ok(KotlinCodeOracle.convert_error_suffix(&name)) } + /// Get the idiomatic Kotlin rendering of an FFI callback function name + pub fn ffi_callback_name(nm: &str) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.ffi_callback_name(nm)) + } + + /// Get the idiomatic Kotlin rendering of an FFI struct name + pub fn ffi_struct_name(nm: &str) -> Result<String, askama::Error> { + Ok(KotlinCodeOracle.ffi_struct_name(nm)) + } + + pub fn object_names( + obj: &Object, + ci: &ComponentInterface, + ) -> Result<(String, String), askama::Error> { + Ok(KotlinCodeOracle.object_names(ci, obj)) + } + pub fn async_poll( callable: impl Callable, ci: &ComponentInterface, ) -> Result<String, askama::Error> { let ffi_func = callable.ffi_rust_future_poll(ci); Ok(format!( - "{{ future, continuation -> _UniFFILib.INSTANCE.{ffi_func}(future, continuation) }}" + "{{ future, callback, continuation -> UniffiLib.INSTANCE.{ffi_func}(future, callback, continuation) }}" )) } @@ -493,7 +677,7 @@ mod filters { ci: &ComponentInterface, ) -> Result<String, askama::Error> { let ffi_func = callable.ffi_rust_future_complete(ci); - let call = format!("_UniFFILib.INSTANCE.{ffi_func}(future, continuation)"); + let call = format!("UniffiLib.INSTANCE.{ffi_func}(future, continuation)"); let call = match callable.return_type() { Some(Type::External { kind: ExternalKind::DataClass, @@ -502,7 +686,7 @@ mod filters { }) => { // Need to convert the RustBuffer from our package to the RustBuffer of the external package let suffix = KotlinCodeOracle.class_name(ci, &name); - format!("{call}.let {{ RustBuffer{suffix}.create(it.capacity, it.len, it.data) }}") + format!("{call}.let {{ RustBuffer{suffix}.create(it.capacity.toULong(), it.len.toULong(), it.data) }}") } _ => call, }; @@ -515,7 +699,7 @@ mod filters { ) -> Result<String, askama::Error> { let ffi_func = callable.ffi_rust_future_free(ci); Ok(format!( - "{{ future -> _UniFFILib.INSTANCE.{ffi_func}(future) }}" + "{{ future -> UniffiLib.INSTANCE.{ffi_func}(future) }}" )) } @@ -527,4 +711,13 @@ mod filters { pub fn unquote(nm: &str) -> Result<String, askama::Error> { Ok(nm.trim_matches('`').to_string()) } + + /// Get the idiomatic Kotlin rendering of docstring + pub fn docstring(docstring: &str, spaces: &i32) -> Result<String, askama::Error> { + 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))) + } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs index c39ae59cce..5a4305d14a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs @@ -3,25 +3,32 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::CodeType; -use crate::ComponentInterface; +use crate::{interface::ObjectImpl, ComponentInterface}; #[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, ci: &ComponentInterface) -> String { - super::KotlinCodeOracle.class_name(ci, &self.id) + super::KotlinCodeOracle.class_name(ci, &self.name) } fn canonical_name(&self) -> String { - format!("Type{}", self.id) + format!("Type{}", self.name) + } + + fn initialization_fn(&self) -> Option<String> { + self.imp + .has_callback_interface() + .then(|| format!("uniffiCallbackInterface{}.register", self.name)) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs index 22495fa209..0bc5a5d99e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs @@ -9,7 +9,11 @@ use paste::paste; fn render_literal(literal: &Literal, _ci: &ComponentInterface) -> 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 { // Bytes, Shorts and Ints can all be inferred from the type. Type::Int8 | Type::Int16 | Type::Int32 => num_str, Type::Int64 => format!("{num_str}L"), @@ -19,7 +23,7 @@ fn render_literal(literal: &Literal, _ci: &ComponentInterface) -> String { Type::Float32 => format!("{num_str}f"), Type::Float64 => num_str, - _ => panic!("Unexpected literal: {num_str} is not a number"), + _ => panic!("Unexpected literal: {num_str} for type: {type_:?}"), } } @@ -56,7 +60,7 @@ macro_rules! impl_code_type_for_primitive { impl CodeType for $T { fn type_label(&self, _ci: &ComponentInterface) -> String { - $class_name.into() + format!("kotlin.{}", $class_name) } fn canonical_name(&self) -> String { |