Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kill UniFfiTag #1863

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
5 changes: 5 additions & 0 deletions examples/custom-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,9 @@ pub fn get_example_custom_type() -> ExampleCustomType {
ExampleCustomType("abadidea".to_string())
}

#[uniffi::export]
pub fn get_url(url: Option<Url>) -> Url {
url.unwrap_or_else(|| Url::parse("https://mozilla.org").unwrap())
}

uniffi::include_scaffolding!("custom-types");
2 changes: 0 additions & 2 deletions fixtures/metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@
/// on all the functionality.
#[cfg(test)]
mod tests;

pub struct UniFfiTag;
3 changes: 1 addition & 2 deletions fixtures/metadata/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
/// This entire crate is just a set of tests for metadata handling. We use a separate crate
/// for testing because the metadata handling is split up between several crates, and no crate
/// owns all the functionality.
use crate::UniFfiTag;
use uniffi_meta::*;

mod person {
Expand Down Expand Up @@ -90,7 +89,7 @@ mod test_type_ids {
use std::sync::Arc;
use uniffi_core::Lower;

fn check_type_id<T: Lower<UniFfiTag>>(correct_type: Type) {
fn check_type_id<T: Lower>(correct_type: Type) {
let buf = &mut T::TYPE_ID_META.as_ref();
assert_eq!(
uniffi_meta::read_metadata_type(buf).unwrap(),
Expand Down
6 changes: 2 additions & 4 deletions fixtures/reexport-scaffolding-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ mod tests {
use uniffi::{FfiConverter, ForeignCallback, RustBuffer, RustCallStatus, RustCallStatusCode};
use uniffi_bindgen::ComponentInterface;

struct UniFfiTag;

// Load the dynamic library that was built for this crate. The external functions from
// `uniffi_callbacks' and `uniffi_coverall` should be present.
pub fn load_library() -> Library {
Expand Down Expand Up @@ -170,7 +168,7 @@ mod tests {

let obj_id = unsafe {
coveralls_new(
<String as FfiConverter<UniFfiTag>>::lower("TestName".into()),
<String as FfiConverter>::lower("TestName".into()),
&mut call_status,
)
};
Expand All @@ -179,7 +177,7 @@ mod tests {
let name_buf = unsafe { coveralls_get_name(obj_id, &mut call_status) };
assert_eq!(call_status.code, RustCallStatusCode::Success);
assert_eq!(
<String as FfiConverter<UniFfiTag>>::try_lift(name_buf).unwrap(),
<String as FfiConverter>::try_lift(name_buf).unwrap(),
"TestName"
);

Expand Down
3 changes: 0 additions & 3 deletions uniffi/tests/ui/proc_macro_arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use std::sync::Arc;

fn main() {}

// Normally this is defined by the scaffolding code, manually define it for the UI test
pub struct UniFfiTag;

pub struct Foo;

#[uniffi::export]
Expand Down
2 changes: 1 addition & 1 deletion uniffi_bindgen/src/bindings/kotlin/templates/Types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ inline fun <T : Disposable?, R> T.use(block: (T) -> R) =
{%- when Type::Custom { module_path, name, builtin } %}
{% include "CustomTypeTemplate.kt" %}

{%- when Type::External { module_path, name, namespace, kind, tagged } %}
{%- when Type::External { module_path, name, namespace, kind } %}
{% include "ExternalTypeTemplate.kt" %}

{%- else %}
Expand Down
2 changes: 1 addition & 1 deletion uniffi_bindgen/src/bindings/python/templates/Types.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
{%- when Type::Custom { name, module_path, builtin } %}
{%- include "CustomType.py" %}

{%- when Type::External { name, module_path, namespace, kind, tagged } %}
{%- when Type::External { name, module_path, namespace, kind } %}
{%- include "ExternalTemplate.py" %}

{%- when Type::ForeignExecutor %}
Expand Down
22 changes: 0 additions & 22 deletions uniffi_bindgen/src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,28 +265,6 @@ impl ComponentInterface {
self.is_name_used_as_error(&e.name) && (fielded || used_in_foreign_interface)
}

/// Get details about all `Type::External` types.
/// Returns an iterator of (name, crate_name, kind)
pub fn iter_external_types(
&self,
) -> impl Iterator<Item = (&String, String, ExternalKind, bool)> {
self.types.iter_known_types().filter_map(|t| match t {
Type::External {
name,
module_path,
kind,
tagged,
..
} => Some((
name,
module_path.split("::").next().unwrap().to_string(),
*kind,
*tagged,
)),
_ => None,
})
}

/// Get details about all `Type::Custom` types
pub fn iter_custom_types(&self) -> impl Iterator<Item = (&String, &Type)> {
self.types.iter_known_types().filter_map(|t| match t {
Expand Down
9 changes: 3 additions & 6 deletions uniffi_bindgen/src/scaffolding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,17 @@ mod filters {

// Map a type to Rust code that specifies the FfiConverter implementation.
//
// This outputs something like `<MyStruct as Lift<crate::UniFfiTag>>`
// This outputs something like `<MyStruct as Lift>`
pub fn ffi_trait(type_: &Type, trait_name: &str) -> Result<String, askama::Error> {
Ok(match type_ {
Type::External {
name,
kind: ExternalKind::Interface,
..
} => {
format!("<::std::sync::Arc<r#{name}> as ::uniffi::{trait_name}<crate::UniFfiTag>>")
format!("<::std::sync::Arc<r#{name}> as ::uniffi::{trait_name}>")
}
_ => format!(
"<{} as ::uniffi::{trait_name}<crate::UniFfiTag>>",
type_rs(type_)?
),
_ => format!("<{} as ::uniffi::{trait_name}>", type_rs(type_)?),
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl {{ trait_impl }} {

impl Drop for {{ trait_impl }} {
fn drop(&mut self) {
{{ foreign_callback_internals }}.invoke_callback::<(), crate::UniFfiTag>(
{{ foreign_callback_internals }}.invoke_callback::<()>(
self.handle, uniffi::IDX_CALLBACK_FREE, Default::default()
)
}
Expand Down Expand Up @@ -74,7 +74,7 @@ impl r#{{ trait_name }} for {{ trait_impl }} {
let args_rbuf = uniffi::RustBuffer::from_vec(args_buf);

{#- Calling into foreign code. #}
{{ foreign_callback_internals }}.invoke_callback::<{{ meth|return_type }}, crate::UniFfiTag>(self.handle, {{ loop.index }}, args_rbuf)
{{ foreign_callback_internals }}.invoke_callback::<{{ meth|return_type }}>(self.handle, {{ loop.index }}, args_rbuf)
}
{%- endfor %}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
// Support for external types.

// Types with an external `FfiConverter`...
{% for (name, crate_name, kind, tagged) in ci.iter_external_types() %}
// The FfiConverter for `{{ name }}` is defined in `{{ crate_name }}`
// If it has its existing FfiConverter defined with a UniFFITag, it needs forwarding.
{% if tagged %}
{%- match kind %}
{%- when ExternalKind::DataClass %}
::uniffi::ffi_converter_forward!(r#{{ name }}, ::{{ crate_name|crate_name_rs }}::UniFfiTag, crate::UniFfiTag);
{%- when ExternalKind::Interface %}
::uniffi::ffi_converter_arc_forward!(r#{{ name }}, ::{{ crate_name|crate_name_rs }}::UniFfiTag, crate::UniFfiTag);
{%- endmatch %}
{% endif %}
{%- endfor %}

// We generate support for each Custom Type and the builtin type it uses.
{%- for (name, builtin) in ci.iter_custom_types() %}
::uniffi::custom_type!(r#{{ name }}, {{builtin|type_rs}});
Expand Down
6 changes: 3 additions & 3 deletions uniffi_core/src/ffi/callbackinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,9 @@ impl ForeignCallbackInternals {
}

/// Invoke a callback interface method on the foreign side and return the result
pub fn invoke_callback<R, UniFfiTag>(&self, handle: u64, method: u32, args: RustBuffer) -> R
pub fn invoke_callback<R>(&self, handle: u64, method: u32, args: RustBuffer) -> R
where
R: LiftReturn<UniFfiTag>,
R: LiftReturn,
{
let mut ret_rbuf = RustBuffer::new();
let callback = self.callback_cell.get();
Expand All @@ -189,7 +189,7 @@ impl ForeignCallbackInternals {
CallbackResult::Error => R::lift_callback_error(ret_rbuf),
CallbackResult::UnexpectedError => {
let reason = if !ret_rbuf.is_empty() {
match <String as Lift<UniFfiTag>>::try_lift(ret_rbuf) {
match <String as Lift>::try_lift(ret_rbuf) {
Ok(s) => s,
Err(e) => {
log::error!("{{ trait_name }} Error reading ret_buf: {e}");
Expand Down
16 changes: 8 additions & 8 deletions uniffi_core/src/ffi/rustcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! - Adapting the result of `Return::lower_return()` into either a return value or an
//! exception

use crate::{FfiDefault, Lower, RustBuffer, UniFfiTag};
use crate::{FfiDefault, Lower, RustBuffer};
use std::mem::MaybeUninit;
use std::panic;

Expand Down Expand Up @@ -66,7 +66,7 @@ impl RustCallStatus {
pub fn error(message: impl Into<String>) -> Self {
Self {
code: RustCallStatusCode::UnexpectedError,
error_buf: MaybeUninit::new(<String as Lower<UniFfiTag>>::lower(message.into())),
error_buf: MaybeUninit::new(<String as Lower>::lower(message.into())),
}
}
}
Expand Down Expand Up @@ -172,7 +172,7 @@ where
"Unknown panic!".to_string()
};
log::error!("Caught a panic calling rust code: {:?}", message);
<String as Lower<UniFfiTag>>::lower(message)
<String as Lower>::lower(message)
}));
if let Ok(buf) = message_result {
unsafe {
Expand Down Expand Up @@ -213,31 +213,31 @@ mod test {
fn test_rust_call() {
let mut status = create_call_status();
let return_value = rust_call(&mut status, || {
<Result<i8, TestError> as LowerReturn<UniFfiTag>>::lower_return(test_callback(0))
<Result<i8, TestError> as LowerReturn>::lower_return(test_callback(0))
});

assert_eq!(status.code, RustCallStatusCode::Success);
assert_eq!(return_value, 100);

rust_call(&mut status, || {
<Result<i8, TestError> as LowerReturn<UniFfiTag>>::lower_return(test_callback(1))
<Result<i8, TestError> as LowerReturn>::lower_return(test_callback(1))
});
assert_eq!(status.code, RustCallStatusCode::Error);
unsafe {
assert_eq!(
<TestError as Lift<UniFfiTag>>::try_lift(status.error_buf.assume_init()).unwrap(),
<TestError as Lift>::try_lift(status.error_buf.assume_init()).unwrap(),
TestError("Error".to_owned())
);
}

let mut status = create_call_status();
rust_call(&mut status, || {
<Result<i8, TestError> as LowerReturn<UniFfiTag>>::lower_return(test_callback(2))
<Result<i8, TestError> as LowerReturn>::lower_return(test_callback(2))
});
assert_eq!(status.code, RustCallStatusCode::UnexpectedError);
unsafe {
assert_eq!(
<String as Lift<UniFfiTag>>::try_lift(status.error_buf.assume_init()).unwrap(),
<String as Lift>::try_lift(status.error_buf.assume_init()).unwrap(),
"Unexpected value: 2"
);
}
Expand Down
42 changes: 18 additions & 24 deletions uniffi_core/src/ffi/rustfuture/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,11 @@ use super::{RustFutureContinuationCallback, RustFuturePoll, Scheduler};
use crate::{rust_call_with_out_status, FfiDefault, LowerReturn, RustCallStatus};

/// Wraps the actual future we're polling
struct WrappedFuture<F, T, UT>
struct WrappedFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
// Note: this could be a single enum, but that would make it easy to mess up the future pinning
// guarantee. For example you might want to call `std::mem::take()` to try to get the result,
Expand All @@ -103,12 +102,11 @@ where
result: Option<Result<T::ReturnType, RustCallStatus>>,
}

impl<F, T, UT> WrappedFuture<F, T, UT>
impl<F, T> WrappedFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
fn new(future: F) -> Self {
Self {
Expand Down Expand Up @@ -182,40 +180,38 @@ where
//
// Rust will not mark it Send by default when T::ReturnType is a raw pointer. This is promising
// that we will treat the raw pointer properly, for example by not returning it twice.
unsafe impl<F, T, UT> Send for WrappedFuture<F, T, UT>
unsafe impl<F, T> Send for WrappedFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
}

/// Future that the foreign code is awaiting
pub(super) struct RustFuture<F, T, UT>
pub(super) struct RustFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
// This Mutex should never block if our code is working correctly, since there should not be
// multiple threads calling [Self::poll] and/or [Self::complete] at the same time.
future: Mutex<WrappedFuture<F, T, UT>>,
future: Mutex<WrappedFuture<F, T>>,
continuation_data: Mutex<Scheduler>,
// UT is used as the generic parameter for [LowerReturn].
// Let's model this with PhantomData as a function that inputs a UT value.
_phantom: PhantomData<fn(UT) -> ()>,
// ????
_phantom: PhantomData<fn() -> ()>,
}

impl<F, T, UT> RustFuture<F, T, UT>
impl<F, T> RustFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
pub(super) fn new(future: F, _tag: UT) -> Arc<Self> {
pub(super) fn new(future: F) -> Arc<Self> {
Arc::new(Self {
future: Mutex::new(WrappedFuture::new(future)),
continuation_data: Mutex::new(Scheduler::new()),
Expand Down Expand Up @@ -260,12 +256,11 @@ where
}
}

impl<F, T, UT> Wake for RustFuture<F, T, UT>
impl<F, T> Wake for RustFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
fn wake(self: Arc<Self>) {
self.deref().wake()
Expand Down Expand Up @@ -295,12 +290,11 @@ pub trait RustFutureFfi<ReturnType> {
fn ffi_free(self: Arc<Self>);
}

impl<F, T, UT> RustFutureFfi<T::ReturnType> for RustFuture<F, T, UT>
impl<F, T> RustFutureFfi<T::ReturnType> for RustFuture<F, T>
where
// See rust_future_new for an explanation of these trait bounds
F: Future<Output = T> + Send + 'static,
T: LowerReturn<UT> + Send + 'static,
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
fn ffi_poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: *const ()) {
self.poll(callback, data)
Expand Down
8 changes: 3 additions & 5 deletions uniffi_core/src/ffi/rustfuture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct RustFutureHandle(*const ());
///
/// For each exported async function, UniFFI will create a scaffolding function that uses this to
/// create the [RustFutureHandle] to pass to the foreign code.
pub fn rust_future_new<F, T, UT>(future: F, tag: UT) -> RustFutureHandle
pub fn rust_future_new<F, T>(future: F) -> RustFutureHandle
where
// F is the future type returned by the exported async function. It needs to be Send + `static
// since it will move between threads for an indeterminate amount of time as the foreign
Expand All @@ -49,13 +49,11 @@ where
F: Future<Output = T> + Send + 'static,
// T is the output of the Future. It needs to implement [LowerReturn]. Also it must be Send +
// 'static for the same reason as F.
T: LowerReturn<UT> + Send + 'static,
// The UniFfiTag ZST. The Send + 'static bound is to keep rustc happy.
UT: Send + 'static,
T: LowerReturn + Send + 'static,
{
// Create a RustFuture and coerce to `Arc<dyn RustFutureFfi>`, which is what we use to
// implement the FFI
let future_ffi = RustFuture::new(future, tag) as Arc<dyn RustFutureFfi<T::ReturnType>>;
let future_ffi = RustFuture::new(future) as Arc<dyn RustFutureFfi<T::ReturnType>>;
// Box the Arc, to convert the wide pointer into a normal sized pointer so that we can pass it
// to the foreign code.
let boxed_ffi = Box::new(future_ffi);
Expand Down
Loading