Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ required-features = ["binary"]
anyhow = "1"
paste = "1"
heck = "0.5"
uniffi = { workspace = true, features = [
"build", "tokio"
] }
uniffi = { workspace = true, features = ["build", "tokio"] }
uniffi_dart_macro = { path = "./uniffi_dart_macro" }
uniffi_bindgen = { workspace = true }
camino = "1"
serde = "1"
toml = "0.5.1"
toml = "0.9"
genco = "0.17.5"
proc-macro2 = "1.0.66"

Expand All @@ -60,10 +58,10 @@ stringcase = "0.4.0"
members = [
".",
"uniffi_dart_macro",

# Working fixtures - only include fixtures that actually work
"fixtures/arithmetic",
"fixtures/bytes_types",
"fixtures/bytes_types",
"fixtures/duration_type_test",
"fixtures/type-limits",
"fixtures/hello_world",
Expand All @@ -77,8 +75,8 @@ members = [
]

[workspace.dependencies]
uniffi = { version = "0.29.0" }
uniffi_bindgen = { version = "0.29.0" }
uniffi_build = { version = "0.29.0" }
uniffi_testing = { version = "0.29.0" }
uniffi = { version = "0.30.0" }
uniffi_bindgen = { version = "0.30.0" }
uniffi_build = { version = "0.30.0" }
uniffi_testing = { version = "0.30.0" }
camino = { version = "1.1" }
4 changes: 2 additions & 2 deletions fixtures/benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ crate-type = ["lib", "cdylib"]
bench = false

[dependencies]
uniffi = "0.29"
uniffi = "0.30"
clap = { version = "4", features = ["cargo", "std", "derive"] }
criterion = "0.5.1"

[build-dependencies]
uniffi-dart = { path = "../../" }
camino = "1"
camino = "1"
4 changes: 2 additions & 2 deletions fixtures/docstring-proc-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ crate-type = ["lib", "cdylib"]

[dependencies]
thiserror = "1.0"
uniffi = "0.29"
uniffi = "0.30"

[build-dependencies]
uniffi-dart = { path = "../../" }
camino = "1"
camino = "1"
4 changes: 2 additions & 2 deletions fixtures/docstring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ crate-type = ["lib", "cdylib"]

[dependencies]
thiserror = "1.0"
uniffi = "0.29"
uniffi = "0.30"
uniffi-dart = { path = "../../", features = ["bindgen-tests"] }

[build-dependencies]
uniffi-dart = { path = "../../", features = ["build"] }
camino = { workspace = true }
camino = { workspace = true }
4 changes: 2 additions & 2 deletions fixtures/keywords/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ name = "keywords"
crate-type = ["lib", "cdylib"]

[dependencies]
uniffi = "0.29"
uniffi = "0.30"

[build-dependencies]
uniffi-dart = { path = "../../", features = ["build"] }
camino = { workspace = true }
camino = { workspace = true }
4 changes: 2 additions & 2 deletions fixtures/metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ crate-type = ["lib", "cdylib"]

[dependencies]
thiserror = "1.0"
uniffi = "0.29"
uniffi = "0.30"
uniffi-dart = { path = "../../", features = ["bindgen-tests"] }

[build-dependencies]
uniffi-dart = { path = "../../", features = ["build"] }
camino = { workspace = true }
camino = { workspace = true }
4 changes: 2 additions & 2 deletions fixtures/proc-macro-no-implicit-prelude/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ myfeature = []

[dependencies]
thiserror = "1.0"
uniffi = "0.29"
uniffi = "0.30"

[build-dependencies]
uniffi-dart = { path = "../../" }
camino = "1"
camino = "1"
9 changes: 6 additions & 3 deletions fixtures/time-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ name = "time_types"
crate-type = ["lib", "cdylib"]

[dependencies]
uniffi = "0.29"
uniffi = "0.30"
thiserror = "1.0"
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
chrono = { version = "0.4", default-features = false, features = [
"alloc",
"std",
] }

[build-dependencies]
uniffi-dart = { path = "../../", features = ["build"] }
camino = { workspace = true }
camino = { workspace = true }
31 changes: 26 additions & 5 deletions src/gen/callback_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use crate::gen::oracle::{AsCodeType, DartCodeOracle};
use crate::gen::render::AsRenderable;
use crate::gen::render::{Renderable, TypeHelperRenderer};

// Removed problematic context structure - will implement simpler improvements

#[derive(Debug)]
pub struct CallbackInterfaceCodeType {
name: String,
Expand Down Expand Up @@ -199,6 +197,8 @@ fn generate_callback_methods_signatures(
tokens.append(quote! {
typedef UniffiCallbackInterface$(callback_name)Free = Void Function(Uint64);
typedef UniffiCallbackInterface$(callback_name)FreeDart = void Function(int);
typedef UniffiCallbackInterface$(callback_name)Clone = Uint64 Function(Uint64);
typedef UniffiCallbackInterface$(callback_name)CloneDart = int Function(int);
});

tokens
Expand All @@ -213,10 +213,11 @@ pub fn generate_callback_vtable_interface(

quote! {
final class $vtable_name extends Struct {
external Pointer<NativeFunction<UniffiCallbackInterface$(callback_name)Free>> uniffiFree;
external Pointer<NativeFunction<UniffiCallbackInterface$(callback_name)Clone>> uniffiClone;
$(for (index, m) in &methods_vec =>
external Pointer<NativeFunction<UniffiCallbackInterface$(callback_name)Method$(format!("{}",index))>> $(DartCodeOracle::fn_name(m.name()));
)
external Pointer<NativeFunction<UniffiCallbackInterface$(callback_name)Free>> uniffiFree;
}
}
}
Expand Down Expand Up @@ -287,6 +288,11 @@ pub fn generate_callback_functions(
let free_callback_pointer = &format!("{}FreePointer", DartCodeOracle::fn_name(callback_name));
let free_callback_type = &format!("UniffiCallbackInterface{callback_name}Free");

// Clone callback
let clone_callback_fn = &format!("{}CloneCallback", DartCodeOracle::fn_name(callback_name));
let clone_callback_pointer = &format!("{}ClonePointer", DartCodeOracle::fn_name(callback_name));
let clone_callback_type = &format!("UniffiCallbackInterface{callback_name}Clone");

quote! {
$(functions)

Expand All @@ -300,6 +306,20 @@ pub fn generate_callback_functions(

final Pointer<NativeFunction<$free_callback_type>> $free_callback_pointer =
Pointer.fromFunction<$free_callback_type>($free_callback_fn);

int $clone_callback_fn(int handle) {
try {
final obj = FfiConverterCallbackInterface$cls_name._handleMap.get(handle);
final newHandle = FfiConverterCallbackInterface$cls_name._handleMap.insert(obj);
return newHandle;
} catch (e) {
// Return 0 on error, which should trigger an error on the Rust side
return 0;
}
}

final Pointer<NativeFunction<$clone_callback_type>> $clone_callback_pointer =
Pointer.fromFunction<$clone_callback_type>($clone_callback_fn, 0);
}
}

Expand All @@ -324,13 +344,14 @@ pub fn generate_callback_interface_vtable_init_function(
}

$(&vtable_static_instance_name) = calloc<$vtable_name>();
$(&vtable_static_instance_name).ref.uniffiFree = $(format!("{}FreePointer", DartCodeOracle::fn_name(callback_name)));
$(&vtable_static_instance_name).ref.uniffiClone = $(format!("{}ClonePointer", DartCodeOracle::fn_name(callback_name)));
$(for m in methods {
$(&vtable_static_instance_name).ref.$(DartCodeOracle::fn_name(m.name())) = $(DartCodeOracle::fn_name(callback_name))$(DartCodeOracle::class_name(m.name()))Pointer;
})
$(&vtable_static_instance_name).ref.uniffiFree = $(format!("{}FreePointer", DartCodeOracle::fn_name(callback_name)));

rustCall((status) {
_UniffiLib.instance.uniffi_$(ffi_module)_fn_init_callback_vtable_$(snake_callback)(
uniffi_$(ffi_module)_fn_init_callback_vtable_$(snake_callback)(
$(vtable_static_instance_name),
);
checkCallStatus(NullRustCallStatusErrorHandler(), status);
Expand Down
2 changes: 1 addition & 1 deletion src/gen/code_type.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::fmt::Debug;
use uniffi_bindgen::backend::Literal;
use uniffi_bindgen::pipeline::general::nodes::Literal;

/// A trait tor the implementation.
pub trait CodeType: Debug {
Expand Down
13 changes: 11 additions & 2 deletions src/gen/compounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,17 @@ macro_rules! impl_renderable_for_compound {
let _inner_type_signature =
if inner_data_type.contains("Float") { "double" } else { "int" };

let inner_helper = if matches!(self.inner(), Type::Sequence { .. }) && !inner_already_registered {
self.inner().as_renderable().render_type_helper(type_helper)
// Render inner helper for Sequences and primitives that haven't been rendered yet
let inner_helper = if !inner_already_registered {
match self.inner() {
Type::Sequence { .. }
| Type::Int8 | Type::Int16 | Type::Int32 | Type::Int64
| Type::UInt8 | Type::UInt16 | Type::UInt32 | Type::UInt64
| Type::Float32 | Type::Float64 => {
self.inner().as_renderable().render_type_helper(type_helper)
}
_ => quote!()
}
} else {
quote!()
};
Expand Down
2 changes: 1 addition & 1 deletion src/gen/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::oracle::{AsCodeType, DartCodeOracle};
use super::render::{Renderable, TypeHelperRenderer};
use super::CodeType;
use genco::prelude::*;
use uniffi_bindgen::backend::Type;
use uniffi_bindgen::interface::AsType;
use uniffi_bindgen::interface::Type;

#[derive(Debug)]
pub struct CustomCodeType {
Expand Down
31 changes: 29 additions & 2 deletions src/gen/enums.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::gen::CodeType;
use genco::prelude::*;
use heck::ToLowerCamelCase;
use uniffi_bindgen::backend::Literal;
use uniffi_bindgen::interface::{AsType, Enum, Field, Type};
use uniffi_bindgen::pipeline::general::nodes::Literal;

use super::oracle::{AsCodeType, DartCodeOracle};
use super::render::{AsRenderable, Renderable, TypeHelperRenderer};
Expand Down Expand Up @@ -61,8 +61,33 @@ pub fn generate_enum(obj: &Enum, type_helper: &dyn TypeHelperRenderer) -> dart::
let dart_cls_name = &DartCodeOracle::class_name(obj.name());
let ffi_converter_name = &obj.as_codetype().ffi_converter_name();
if obj.is_flat() {
let is_error_enum = type_helper.get_ci().is_name_used_as_error(obj.name());
let implements_exception = if is_error_enum {
quote!( implements Exception)
} else {
quote!()
};

// For flat error enums, generate an error handler
let error_handler_class = if is_error_enum {
let error_handler_name = format!("{dart_cls_name}ErrorHandler");
let instance_name = dart_cls_name.to_lower_camel_case();
quote! {
class $(&error_handler_name) extends UniffiRustCallStatusErrorHandler {
@override
Exception lift(RustBuffer errorBuf) {
return $ffi_converter_name.lift(errorBuf);
}
}

final $(&error_handler_name) $(instance_name)ErrorHandler = $(&error_handler_name)();
}
} else {
quote!()
};

quote! {
enum $dart_cls_name {
enum $dart_cls_name $implements_exception {
$(for variant in obj.variants() =>
$(DartCodeOracle::enum_variant_name(variant.name())),)
;
Expand Down Expand Up @@ -103,6 +128,8 @@ pub fn generate_enum(obj: &Enum, type_helper: &dyn TypeHelperRenderer) -> dart::
return 4;
}
}

$error_handler_class
}
} else {
let mut variants = vec![];
Expand Down
28 changes: 22 additions & 6 deletions src/gen/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,28 @@ pub fn generate_function(func: &Function, type_helper: &dyn TypeHelperRenderer)

// Use centralized callback-aware argument lowering
if func.is_async() {
// For async methods returning objects, we need to convert the int pointer to Pointer<Void>
let async_lifter = if let Some(ret_type) = func.return_type() {
match ret_type {
uniffi_bindgen::interface::Type::Object { .. } => {
quote!((ptr) => $lifter(Pointer<Void>.fromAddress(ptr)))
}
_ => lifter.clone(),
}
} else {
lifter.clone()
};

quote!(
Future<$ret> $(DartCodeOracle::fn_name(func.name()))($args) {
return uniffiRustCallAsync(
() => $(DartCodeOracle::find_lib_instance()).$(func.ffi_func().name())(
() => $(func.ffi_func().name())(
$(for arg in &func.arguments() => $(DartCodeOracle::lower_arg_with_callback_handling(arg)),)
),
$(DartCodeOracle::async_poll(func, type_helper.get_ci())),
$(DartCodeOracle::async_complete(func, type_helper.get_ci())),
$(DartCodeOracle::async_free(func, type_helper.get_ci())),
$lifter,
$async_lifter,
$error_handler,
);
}
Expand All @@ -50,7 +62,7 @@ pub fn generate_function(func: &Function, type_helper: &dyn TypeHelperRenderer)
quote!(
$ret $(DartCodeOracle::fn_name(func.name()))($args) {
return rustCall((status) {
$(DartCodeOracle::find_lib_instance()).$(func.ffi_func().name())(
$(func.ffi_func().name())(
$(for arg in &func.arguments() => $(DartCodeOracle::lower_arg_with_callback_handling(arg)),) status
);
}, $error_handler);
Expand All @@ -59,9 +71,13 @@ pub fn generate_function(func: &Function, type_helper: &dyn TypeHelperRenderer)
} else {
quote!(
$ret $(DartCodeOracle::fn_name(func.name()))($args) {
return rustCall((status) => $lifter($(DartCodeOracle::find_lib_instance()).$(func.ffi_func().name())(
$(for arg in &func.arguments() => $(DartCodeOracle::lower_arg_with_callback_handling(arg)),) status
)), $error_handler);
return rustCallWithLifter(
(status) => $(func.ffi_func().name())(
$(for arg in &func.arguments() => $(DartCodeOracle::lower_arg_with_callback_handling(arg)),) status
),
$lifter,
$error_handler
);
}
)
}
Expand Down
Loading
Loading