From 79a0f58a72944be3ae387741b35dd5ec979ffcd3 Mon Sep 17 00:00:00 2001 From: bendk Date: Wed, 7 Feb 2024 21:54:15 +0000 Subject: [PATCH] Built artifacts of 49beceaba [ci skip] --- futures.html | 17 +++++++++++++++++ .../src/uniffi_bindgen/interface/object.rs.html | 6 +++++- .../export/trait_interface.rs.html | 12 ------------ .../interface/enum.UniffiTrait.html | 4 ++-- .../interface/function/trait.Callable.html | 2 +- .../interface/object/enum.UniffiTrait.html | 4 ++-- .../uniffi_bindgen/interface/object/index.html | 2 +- .../interface/object/struct.Constructor.html | 2 +- .../interface/object/struct.Method.html | 2 +- .../interface/struct.Constructor.html | 2 +- .../uniffi_bindgen/interface/struct.Method.html | 2 +- .../interface/trait.Callable.html | 2 +- .../trait_interface/fn.ffi_converter.html | 2 +- .../fn.gen_trait_scaffolding.html | 2 +- .../export/trait_interface/index.html | 2 +- print.html | 17 +++++++++++++++++ searchindex.js | 2 +- searchindex.json | 2 +- 18 files changed, 55 insertions(+), 29 deletions(-) diff --git a/futures.html b/futures.html index 712cec9563..4230a22ceb 100644 --- a/futures.html +++ b/futures.html @@ -206,6 +206,23 @@

Example

This code uses asyncio to drive the future to completion, while our exposed function is used with await.

In Rust Future terminology this means the foreign bindings supply the "executor" - think event-loop, or async runtime. In this example it's asyncio. There's no requirement for a Rust event loop.

There are some great API docs on the implementation that are well worth a read.

+

Exporting async trait methods

+

UniFFI is compatible with the async-trait crate and this can +be used to export trait interfaces over the FFI.

+

When using UDL, wrap your trait with the #[async_trait] attribute. In the UDL, annotate all async +methods with [Async]:

+
[Trait]
+interface SayAfterTrait {
+    [Async]
+    string say_after(u16 ms, string who);
+};
+
+

When using proc-macros, make sure to put #[uniffi::export] outside the #[async_trait] attribute:

+
#[uniffi::export]
+#[async_trait::async_trait]
+pub trait SayAfterTrait: Send + Sync {
+    async fn say_after(&self, ms: u16, who: String) -> String;
+}
diff --git a/internals/api/src/uniffi_bindgen/interface/object.rs.html b/internals/api/src/uniffi_bindgen/interface/object.rs.html index ef0f259a5a..9b475b3f27 100644 --- a/internals/api/src/uniffi_bindgen/interface/object.rs.html +++ b/internals/api/src/uniffi_bindgen/interface/object.rs.html @@ -932,6 +932,8 @@ 932 933 934 +935 +936
/* 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/. */
@@ -1539,17 +1541,19 @@
     fn from(meta: uniffi_meta::TraitMethodMetadata) -> Self {
         let ffi_name = meta.ffi_symbol_name();
         let checksum_fn_name = meta.checksum_symbol_name();
+        let is_async = meta.is_async;
         let return_type = meta.return_type.map(Into::into);
         let arguments = meta.inputs.into_iter().map(Into::into).collect();
         let ffi_func = FfiFunction {
             name: ffi_name,
+            is_async,
             ..FfiFunction::default()
         };
         Self {
             name: meta.name,
             object_name: meta.trait_name,
             object_module_path: meta.module_path,
-            is_async: false,
+            is_async,
             arguments,
             return_type,
             docstring: meta.docstring.clone(),
diff --git a/internals/api/src/uniffi_macros/export/trait_interface.rs.html b/internals/api/src/uniffi_macros/export/trait_interface.rs.html
index 6e19419495..a26f726ff8 100644
--- a/internals/api/src/uniffi_macros/export/trait_interface.rs.html
+++ b/internals/api/src/uniffi_macros/export/trait_interface.rs.html
@@ -188,12 +188,6 @@
 188
 189
 190
-191
-192
-193
-194
-195
-196
 
/* 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/. */
@@ -283,12 +277,6 @@
         .into_iter()
         .map(|item| match item {
             ImplItem::Method(sig) => {
-                if sig.is_async {
-                    return Err(syn::Error::new(
-                        sig.span,
-                        "async trait methods are not supported",
-                    ));
-                }
                 let fn_args = ExportFnArgs {
                     async_runtime: None,
                 };
diff --git a/internals/api/uniffi_bindgen/interface/enum.UniffiTrait.html b/internals/api/uniffi_bindgen/interface/enum.UniffiTrait.html
index 5e7c8d613f..a0d1022c0c 100644
--- a/internals/api/uniffi_bindgen/interface/enum.UniffiTrait.html
+++ b/internals/api/uniffi_bindgen/interface/enum.UniffiTrait.html
@@ -1,4 +1,4 @@
-UniffiTrait in uniffi_bindgen::interface - Rust
pub enum UniffiTrait {
+UniffiTrait in uniffi_bindgen::interface - Rust
pub enum UniffiTrait {
     Debug {
         fmt: Method,
     },
@@ -13,7 +13,7 @@
         hash: Method,
     },
 }
Expand description

The list of traits we support generating helper methods for.

-

Variants§

§

Debug

Fields

§

Display

Fields

§

Eq

Fields

§

Hash

Fields

§hash: Method

Implementations§

source§

impl UniffiTrait

source

pub fn iter_types(&self) -> TypeIterator<'_>

source

pub fn derive_ffi_func(&mut self) -> Result<()>

Trait Implementations§

source§

impl Checksum for UniffiTrait

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for UniffiTrait

source§

fn clone(&self) -> UniffiTrait

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for UniffiTrait

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<UniffiTraitMetadata> for UniffiTrait

source§

fn from(meta: UniffiTraitMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +

Variants§

§

Debug

Fields

§

Display

Fields

§

Eq

Fields

§

Hash

Fields

§hash: Method

Implementations§

source§

impl UniffiTrait

source

pub fn iter_types(&self) -> TypeIterator<'_>

source

pub fn derive_ffi_func(&mut self) -> Result<()>

Trait Implementations§

source§

impl Checksum for UniffiTrait

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for UniffiTrait

source§

fn clone(&self) -> UniffiTrait

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for UniffiTrait

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<UniffiTraitMetadata> for UniffiTrait

source§

fn from(meta: UniffiTraitMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/function/trait.Callable.html b/internals/api/uniffi_bindgen/interface/function/trait.Callable.html index b5c466a5ca..9126f9d9f8 100644 --- a/internals/api/uniffi_bindgen/interface/function/trait.Callable.html +++ b/internals/api/uniffi_bindgen/interface/function/trait.Callable.html @@ -12,4 +12,4 @@ fn ffi_rust_future_complete(&self, ci: &ComponentInterface) -> String { ... } fn ffi_rust_future_free(&self, ci: &ComponentInterface) -> String { ... } }
Expand description

Implemented by function-like types (Function, Method, Constructor)

-

Required Methods§

Provided Methods§

Implementations on Foreign Types§

source§

impl<T: Callable> Callable for &T

Implementors§

\ No newline at end of file +

Required Methods§

Provided Methods§

Implementations on Foreign Types§

source§

impl<T: Callable> Callable for &T

Implementors§

\ No newline at end of file diff --git a/internals/api/uniffi_bindgen/interface/object/enum.UniffiTrait.html b/internals/api/uniffi_bindgen/interface/object/enum.UniffiTrait.html index 4f89f7d6f5..fa534f00e0 100644 --- a/internals/api/uniffi_bindgen/interface/object/enum.UniffiTrait.html +++ b/internals/api/uniffi_bindgen/interface/object/enum.UniffiTrait.html @@ -1,4 +1,4 @@ -UniffiTrait in uniffi_bindgen::interface::object - Rust
pub enum UniffiTrait {
+UniffiTrait in uniffi_bindgen::interface::object - Rust
pub enum UniffiTrait {
     Debug {
         fmt: Method,
     },
@@ -13,7 +13,7 @@
         hash: Method,
     },
 }
Expand description

The list of traits we support generating helper methods for.

-

Variants§

§

Debug

Fields

§

Display

Fields

§

Eq

Fields

§

Hash

Fields

§hash: Method

Implementations§

source§

impl UniffiTrait

source

pub fn iter_types(&self) -> TypeIterator<'_>

source

pub fn derive_ffi_func(&mut self) -> Result<()>

Trait Implementations§

source§

impl Checksum for UniffiTrait

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for UniffiTrait

source§

fn clone(&self) -> UniffiTrait

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for UniffiTrait

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<UniffiTraitMetadata> for UniffiTrait

source§

fn from(meta: UniffiTraitMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +

Variants§

§

Debug

Fields

§

Display

Fields

§

Eq

Fields

§

Hash

Fields

§hash: Method

Implementations§

source§

impl UniffiTrait

source

pub fn iter_types(&self) -> TypeIterator<'_>

source

pub fn derive_ffi_func(&mut self) -> Result<()>

Trait Implementations§

source§

impl Checksum for UniffiTrait

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for UniffiTrait

source§

fn clone(&self) -> UniffiTrait

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for UniffiTrait

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<UniffiTraitMetadata> for UniffiTrait

source§

fn from(meta: UniffiTraitMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/object/index.html b/internals/api/uniffi_bindgen/interface/object/index.html index 52b1d605ef..cdfb3f8901 100644 --- a/internals/api/uniffi_bindgen/interface/object/index.html +++ b/internals/api/uniffi_bindgen/interface/object/index.html @@ -1,4 +1,4 @@ -uniffi_bindgen::interface::object - Rust
Expand description

Object definitions for a ComponentInterface.

+uniffi_bindgen::interface::object - Rust
Expand description

Object definitions for a ComponentInterface.

This module converts “interface” definitions from UDL into Object structures that can be added to a ComponentInterface, which are the main way we define stateful objects with behaviour for a UniFFI Rust Component. An Object is an opaque handle diff --git a/internals/api/uniffi_bindgen/interface/object/struct.Constructor.html b/internals/api/uniffi_bindgen/interface/object/struct.Constructor.html index 315e1b9261..b26e3e258e 100644 --- a/internals/api/uniffi_bindgen/interface/object/struct.Constructor.html +++ b/internals/api/uniffi_bindgen/interface/object/struct.Constructor.html @@ -8,7 +8,7 @@ pub(super) throws: Option<Type>, pub(super) checksum_fn_name: String, pub(super) checksum: Option<u16>, -}

Fields§

§name: String§object_name: String§object_module_path: String§arguments: Vec<Argument>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Constructor

source

pub fn name(&self) -> &str

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn is_primary_constructor(&self) -> bool

source

fn derive_ffi_func(&mut self)

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Constructor

source§

impl Checksum for Constructor

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Constructor

source§

fn clone(&self) -> Constructor

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Constructor

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<ConstructorMetadata> for Constructor

source§

fn from(meta: ConstructorMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +}

Fields§

§name: String§object_name: String§object_module_path: String§arguments: Vec<Argument>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Constructor

source

pub fn name(&self) -> &str

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn is_primary_constructor(&self) -> bool

source

fn derive_ffi_func(&mut self)

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Constructor

source§

impl Checksum for Constructor

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Constructor

source§

fn clone(&self) -> Constructor

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Constructor

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<ConstructorMetadata> for Constructor

source§

fn from(meta: ConstructorMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/object/struct.Method.html b/internals/api/uniffi_bindgen/interface/object/struct.Method.html index 1b848aa203..72cc33d8d0 100644 --- a/internals/api/uniffi_bindgen/interface/object/struct.Method.html +++ b/internals/api/uniffi_bindgen/interface/object/struct.Method.html @@ -12,7 +12,7 @@ pub(super) takes_self_by_arc: bool, pub(super) checksum_fn_name: String, pub(super) checksum: Option<u16>, -
}

Fields§

§name: String§object_name: String§object_module_path: String§is_async: bool§object_impl: ObjectImpl§arguments: Vec<Argument>§return_type: Option<Type>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§takes_self_by_arc: bool§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Method

source

pub fn name(&self) -> &str

source

pub fn is_async(&self) -> bool

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn return_type(&self) -> Option<&Type>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn takes_self_by_arc(&self) -> bool

source

pub fn derive_ffi_func(&mut self) -> Result<()>

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Method

source§

impl Checksum for Method

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Method

source§

fn clone(&self) -> Method

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Method

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<MethodMetadata> for Method

source§

fn from(meta: MethodMetadata) -> Self

Converts to this type from the input type.
source§

impl From<TraitMethodMetadata> for Method

source§

fn from(meta: TraitMethodMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +

}

Fields§

§name: String§object_name: String§object_module_path: String§is_async: bool§object_impl: ObjectImpl§arguments: Vec<Argument>§return_type: Option<Type>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§takes_self_by_arc: bool§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Method

source

pub fn name(&self) -> &str

source

pub fn is_async(&self) -> bool

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn return_type(&self) -> Option<&Type>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn takes_self_by_arc(&self) -> bool

source

pub fn derive_ffi_func(&mut self) -> Result<()>

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Method

source§

impl Checksum for Method

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Method

source§

fn clone(&self) -> Method

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Method

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<MethodMetadata> for Method

source§

fn from(meta: MethodMetadata) -> Self

Converts to this type from the input type.
source§

impl From<TraitMethodMetadata> for Method

source§

fn from(meta: TraitMethodMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/struct.Constructor.html b/internals/api/uniffi_bindgen/interface/struct.Constructor.html index ea657d60ec..7643f91934 100644 --- a/internals/api/uniffi_bindgen/interface/struct.Constructor.html +++ b/internals/api/uniffi_bindgen/interface/struct.Constructor.html @@ -8,7 +8,7 @@ pub(super) throws: Option<Type>, pub(super) checksum_fn_name: String, pub(super) checksum: Option<u16>, -}

Fields§

§name: String§object_name: String§object_module_path: String§arguments: Vec<Argument>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Constructor

source

pub fn name(&self) -> &str

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn is_primary_constructor(&self) -> bool

source

fn derive_ffi_func(&mut self)

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Constructor

source§

impl Checksum for Constructor

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Constructor

source§

fn clone(&self) -> Constructor

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Constructor

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<ConstructorMetadata> for Constructor

source§

fn from(meta: ConstructorMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +}

Fields§

§name: String§object_name: String§object_module_path: String§arguments: Vec<Argument>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Constructor

source

pub fn name(&self) -> &str

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn is_primary_constructor(&self) -> bool

source

fn derive_ffi_func(&mut self)

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Constructor

source§

impl Checksum for Constructor

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Constructor

source§

fn clone(&self) -> Constructor

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Constructor

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<ConstructorMetadata> for Constructor

source§

fn from(meta: ConstructorMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/struct.Method.html b/internals/api/uniffi_bindgen/interface/struct.Method.html index 636507bf3d..68a2b3f226 100644 --- a/internals/api/uniffi_bindgen/interface/struct.Method.html +++ b/internals/api/uniffi_bindgen/interface/struct.Method.html @@ -12,7 +12,7 @@ pub(super) takes_self_by_arc: bool, pub(super) checksum_fn_name: String, pub(super) checksum: Option<u16>, -
}

Fields§

§name: String§object_name: String§object_module_path: String§is_async: bool§object_impl: ObjectImpl§arguments: Vec<Argument>§return_type: Option<Type>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§takes_self_by_arc: bool§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Method

source

pub fn name(&self) -> &str

source

pub fn is_async(&self) -> bool

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn return_type(&self) -> Option<&Type>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn takes_self_by_arc(&self) -> bool

source

pub fn derive_ffi_func(&mut self) -> Result<()>

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Method

source§

impl Checksum for Method

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Method

source§

fn clone(&self) -> Method

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Method

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<MethodMetadata> for Method

source§

fn from(meta: MethodMetadata) -> Self

Converts to this type from the input type.
source§

impl From<TraitMethodMetadata> for Method

source§

fn from(meta: TraitMethodMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere +

}

Fields§

§name: String§object_name: String§object_module_path: String§is_async: bool§object_impl: ObjectImpl§arguments: Vec<Argument>§return_type: Option<Type>§ffi_func: FfiFunction§docstring: Option<String>§throws: Option<Type>§takes_self_by_arc: bool§checksum_fn_name: String§checksum: Option<u16>

Implementations§

source§

impl Method

source

pub fn name(&self) -> &str

source

pub fn is_async(&self) -> bool

source

pub fn arguments(&self) -> Vec<&Argument>

source

pub fn full_arguments(&self) -> Vec<Argument>

source

pub fn return_type(&self) -> Option<&Type>

source

pub fn ffi_func(&self) -> &FfiFunction

source

pub fn checksum_fn_name(&self) -> &str

source

pub fn checksum(&self) -> u16

source

pub fn throws(&self) -> bool

source

pub fn throws_name(&self) -> Option<&str>

source

pub fn throws_type(&self) -> Option<&Type>

source

pub fn docstring(&self) -> Option<&str>

source

pub fn takes_self_by_arc(&self) -> bool

source

pub fn derive_ffi_func(&mut self) -> Result<()>

source

pub fn iter_types(&self) -> TypeIterator<'_>

Trait Implementations§

source§

impl Callable for Method

source§

impl Checksum for Method

source§

fn checksum<__H: Hasher>(&self, state: &mut __H)

source§

impl Clone for Method

source§

fn clone(&self) -> Method

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Method

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<MethodMetadata> for Method

source§

fn from(meta: MethodMetadata) -> Self

Converts to this type from the input type.
source§

impl From<TraitMethodMetadata> for Method

source§

fn from(meta: TraitMethodMetadata) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/internals/api/uniffi_bindgen/interface/trait.Callable.html b/internals/api/uniffi_bindgen/interface/trait.Callable.html index 532ae7a04d..82f8faee6f 100644 --- a/internals/api/uniffi_bindgen/interface/trait.Callable.html +++ b/internals/api/uniffi_bindgen/interface/trait.Callable.html @@ -12,4 +12,4 @@ fn ffi_rust_future_complete(&self, ci: &ComponentInterface) -> String { ... } fn ffi_rust_future_free(&self, ci: &ComponentInterface) -> String { ... } }
Expand description

Implemented by function-like types (Function, Method, Constructor)

-

Required Methods§

Provided Methods§

Implementations on Foreign Types§

source§

impl<T: Callable> Callable for &T

Implementors§

\ No newline at end of file +

Required Methods§

Provided Methods§

Implementations on Foreign Types§

source§

impl<T: Callable> Callable for &T

Implementors§

\ No newline at end of file diff --git a/internals/api/uniffi_macros/export/trait_interface/fn.ffi_converter.html b/internals/api/uniffi_macros/export/trait_interface/fn.ffi_converter.html index 5e25ccc375..81403eb1c8 100644 --- a/internals/api/uniffi_macros/export/trait_interface/fn.ffi_converter.html +++ b/internals/api/uniffi_macros/export/trait_interface/fn.ffi_converter.html @@ -1,4 +1,4 @@ -ffi_converter in uniffi_macros::export::trait_interface - Rust
pub(crate) fn ffi_converter(
+ffi_converter in uniffi_macros::export::trait_interface - Rust
pub(crate) fn ffi_converter(
     mod_path: &str,
     trait_ident: &Ident,
     udl_mode: bool,
diff --git a/internals/api/uniffi_macros/export/trait_interface/fn.gen_trait_scaffolding.html b/internals/api/uniffi_macros/export/trait_interface/fn.gen_trait_scaffolding.html
index e14312a4b3..35f54eb7bc 100644
--- a/internals/api/uniffi_macros/export/trait_interface/fn.gen_trait_scaffolding.html
+++ b/internals/api/uniffi_macros/export/trait_interface/fn.gen_trait_scaffolding.html
@@ -1,4 +1,4 @@
-gen_trait_scaffolding in uniffi_macros::export::trait_interface - Rust
pub(super) fn gen_trait_scaffolding(
+gen_trait_scaffolding in uniffi_macros::export::trait_interface - Rust
pub(super) fn gen_trait_scaffolding(
     mod_path: &str,
     args: ExportTraitArgs,
     self_ident: Ident,
diff --git a/internals/api/uniffi_macros/export/trait_interface/index.html b/internals/api/uniffi_macros/export/trait_interface/index.html
index 68393e38c6..e34b4c84e6 100644
--- a/internals/api/uniffi_macros/export/trait_interface/index.html
+++ b/internals/api/uniffi_macros/export/trait_interface/index.html
@@ -1 +1 @@
-uniffi_macros::export::trait_interface - Rust
\ No newline at end of file +uniffi_macros::export::trait_interface - Rust
\ No newline at end of file diff --git a/print.html b/print.html index 9d8769c48b..af504ca095 100644 --- a/print.html +++ b/print.html @@ -1637,6 +1637,23 @@

Example

This code uses asyncio to drive the future to completion, while our exposed function is used with await.

In Rust Future terminology this means the foreign bindings supply the "executor" - think event-loop, or async runtime. In this example it's asyncio. There's no requirement for a Rust event loop.

There are some great API docs on the implementation that are well worth a read.

+

Exporting async trait methods

+

UniFFI is compatible with the async-trait crate and this can +be used to export trait interfaces over the FFI.

+

When using UDL, wrap your trait with the #[async_trait] attribute. In the UDL, annotate all async +methods with [Async]:

+
[Trait]
+interface SayAfterTrait {
+    [Async]
+    string say_after(u16 ms, string who);
+};
+
+

When using proc-macros, make sure to put #[uniffi::export] outside the #[async_trait] attribute:

+
#[uniffi::export]
+#[async_trait::async_trait]
+pub trait SayAfterTrait: Send + Sync {
+    async fn say_after(&self, ms: u16, who: String) -> String;
+}

Generating bindings

Bindings is the term used for the code generates for foreign languages which integrate with Rust crates - that is, the generated Python, Swift or Kotlin code which drives the diff --git a/searchindex.js b/searchindex.js index 0f9aed0114..6bcf675302 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Object.assign(window.search, {"doc_urls":["Overview.html#uniffi","Overview.html#design","Overview.html#supported-languages","Overview.html#third-party-foreign-language-bindings","Motivation.html#what","Motivation.html#how","Motivation.html#why","Motivation.html#why-not","Getting_started.html#getting-started","tutorial/Prerequisites.html#prerequisites","tutorial/Prerequisites.html#add-uniffi-as-a-dependency-and-build-dependency","tutorial/Prerequisites.html#build-your-crate-as-a-cdylib","tutorial/udl_file.html#the-udl-file","tutorial/Rust_scaffolding.html#rust-scaffolding","tutorial/Rust_scaffolding.html#rust-scaffolding-code","tutorial/Rust_scaffolding.html#setup-for-crates-using-udl","tutorial/Rust_scaffolding.html#setup-for-crates-using-only-proc-macros","tutorial/Rust_scaffolding.html#libraries-that-depend-on-uniffi-components","tutorial/foreign_language_bindings.html#foreign-language-bindings","tutorial/foreign_language_bindings.html#creating-the-bindgen-binary","tutorial/foreign_language_bindings.html#multi-crate-workspaces","tutorial/foreign_language_bindings.html#running-uniffi-bindgen-using-a-library-file-recommended","tutorial/foreign_language_bindings.html#running-uniffi-bindgen-with-a-single-udl-file","tutorial/foreign_language_bindings.html#kotlin","tutorial/foreign_language_bindings.html#swift","udl_file_spec.html#the-udl-file","udl/namespace.html#namespace","udl/builtin_types.html#built-in-types","udl/enumerations.html#enumerations","udl/enumerations.html#enums-with-fields","udl/enumerations.html#remote-non-exhaustive-enums","udl/structs.html#structsdictionaries","udl/structs.html#fields-holding-object-references","udl/structs.html#default-values-for-fields","udl/structs.html#optional-fields-and-default-values","udl/functions.html#functions","udl/functions.html#optional-arguments--default-values","udl/functions.html#async","udl/errors.html#throwing-errors","udl/interfaces.html#interfacesobjects","udl/interfaces.html#exposing-traits-as-interfaces","udl/interfaces.html#foreign-implementations","udl/interfaces.html#traits-construction","udl/interfaces.html#traits-example","udl/interfaces.html#alternate-named-constructors","udl/interfaces.html#exposing-methods-from-standard-rust-traits","udl/interfaces.html#managing-shared-references","udl/interfaces.html#concurrent-access","udl/callback_interfaces.html#callback-interfaces","udl/callback_interfaces.html#defining-a-callback","udl/callback_interfaces.html#box-and-send--sync","udl/callback_interfaces.html#rust-signature-differences","udl/ext_types.html#external-types","udl/ext_types.html#types-in-another-crate","udl/ext_types.html#types-from-procmacros-in-this-crate","udl/ext_types_external.html#declaring-external-types","udl/ext_types_external.html#external-interface-and-trait-types","udl/ext_types_external.html#external-procmacro-types","udl/ext_types_external.html#foreign-bindings","udl/ext_types_external.html#kotlin","udl/ext_types_external.html#swift","udl/custom_types.html#custom-types","udl/custom_types.html#custom-types-in-the-scaffolding-code","udl/custom_types.html#error-handling-during-conversion","udl/custom_types.html#example","udl/custom_types.html#custom-types-in-the-bindings-code","udl/custom_types.html#using-custom-types-from-other-crates","udl/docstrings.html#docstrings","udl/docstrings.html#docstrings-in-udl","udl/docstrings.html#docstrings-in-generated-kotlin-bindings","udl/docstrings.html#docstrings-in-generated-swift-bindings","udl/docstrings.html#docstrings-in-generated-python-bindings","proc_macro/index.html#procedural-macros-attributes-and-derives","proc_macro/index.html#build-workflow","proc_macro/index.html#the-uniffiexport-attribute","proc_macro/index.html#the-uniffirecord-derive","proc_macro/index.html#the-uniffienum-derive","proc_macro/index.html#the-uniffiobject-derive","proc_macro/index.html#the-unifficustom_type-and-unifficustom_newtype-macros","proc_macro/index.html#the-uniffierror-derive","proc_macro/index.html#the-uniffiexportcallback_interface-attribute","proc_macro/index.html#types-from-dependent-crates","proc_macro/index.html#types-from-udl-based-dependent-crates","proc_macro/index.html#non-uniffi-types-from-dependent-crates","proc_macro/index.html#other-limitations","futures.html#asyncfuture-support","futures.html#example","bindings.html#generating-bindings","bindings.html#customizing-the-binding-generation","bindings.html#generating-bindings","bindings.html#customizing-the-binding-generation","foreign_traits.html#foreign-traits","foreign_traits.html#example","foreign_traits.html#1-define-a-rust-trait","foreign_traits.html#2-allow-it-to-be-passed-into-rust","foreign_traits.html#3-create-a-foreign-language-implementation-of-the-trait","foreign_traits.html#4-pass-the-implementation-to-rust","foreign_traits.html#--avoid-cycles","foreign_traits.html#error-handling","foreign_traits.html#unexpected-error-handling","kotlin/configuration.html#configuration","kotlin/configuration.html#available-options","kotlin/configuration.html#example","kotlin/gradle.html#integrating-with-gradle","kotlin/gradle.html#using-experimental-unsigned-types","kotlin/gradle.html#update","kotlin/gradle.html#jna-dependency","kotlin/gradle.html#coroutines-dependency","kotlin/lifetimes.html#kotlin-lifetimes","kotlin/lifetimes.html#nested-objects","swift/overview.html#swift-bindings","swift/configuration.html#configuration","swift/configuration.html#available-options","swift/configuration.html#example","swift/module.html#compiling-a-swift-module","swift/xcode.html#integrating-with-xcode","swift/xcode.html#compiling-the-rust-crate","swift/xcode.html#generating-the-bindings","swift/xcode.html#including-the-bridging-header","python/configuration.html#configuration","python/configuration.html#available-options","python/configuration.html#external-packages","python/configuration.html#default-value","python/configuration.html#specified-value","python/configuration.html#examples","internals/design_principles.html#design-principles","internals/design_principles.html#prioritize-mozillas-short-term-needs","internals/design_principles.html#safety-first","internals/design_principles.html#performance-is-a-feature-but-not-a-deal-breaker","internals/design_principles.html#produce-bindings-that-feel-idiomatic-for-the-target-language","internals/design_principles.html#empower-users-to-debug-and-maintain-the-tool","internals/crates.html#navigating-the-code","internals/lifting_and_lowering.html#lifting-lowering-and-serialization","internals/lifting_and_lowering.html#lowered-types","internals/lifting_and_lowering.html#serialization-format","internals/lifting_and_lowering.html#code-generation-and-the-fficonverter-trait","internals/object_references.html#managing-object-references","internals/object_references.html#concurrency","internals/object_references.html#lifetimes","internals/rendering_foreign_bindings.html#rendering-foreign-bindings","internals/rendering_foreign_bindings.html#the-askama-template-engine","internals/rendering_foreign_bindings.html#type-matching","internals/rendering_foreign_bindings.html#askama-extensions","internals/rendering_foreign_bindings.html#adding-imports","internals/rendering_foreign_bindings.html#including-templates-once"],"index":{"documentStore":{"docInfo":{"0":{"body":44,"breadcrumbs":2,"title":1},"1":{"body":46,"breadcrumbs":2,"title":1},"10":{"body":25,"breadcrumbs":7,"title":5},"100":{"body":8,"breadcrumbs":3,"title":1},"101":{"body":95,"breadcrumbs":4,"title":2},"102":{"body":49,"breadcrumbs":3,"title":1},"103":{"body":79,"breadcrumbs":6,"title":2},"104":{"body":59,"breadcrumbs":8,"title":4},"105":{"body":23,"breadcrumbs":5,"title":1},"106":{"body":17,"breadcrumbs":6,"title":2},"107":{"body":20,"breadcrumbs":6,"title":2},"108":{"body":56,"breadcrumbs":6,"title":2},"109":{"body":34,"breadcrumbs":6,"title":2},"11":{"body":22,"breadcrumbs":5,"title":3},"110":{"body":257,"breadcrumbs":4,"title":2},"111":{"body":8,"breadcrumbs":4,"title":1},"112":{"body":99,"breadcrumbs":5,"title":2},"113":{"body":5,"breadcrumbs":4,"title":1},"114":{"body":126,"breadcrumbs":8,"title":3},"115":{"body":51,"breadcrumbs":6,"title":2},"116":{"body":45,"breadcrumbs":7,"title":3},"117":{"body":108,"breadcrumbs":6,"title":2},"118":{"body":38,"breadcrumbs":7,"title":3},"119":{"body":8,"breadcrumbs":3,"title":1},"12":{"body":127,"breadcrumbs":5,"title":2},"120":{"body":41,"breadcrumbs":4,"title":2},"121":{"body":42,"breadcrumbs":4,"title":2},"122":{"body":58,"breadcrumbs":4,"title":2},"123":{"body":45,"breadcrumbs":4,"title":2},"124":{"body":42,"breadcrumbs":3,"title":1},"125":{"body":13,"breadcrumbs":4,"title":2},"126":{"body":24,"breadcrumbs":7,"title":5},"127":{"body":115,"breadcrumbs":4,"title":2},"128":{"body":115,"breadcrumbs":6,"title":4},"129":{"body":84,"breadcrumbs":8,"title":6},"13":{"body":0,"breadcrumbs":7,"title":2},"130":{"body":111,"breadcrumbs":7,"title":5},"131":{"body":135,"breadcrumbs":4,"title":2},"132":{"body":257,"breadcrumbs":6,"title":3},"133":{"body":85,"breadcrumbs":5,"title":2},"134":{"body":187,"breadcrumbs":5,"title":2},"135":{"body":148,"breadcrumbs":7,"title":4},"136":{"body":79,"breadcrumbs":6,"title":3},"137":{"body":59,"breadcrumbs":4,"title":1},"138":{"body":247,"breadcrumbs":4,"title":1},"139":{"body":10,"breadcrumbs":6,"title":3},"14":{"body":70,"breadcrumbs":8,"title":3},"140":{"body":46,"breadcrumbs":6,"title":3},"141":{"body":260,"breadcrumbs":5,"title":2},"142":{"body":12,"breadcrumbs":5,"title":2},"143":{"body":72,"breadcrumbs":5,"title":2},"144":{"body":41,"breadcrumbs":6,"title":3},"15":{"body":32,"breadcrumbs":9,"title":4},"16":{"body":31,"breadcrumbs":10,"title":5},"17":{"body":74,"breadcrumbs":9,"title":4},"18":{"body":13,"breadcrumbs":8,"title":3},"19":{"body":64,"breadcrumbs":8,"title":3},"2":{"body":4,"breadcrumbs":3,"title":2},"20":{"body":56,"breadcrumbs":8,"title":3},"21":{"body":124,"breadcrumbs":12,"title":7},"22":{"body":8,"breadcrumbs":11,"title":6},"23":{"body":14,"breadcrumbs":6,"title":1},"24":{"body":24,"breadcrumbs":6,"title":1},"25":{"body":41,"breadcrumbs":4,"title":2},"26":{"body":36,"breadcrumbs":4,"title":1},"27":{"body":74,"breadcrumbs":6,"title":2},"28":{"body":15,"breadcrumbs":4,"title":1},"29":{"body":51,"breadcrumbs":5,"title":2},"3":{"body":6,"breadcrumbs":6,"title":5},"30":{"body":60,"breadcrumbs":7,"title":4},"31":{"body":62,"breadcrumbs":4,"title":1},"32":{"body":85,"breadcrumbs":7,"title":4},"33":{"body":39,"breadcrumbs":6,"title":3},"34":{"body":69,"breadcrumbs":7,"title":4},"35":{"body":25,"breadcrumbs":4,"title":1},"36":{"body":51,"breadcrumbs":7,"title":4},"37":{"body":16,"breadcrumbs":4,"title":1},"38":{"body":84,"breadcrumbs":7,"title":2},"39":{"body":160,"breadcrumbs":4,"title":1},"4":{"body":54,"breadcrumbs":1,"title":0},"40":{"body":90,"breadcrumbs":6,"title":3},"41":{"body":30,"breadcrumbs":5,"title":2},"42":{"body":6,"breadcrumbs":5,"title":2},"43":{"body":4,"breadcrumbs":5,"title":2},"44":{"body":66,"breadcrumbs":6,"title":3},"45":{"body":90,"breadcrumbs":8,"title":5},"46":{"body":230,"breadcrumbs":6,"title":3},"47":{"body":214,"breadcrumbs":5,"title":2},"48":{"body":30,"breadcrumbs":6,"title":2},"49":{"body":15,"breadcrumbs":6,"title":2},"5":{"body":133,"breadcrumbs":1,"title":0},"50":{"body":26,"breadcrumbs":7,"title":3},"51":{"body":30,"breadcrumbs":7,"title":3},"52":{"body":27,"breadcrumbs":6,"title":2},"53":{"body":3,"breadcrumbs":7,"title":3},"54":{"body":49,"breadcrumbs":7,"title":3},"55":{"body":89,"breadcrumbs":10,"title":3},"56":{"body":16,"breadcrumbs":11,"title":4},"57":{"body":32,"breadcrumbs":10,"title":3},"58":{"body":11,"breadcrumbs":9,"title":2},"59":{"body":53,"breadcrumbs":8,"title":1},"6":{"body":24,"breadcrumbs":1,"title":0},"60":{"body":16,"breadcrumbs":8,"title":1},"61":{"body":25,"breadcrumbs":9,"title":2},"62":{"body":108,"breadcrumbs":11,"title":4},"63":{"body":61,"breadcrumbs":11,"title":4},"64":{"body":76,"breadcrumbs":8,"title":1},"65":{"body":137,"breadcrumbs":11,"title":4},"66":{"body":22,"breadcrumbs":11,"title":4},"67":{"body":43,"breadcrumbs":4,"title":1},"68":{"body":27,"breadcrumbs":5,"title":2},"69":{"body":27,"breadcrumbs":7,"title":4},"7":{"body":106,"breadcrumbs":1,"title":0},"70":{"body":30,"breadcrumbs":7,"title":4},"71":{"body":28,"breadcrumbs":7,"title":4},"72":{"body":116,"breadcrumbs":8,"title":4},"73":{"body":37,"breadcrumbs":6,"title":2},"74":{"body":165,"breadcrumbs":6,"title":2},"75":{"body":79,"breadcrumbs":6,"title":2},"76":{"body":78,"breadcrumbs":6,"title":2},"77":{"body":76,"breadcrumbs":6,"title":2},"78":{"body":96,"breadcrumbs":7,"title":3},"79":{"body":123,"breadcrumbs":6,"title":2},"8":{"body":26,"breadcrumbs":3,"title":2},"80":{"body":34,"breadcrumbs":6,"title":2},"81":{"body":19,"breadcrumbs":7,"title":3},"82":{"body":20,"breadcrumbs":9,"title":5},"83":{"body":24,"breadcrumbs":9,"title":5},"84":{"body":24,"breadcrumbs":5,"title":1},"85":{"body":28,"breadcrumbs":5,"title":2},"86":{"body":93,"breadcrumbs":4,"title":1},"87":{"body":29,"breadcrumbs":3,"title":2},"88":{"body":47,"breadcrumbs":4,"title":3},"89":{"body":29,"breadcrumbs":6,"title":2},"9":{"body":0,"breadcrumbs":3,"title":1},"90":{"body":47,"breadcrumbs":7,"title":3},"91":{"body":36,"breadcrumbs":8,"title":2},"92":{"body":5,"breadcrumbs":7,"title":1},"93":{"body":77,"breadcrumbs":10,"title":4},"94":{"body":38,"breadcrumbs":10,"title":4},"95":{"body":38,"breadcrumbs":12,"title":6},"96":{"body":24,"breadcrumbs":10,"title":4},"97":{"body":37,"breadcrumbs":8,"title":2},"98":{"body":15,"breadcrumbs":8,"title":2},"99":{"body":47,"breadcrumbs":9,"title":3}},"docs":{"0":{"body":"UniFFI is a tool that automatically generates foreign-language bindings targeting Rust libraries. The repository can be found on github . It fits in the practice of consolidating business logic in a single Rust library while targeting multiple platforms, making it simpler to develop and maintain a cross-platform codebase. Note that this tool will not help you ship a Rust library to these platforms, but simply not have to write bindings code by hand. Related .","breadcrumbs":"Overview » UniFFI","id":"0","title":"UniFFI"},"1":{"body":"UniFFI requires to write an Interface Definition Language (based on WebIDL ) file describing the methods and data structures available to the targeted languages. This .udl (UniFFI Definition Language) file, whose definitions must match with the exposed Rust code, is then used to generate Rust scaffolding code and foreign-languages bindings . This process can take place either during the build process or be manually initiated by the developer. uniffi diagram","breadcrumbs":"Overview » Design","id":"1","title":"Design"},"10":{"body":"In your crate's Cargo.toml add: [dependencies]\nuniffi = { version = \"[latest-version]\" } [build-dependencies]\nuniffi = { version = \"[latest-version]\", features = [ \"build\" ] } UniFFI has not reached version 1.0 yet. Versions are typically specified as 0.[minor-version].","breadcrumbs":"Tutorial » Prerequisites » Add uniffi as a dependency and build-dependency","id":"10","title":"Add uniffi as a dependency and build-dependency"},"100":{"body":"The generated Kotlin modules can be configured using a uniffi.toml configuration file.","breadcrumbs":"Bindings » Kotlin » Configuration","id":"100","title":"Configuration"},"101":{"body":"Configuration name Default Description package_name uniffi The Kotlin package name - ie, the value used in the package statement at the top of generated files. cdylib_name uniffi_{namespace} [1] The name of the compiled Rust library containing the FFI implementation (not needed when using generate --library). generate_immutable_records false Whether to generate records with immutable fields (val instead of var). custom_types A map which controls how custom types are exposed to Kotlin. See the custom types section of the manual external_packages A map of packages to be used for the specified external crates. The key is the Rust crate name, the value is the Kotlin package which will be used referring to types in that crate. See the external types section of the manual android false Used to toggle on Android specific optimizations android_cleaner android Use the android.system.SystemCleaner instead of java.lang.ref.Cleaner . Fallback in both instances is the one shipped with JNA.","breadcrumbs":"Bindings » Kotlin » Available options","id":"101","title":"Available options"},"102":{"body":"Custom types # Assuming a Custom Type named URL using a String as the builtin.\n[bindings.kotlin.custom_types.Url]\n# Name of the type in the Kotlin code\ntype_name = \"URL\"\n# Classes that need to be imported\nimports = [ \"java.net.URI\", \"java.net.URL\" ]\n# Functions to convert between strings and URLs\ninto_custom = \"URI({}).toURL()\"\nfrom_custom = \"{}.toString()\" External types [bindings.kotlin.external_packages]\n# This specifies that external types from the crate `rust-crate-name` will be referred by by the package `\"kotlin.package.name`.\nrust-crate-name = \"kotlin.package.name\"","breadcrumbs":"Bindings » Kotlin » Example","id":"102","title":"Example"},"103":{"body":"It is possible to generate Kotlin bindings at compile time for Kotlin Android projects. We'd like to make a gradle plugin for that, but until then you can add to your build.gradle the following: android.libraryVariants.all { variant -> def t = tasks.register(\"generate${variant.name.capitalize()}UniFFIBindings\", Exec) { workingDir \"${project.projectDir}\" // Runs the bindings generation, note that you must have uniffi-bindgen installed and in your PATH environment variable commandLine 'uniffi-bindgen', 'generate', '', '--language', 'kotlin', '--out-dir', \"${buildDir}/generated/source/uniffi/${variant.name}/java\" } variant.javaCompileProvider.get().dependsOn(t) def sourceSet = variant.sourceSets.find { it.name == variant.name } sourceSet.java.srcDir new File(buildDir, \"generated/source/uniffi/${variant.name}/java\") // XXX: I've been trying to make this work but I can't, so the compiled bindings will show as \"regular sources\" in Android Studio. idea.module.generatedSourceDirs += file(\"${buildDir}/generated/source/uniffi/${variant.name}/java/uniffi\")\n} The generated bindings should appear in the project sources in Android Studio.","breadcrumbs":"Bindings » Kotlin » Integrating with Gradle » Integrating with Gradle","id":"103","title":"Integrating with Gradle"},"104":{"body":"Unsigned integers in the defined API are translated to their equivalents in the foreign language binding, e.g. u32 becomes Kotlin's UInt type. See Built-in types . However unsigned integer types are experimental in Kotlin versions prior to 1.5. As such they require explicit annotations to suppress warnings. Uniffi is trying to add these annotations where necessary, but currently misses some places, see PR #977 for details. To suppress all warnings for experimental unsigned types add this to your project's build.gradle file: allprojects { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions { freeCompilerArgs += [ \"-Xuse-experimental=kotlin.ExperimentalUnsignedTypes\", ] } }\n}","breadcrumbs":"Bindings » Kotlin » Integrating with Gradle » Using experimental unsigned types","id":"104","title":"Using experimental unsigned types"},"105":{"body":"As of PR #993 , the Kotlin backend was refactored, and it became harder to support the @ExperimentalUnsignedTypes annotation. Uniffi's Android customers are rapidly moving toward Kotlin 1.5, so adding this compiler arg is no longer necessary.","breadcrumbs":"Bindings » Kotlin » Integrating with Gradle » Update","id":"105","title":"Update"},"106":{"body":"UniFFI relies on JNA for the ability to call native methods. JNA 5.12.0 or greater is required. Set the dependency in your build.gradle: dependencies { implementation \"net.java.dev.jna:jna:5.12.0@aar\"\n}","breadcrumbs":"Bindings » Kotlin » Integrating with Gradle » JNA dependency","id":"106","title":"JNA dependency"},"107":{"body":"UniFFI relies on kotlinx coroutines core for future and async support. Version 1.6 or greater is required. Set the dependency in your build.gradle: dependencies { implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4\"\n}","breadcrumbs":"Bindings » Kotlin » Integrating with Gradle » Coroutines dependency","id":"107","title":"Coroutines dependency"},"108":{"body":"All interfaces exposed via Kotlin expose a public API for freeing the Kotlin wrapper object in lieu of reliable finalizers. This is done by making the \"base class\" for all such generated objects implement the Disposable and AutoCloseable interfaces. As such, these wrappers all implement a close() method, which must be explicitly called to ensure the associated Rust resources are reclaimed. The best way to arrange for this to be called at the right time is beyond the scope of this document; you should consult the official documentation for AutoClosable, but one common pattern is the Kotlin use function .","breadcrumbs":"Bindings » Kotlin » Kotlin Lifetimes » Kotlin Lifetimes","id":"108","title":"Kotlin Lifetimes"},"109":{"body":"We also need to consider what happens when objects are contained in other objects. The current situation is: Dictionaries that contain interfaces implement AutoClosable with their close() method closing any contained interfaces. Enums can't currently contain interfaces. Lists/Maps don't implement AutoClosable; if you have a list/map of interfaces you need to close each one individually.","breadcrumbs":"Bindings » Kotlin » Kotlin Lifetimes » Nested objects","id":"109","title":"Nested objects"},"11":{"body":"Ensure your crate builds as a cdylib by adding [lib]\ncrate-type = [\"cdylib\"]\nname = \"\" to your crate's Cargo.toml. Note: You also need to add staticlib crate type if you target iOS.","breadcrumbs":"Tutorial » Prerequisites » Build your crate as a cdylib","id":"11","title":"Build your crate as a cdylib"},"110":{"body":"UniFFI ships with production-quality support for generating Swift bindings. Concepts from the UDL file map into Swift as follows: Primitive datatypes map to their obvious Swift counterpart, e.g. u32 becomes UInt32, string becomes String, bytes becomes Data, etc. An object interface declared as interface T is represented as a Swift protocol TProtocol and a concrete Swift class T that conforms to it. Having the protocol declared explicitly can be useful for mocking instances of the class in unittests. A dictionary struct declared as dictionary T is represented as a Swift struct T with public mutable fields. An enum declared enum T or [Enum] interface T is represented as a Swift enum T with appropriate variants. Optional types are represented using Swift's builtin optional type syntax T?. Sequences are represented as Swift arrays, and Maps as Swift dictionaries. Errors are represented as Swift enums that conform to the Error protocol. Function calls that have an associated error type are marked with throws, and hence must be called using one of Swift's try syntax variants. Failing assertions, Rust panics, and other unexpected errors in the generated code are translated into a private enum conforming to the Error protocol. If this happens inside a throwing Swift function, it can be caught and handled by a catch-all catch statement (but do so at your own risk, because it indicates that something has gone seriously wrong). If this happens inside a non-throwing Swift function, it will be converted into a fatal Swift error that cannot be caught. Conceptually, the generated bindings are split into two Swift modules, one for the low-level C FFI layer and one for the higher-level Swift bindings. For a UniFFI component named \"example\" we generate: A C header file exampleFFI.h declaring the low-level structs and functions for calling into Rust, along with a corresponding exampleFFI.modulemap to expose them to Swift. A Swift source file example.swift that imports the exampleFFI module and wraps it to provide the higher-level Swift API. Splitting up the bindings in this way gives you flexibility over how both the Rust code and the Swift code are distributed to consumers. For example, you may choose to compile and distribute the Rust code for several UniFFI components as a single shared library in order to reduce the compiled code size, while distributing their Swift wrappers as individual modules. For more technical details on how the bindings work internally, please see the module documentation","breadcrumbs":"Bindings » Swift » Swift Bindings","id":"110","title":"Swift Bindings"},"111":{"body":"The generated Swift module can be configured using a uniffi.toml configuration file.","breadcrumbs":"Bindings » Swift » Configuration » Configuration","id":"111","title":"Configuration"},"112":{"body":"Configuration name Default Description cdylib_name uniffi_{namespace} [1] The name of the compiled Rust library containing the FFI implementation (not needed when using generate --library). module_name {namespace} [1] The name of the Swift module containing the high-level foreign-language bindings. ffi_module_name {module_name}FFI The name of the lower-level C module containing the FFI declarations. ffi_module_filename {ffi_module_name} The filename stem for the lower-level C module containing the FFI declarations. generate_module_map true Whether to generate a .modulemap file for the lower-level C module with FFI declarations. omit_argument_labels false Whether to omit argument labels in Swift function definitions. generate_immutable_records false Whether to generate records with immutable fields (let instead of var). custom_types A map which controls how custom types are exposed to Swift. See the custom types section of the manual namespace is the top-level namespace from your UDL file.","breadcrumbs":"Bindings » Swift » Configuration » Available options","id":"112","title":"Available options"},"113":{"body":"[bindings.swift]\ncdylib_name = \"mycrate_ffi\"\nomit_argument_labels = true","breadcrumbs":"Bindings » Swift » Configuration » Example","id":"113","title":"Example"},"114":{"body":"Before you can import the generated Swift bindings as a module (say, to use them from your application, or to try them out using swift on the command-line) you first need to compile them into a Swift module. To do so, you'll need both the generated .swift file and the corresponding .modulemap file, which tells Swift how to expose the underlying C FFI layer. Use swiftc to combine the cdylib from your Rust crate with the generated Swift bindings: swiftc -module-name example # Name for resulting Swift module -emit-library -o libexample.dylib # File to link with if using Swift REPL -emit-module -emit-module-path ./ # Output directory for resulting module -parse-as-library -L ./target/debug/ # Directory containing compiled Rust crate -lexample # Name of compiled Rust crate cdylib -Xcc -fmodule-map-file=exampleFFI.modulemap # The modulemap file from above example.swift # The generated bindings file This will produce an example.swiftmodule file that can be loaded by other Swift code or used from the Swift command-line REPL. If you are creating an XCFramework with this code, make sure to rename the modulemap file to module.modulemap, the default value expected by Clang and XCFrameworks for exposing the C FFI library to Swift.","breadcrumbs":"Bindings » Swift » Building a Swift module » Compiling a Swift module","id":"114","title":"Compiling a Swift module"},"115":{"body":"It is possible to generate Swift bindings at compile time for Xcode projects and incorporate them alongside hand-written Swift code to form a larger module. Broadly, you will need to: Add a build phase to compile the Rust crate into a static lib and link it into your framework. Add a build phase to run uniffi-bindgen and generate the Swift bindings. Include the generated bridging header into your overall bridging header. There is also an example app in the UniFFI project repo that may be helpful.","breadcrumbs":"Bindings » Swift » Integrating with Xcode » Integrating with Xcode","id":"115","title":"Integrating with Xcode"},"116":{"body":"Sorry, configuring Xcode to compile the Rust crate into a staticlib is beyond the scope of this document. However you do so, make sure you include the resulting libexample.a file in the \"Link Binary with Libraries\" build phase for your framework. This repository contains an example iOS app (at ./examples/app/ios) which may be useful for reference. It contains an xc-universal-binary.sh shell script which can invoke cargo with the necessary settings to produce a static library of Rust code.","breadcrumbs":"Bindings » Swift » Integrating with Xcode » Compiling the Rust crate.","id":"116","title":"Compiling the Rust crate."},"117":{"body":"In the \"Build Rules\" section of your config, add a rule to process .udl files using uniffi-bindgen. We recommend having it generate the output files somewhere in your source tree, rather than in Xcode's default $DERIVED_FILE_DIR; this both helps with debugging the build output, and makes it easier to configure how the generated files are used. Add a build rule processing files with names matching *.udl. Use something like the following as the custom script: $HOME/.cargo/bin/uniffi-bindgen generate $INPUT_FILE_PATH --language swift --out-dir $INPUT_FILE_DIR/Generated Add both the .swift file and the generated bridging header as output files: $(INPUT_FILE_DIR)/Generated/$(INPUT_FILE_BASE).swift $(INPUT_FILE_DIR)/Generated/$(INPUT_FILE_BASE)FFI.h Add your .udl file to the \"Compile Sources\" build phase for your framework, so that Xcode will process it using the new build rule and will include the resulting outputs in the build. You do not need to add the generated Swift code to the list of \"Compile Sources\" and should not attempt to compile it explicitly; Xcode will figure out what it needs to do with this code based on it being generated from the Build Rule for your .udl file.","breadcrumbs":"Bindings » Swift » Integrating with Xcode » Generating the bindings","id":"117","title":"Generating the bindings"},"118":{"body":"In the overall bridging header for your module, include the header file generated by UniFFI in the previous step: #include \"exampleFFI.h\" For this to work without complaint from Xcode, you also need to add the generated header file as a Public header in the \"Headers\" build phase of your project (which is why it's useful to generate this file somewhere in your source tree, rather than in a temporary build directory).","breadcrumbs":"Bindings » Swift » Integrating with Xcode » Including the bridging header","id":"118","title":"Including the bridging header"},"119":{"body":"The generated Python modules can be configured using a uniffi.toml configuration file.","breadcrumbs":"Bindings » Python » Configuration","id":"119","title":"Configuration"},"12":{"body":"We describe in a UDL (a type of IDL, Interface Definition Language) file what is exposed and available to foreign-language bindings. In this case, we are only playing with primitive types (u32) and not custom data structures but we still want to expose the add method. Let's create a math.udl file in the math crate's src/ folder: namespace math { u32 add(u32 a, u32 b);\n}; Here you can note multiple things: The namespace directive: it will be the name of your Kotlin/Swift package. It must be present in any udl file, even if there ain't any exposed function (e.g. namespace foo {}). The add function is in the namespace block. That's because on the Rust side it is a top-level function , we will see later how to to handle methods . Rust's u32 is also UDL's u32, but it is not always true! See the Built-in Types chapter for more information on mapping types between Rust and UDL. Note: If any of the things you expose in the udl file do not have an equivalent in your Rust crate, you will get a hard error. Try changing the u32 result type to u64 and see what happens! Note It's also possible to use Rust procmacros to describe your interface and you can avoid UDL files entirely if you choose. Unfortunately the docs aren't quite as good for that yet though.","breadcrumbs":"Tutorial » Describing the interface » The UDL file","id":"12","title":"The UDL file"},"120":{"body":"Configuration name Default Description cdylib_name uniffi_{namespace} [1] The name of the compiled Rust library containing the FFI implementation (not needed when using generate --library). custom_types A map which controls how custom types are exposed to Python. See the custom types section of the manual external_packages A map which controls the package name used by external packages. See below for more.","breadcrumbs":"Bindings » Python » Available options","id":"120","title":"Available options"},"121":{"body":"When you reference external modules, uniffi will generate statements like from module import Type in the referencing module. The external_packages configuration value allows you to specify how module is formed in such statements. The value is a map, keyed by the crate-name and the value is the package name which will be used by Python for that crate. The default value is an empty map. When looking up crate-name, the following behavior is implemented.","breadcrumbs":"Bindings » Python » External Packages","id":"121","title":"External Packages"},"122":{"body":"If no value for the crate is found, it is assumed that you will be packaging up your library as a simple Python package, so the statement will be of the form from .module import Type, where module is the namespace specified in that crate. Note that this is invalid syntax unless the module lives in a package - attempting to use the module as a stand-alone module will fail. UniFFI just generates flat .py files; the packaging is up to you. Eg, a build process might create a directory, create an __init__.py file in that directory (maybe including from subpackage import *) and have uniffi-bindgen generate the bindings into this directory.","breadcrumbs":"Bindings » Python » Default value","id":"122","title":"Default value"},"123":{"body":"If the crate-name is found in the map, the specified entry used as a package name, so the statement will be of the form from package.module import Type (again, where module is the namespace specified in that crate) An exception is when the specified value is an empty string, in which case you will see from module import Type, so each generated module functions outside a package. This is used by some UniFFI tests to avoid the test code needing to create a Python package.","breadcrumbs":"Bindings » Python » Specified value","id":"123","title":"Specified value"},"124":{"body":"Custom Types # Assuming a Custom Type named URL using a String as the builtin.\n[bindings.python.custom_types.Url]\nimports = [\"urllib.parse\"]\n# Functions to convert between strings and the ParsedUrl class\ninto_custom = \"urllib.parse.urlparse({})\"\nfrom_custom = \"urllib.parse.urlunparse({})\" External Packages [bindings.python.external_packages]\n# An external type `Foo` in `crate-name` (which specifies a namespace of `my_module`) will be referenced via `from MyPackageName.my_module import Foo`\ncrate-name = \"MyPackageName\"","breadcrumbs":"Bindings » Python » Examples","id":"124","title":"Examples"},"125":{"body":"These are some high-level points to consider when making changes to UniFFI (or when wondering why past changes were made in a particular way).","breadcrumbs":"Design Principles » Design Principles","id":"125","title":"Design Principles"},"126":{"body":"The initial consumers of this tool are teams working on features for Mozilla's mobile browsers. While we try to make the tool generally useful, we'll invest first in things that are the most valuable to those teams, which are reflected in the points below.","breadcrumbs":"Design Principles » Prioritize Mozilla's short-term needs","id":"126","title":"Prioritize Mozilla's short-term needs"},"127":{"body":"The generated bindings need to be safe by default. It should be impossible for foreign-language code to trigger undefined behaviour in Rust by calling the public API of the generated bindings, even if it is called in egregiously wrong or malicious ways. We will accept reduced performance in the interests of ensuring this safety. (The meaning of \"impossible\" and \"public API\" will of course depend on the target language. For example, code in Python might mutate internal attributes of an object that are marked as private with a leading underscore, and there's not much we can do to guard against that.) Where possible, we use Rust's typesystem to encode safety guarantees. If that's not possible then the generated Rust code may use unsafe and assume that the generated foreign-language code will uphold safety guarantees at runtime. Example: We insist that all object instances exposed to foreign-language code be Sync and Send, so that they're safe to access regardless of the threading model of the calling code. We do not allow thread-safety guarantees to be deferred to assumptions about how the code is called. Example: We do not allow returning any borrowed data from function calls, because we can't make any guarantees about when or how the foreign-language could access it.","breadcrumbs":"Design Principles » Safety First","id":"127","title":"Safety First"},"128":{"body":"Our initial use-cases are not performance-critical, and our team are not low-level Rust experts, so we're highly motivated to favour simplicity and maintainability over performance. Given the choice we will pick \"simple but slow\" over \"fast but complicated\". However, we know that performance can degrade through thousands of tiny cuts, so we'll keep iterating towards the winning combination of \"simple and fast\" over time. Example: Initial versions of the tool used opaque integer handles and explicit mutexes to manage object references, favouring simplicity (in the \"we're confident this works as intended\" sense) over performance. As we got more experience and confidence with the approach and tool we replaced handles with raw Arc pointers, which both simplified the code and removed some runtime overheads. Violation: The tool currently passes structured data over the FFI by serializing it to a byte buffer, favouring ease of implementation and understanding over performance. This was fine as a starting point! However, we have not done any work to measure the performance impact or iterate towards something with lower overhead (such as using repr(C) structs).","breadcrumbs":"Design Principles » Performance is a feature, but not a deal-breaker","id":"128","title":"Performance is a feature, but not a deal-breaker"},"129":{"body":"The generated bindings should feel idiomatic for their end users, and what feels idiomatic can differ between different target languages. Ideally consumers should not even realize that they're using bindings to Rust under the hood. We'll accept extra complexity inside of UniFFI if it means producing bindings that are nicer for consumers to use. Example: We case-convert names to match the accepted standards of the target language, so a method named do_the_thing in Rust might be called doTheThing in its Kotlin bindings. Example: Object references try to integrate with the GC of the target language, so that holding a reference to a Rust struct feels like holding an ordinary object instance. Violation: The Kotlin bindings have an explicit destroy method on object instances, because we haven't yet found a good way to integrate with the JVM's GC.","breadcrumbs":"Design Principles » Produce bindings that feel idiomatic for the target language","id":"129","title":"Produce bindings that feel idiomatic for the target language"},"13":{"body":"","breadcrumbs":"Tutorial » Generating the Rust scaffolding code » Rust scaffolding","id":"13","title":"Rust scaffolding"},"130":{"body":"To succeed long-term, we can't depend on a dedicated team of \"UniFFI experts\" for debugging and maintenance. The people using the tool need to be empowered to debug, maintain and develop it. If you're using UniFFI-generated bindings and something doesn't work quite right, it should be possible for you to dig in to the generated foreign-language code, follow it through to the underlying Rust code, and work out what's going wrong without being an expert in Rust or UniFFI. Example: We try to include comments in the generated code to help guide users who may be reading through it to debug some issue. Violation: We don't have very good \"overview\" documentation on how each set of foreign-language bindings works, so someone trying to debug the Kotlin bindings would need to poke around in the generated code to try to build up a mental model of how it's supposed to work. Violation: A lack of structure in our code-generation templates means that it's hard for non-experts to find and change the codegen logic for a particular piece of functionality.","breadcrumbs":"Design Principles » Empower users to debug and maintain the tool","id":"130","title":"Empower users to debug and maintain the tool"},"131":{"body":"The code for UniFFI is organized into the following crates: ./uniffi_bindgen : This is the source for the uniffi-bindgen executable and is where most of the logic for the UniFFI tool lives. Its contents include: ./uniffi_bindgen/src/interface/ : The logic for parsing .udl files into an in-memory representation called ComponentInterface , from which we can generate code for different languages. ./uniffi_bindgen/src/scaffolding : This module turns a ComponentInterface into Rust scaffolding , the code that wraps the user-provided Rust code and exposes it via a C-compatible FFI layer. ./uniffi_bindgen/src/bindings/ : This module turns a ComponentInterface into foreign-language bindings , the code that can load the FFI layer exposed by the scaffolding and expose it as a higher-level API in a target language. There is a sub-module for each supported language. ./uniffi : This is a run-time support crate that is used by the generated Rust scaffolding. It controls how values of various types are passed back-and-forth over the FFI layer, by means of the FfiConverter trait. ./uniffi_build : This is a small hook to run uniffi-bindgen from the build.rs script of a UniFFI component, in order to automatically generate the Rust scaffolding as part of its build process. ./uniffi_macros : This contains some helper macros that UniFFI components can use to simplify loading the generated scaffolding, and executing foreign-language tests. ./examples : This contains code examples that you can use to explore the code generation process.","breadcrumbs":"Navigating the Code » Navigating the code","id":"131","title":"Navigating the code"},"132":{"body":"UniFFI is able to transfer rich data types back-and-forth between the Rust code and the foreign-language code via a process we refer to as \"lowering\" and \"lifting\". Recall that UniFFI interoperates between different languages by defining a C-style FFI layer which operates in terms of primitive data types and plain functions. To transfer data from one side of this layer to the other, the sending side \" lowers \" the data from a language-specific data type into one of the primitive types supported by the FFI-layer functions, and the receiving side \" lifts \" that primitive type into its own language-specific data type. Lifting and lowering simple types such as integers is done by directly casting the value to and from an appropriate type. For complex types such as optionals and records we currently implement lifting and lowering by serializing into a byte buffer, but this is an implementation detail that may change in future. (See ADR-0002 for the reasoning behind this choice.) As a concrete example, consider this interface for accumulating a list of integers: namespace example { sequence add_to_list(i32 item);\n} Calling this function from foreign language code involves the following steps: The user-provided calling code invokes the add_to_list function that is exposed by the UniFFI-generated foreign language bindings, passing item as an appropriate language-native integer. The foreign language bindings lower each argument to a function call into something that can be passed over the C-style FFI. Since the item argument is a plain integer, it is lowered by casting to an int32_t. The foreign language bindings pass the lowered arguments to a C FFI function named like example_XYZ_add_to_list that is exposed by the UniFFI-generated Rust scaffolding. The Rust scaffolding lifts each argument received over the FFI into a native Rust type. Since item is a plain integer it is lifted by casting to a Rust i32. The Rust scaffolding passes the lifted arguments to the user-provided Rust code for the add_to_list function, which returns a Vec. The Rust scaffolding now needs to lower the return value in order to pass it back to the foreign language code. Since this is a complex data type, it is lowered by serializing the values into a byte buffer and returning the buffer pointer and length from the FFI function. The foreign language bindings receive the return value and need to lift it into an appropriate native data type. Since it is a complex data type, it is lifted by deserializing from the returned byte buffer into a language-native list of integers.","breadcrumbs":"Lifting, Lowering, and Serialization » Lifting, Lowering and Serialization","id":"132","title":"Lifting, Lowering and Serialization"},"133":{"body":"UDL Type Representation in the C FFI i8/i16/i32/i64 int8_t/int16_t/int32_t/int64_t u8/u16/u32/u64 uint8_t/uint16_t/uint32_t/uint64_t f32/float float f64/double double boolean int8_t, either 0 or 1 string RustBuffer struct pointing to utf8 bytes bytes Same as sequence timestamp RustBuffer struct pointing to a i64 representing seconds and a u32 representing nanoseconds duration RustBuffer struct pointing to a u64 representing seconds and a u32 representing nanoseconds T? RustBuffer struct pointing to serialized bytes sequence RustBuffer struct pointing to serialized bytes record RustBuffer struct pointing to serialized bytes enum and [Enum] interface RustBuffer struct pointing to serialized bytes dictionary RustBuffer struct pointing to serialized bytes interface void* opaque pointer to object on the heap","breadcrumbs":"Lifting, Lowering, and Serialization » Lowered Types","id":"133","title":"Lowered Types"},"134":{"body":"When serializing complex data types into a byte buffer, UniFFI uses an ad-hoc fixed-width format which is designed mainly for simplicity. The details of this format are internal only and may change between versions of UniFFI. UDL Type Representation in serialized bytes i8/i16/i32/i64 Fixed-width 1/2/4/8-byte signed integer, big-endian u8/u16/u32/u64 Fixed-width 1/2/4/8-byte unsigned integer, big-endian f32/float Fixed-width 4-byte float, big-endian f64/double Fixed-width 8-byte double, big-endian boolean Fixed-width 1-byte signed integer, either 0 or 1 string Serialized i32 length followed by utf-8 string bytes; no trailing null T? If null, serialized boolean false; if non-null, serialized boolean true followed by serialized T sequence Serialized i32 item count followed by serialized items; each item is a serialized T record Serialized i32 item count followed by serialized items; each item is a serialized string followed by a serialized T enum and [Enum] interface Serialized i32 indicating variant, numbered in declaration order starting from 1, followed by the serialized values of the variant's fields in declaration order dictionary The serialized value of each field, in declaration order interface Fixed-width 8-byte unsigned integer encoding a pointer to the object on the heap Note that length fields in this format are serialized as signed integers despite the fact that they will always be non-negative. This is to help ease compatibility with JVM-based languages since the JVM uses signed 32-bit integers for its size fields internally.","breadcrumbs":"Lifting, Lowering, and Serialization » Serialization Format","id":"134","title":"Serialization Format"},"135":{"body":"UniFFI needs to generate Rust code to lift/lower types. To help with this, we define the FfiConverter trait which contains the code to lift/lower/serialize a particular type. The most straightforward approach would be to define FfiConverter on the type being lifted/lowered/serialized. However, this wouldn't work for remote types defined in 3rd-party crates because of the Rust orphan rules. For example, our crates can't implement FfiConverter on serde_json::Value because both the trait and the type are remote. To work around this we do several things: FfiConverter gets a generic type parameter. This type is basically arbitrary and doesn't affect the lowering/lifting/serialization process. We generate a unit struct named UniFfiTag in the root of each UniFFIed crate. Each crate uses the FfiConverter trait to lower/lift/serialize values for its scaffolding functions. This allows us to work around the orphan rules when defining FfiConverter implementations. UniFFI consumer crates can implement lifting/lowering/serializing types for their own scaffolding functions, for example impl FfiConverter for serde_json::Value. This is allowed since UniFfiTag is a local type. The uniffi crate can implement lifting/lowering/serializing types for all scaffolding functions using a generic impl, for example impl FfiConverter for u8. \"UT\" is short for \"UniFFI Tag\" We don't currently use this, but crates can also implement lifting/lowering/serializing their local types for all scaffolding functions using a similar generic impl (impl FfiConverter for MyLocalType). For more details on the specifics of the \"orphan rule\" and why these are legal implementations, see the Rust Chalk Book","breadcrumbs":"Lifting, Lowering, and Serialization » Code Generation and the FfiConverter trait","id":"135","title":"Code Generation and the FfiConverter trait"},"136":{"body":"UniFFI interfaces represent instances of objects that have methods and contain state. One of Rust's core innovations is its ability to provide compile-time guarantees about working with such instances, including: Ensuring that each instance has a unique owner responsible for disposing of it. Ensuring that there is only a single writer or multiple readers of an object active at any point in the program. Guarding against data races. The very nature of the problems UniFFI tries to solve is that calls may come from foreign languages on any thread, outside of the control of Rust's ownership system. UniFFI itself tries to take a hands-off approach as much as possible and depends on the Rust compiler itself to uphold safety guarantees, without assuming that foreign-language callers will be \"well behaved\".","breadcrumbs":"Managing Object References » Managing Object References","id":"136","title":"Managing Object References"},"137":{"body":"UniFFI's hands-off approach means that all object instances exposed by UniFFI must be safe to access concurrently. In Rust terminology, they must be Send+Sync and must be useable without taking any &mut references. Typically this will mean that the Rust implementation of an object uses some of Rust's data structures for thread-safe interior mutability, such as a Mutex or RwLock or the types from std::atomic. The precise details are completely up to the author of the component - as much as possible, UniFFI tries to stay out of your way, simply requiring that the object implementation is Send+Sync and letting the Rust compiler ensure that this is so.","breadcrumbs":"Managing Object References » Concurrency","id":"137","title":"Concurrency"},"138":{"body":"In order to allow for instances to be used as flexibly as possible from foreign-language code, UniFFI wraps all object instances in an Arc and leverages their reference-count based lifetimes, allowing UniFFI to largely stay out of handling lifetimes entirely for these objects. When constructing a new object, UniFFI is able to add the Arc automatically, because it knows that the return type of the Rust constructor must be a new uniquely-owned struct of the corresponding type. When you want to return object instances from functions or methods, or store object instances as fields in records, the underlying Rust code will need to work with Arc directly, to ensure that the code behaves in the way that UniFFI expects. When accepting instances as arguments, the underlying Rust code can choose to accept it as an Arc or as the underlying struct T, as there are different use-cases for each scenario. For example, given a interface definition like this: interface TodoList { constructor(); void add_item(string todo); sequence get_items();\n}; On the Rust side of the generated bindings: The instance constructor will create an instance of the corresponding TodoList Rust struct The owned value is wrapped in an Arc<> The Arc<> is lowered into the foreign code using Arc::into_raw and returned as an object pointer. This is the \"arc to pointer\" dance. Note that this has \"leaked\" the Arc<> reference out of Rusts ownership system and given it to the foreign-language code. The foreign-language code must pass that pointer back into Rust in order to free it, or our instance will leak. When invoking a method on the instance: The foreign-language code passes the raw pointer back to the Rust code, conceptually passing a \"borrow\" of the Arc<> to the Rust scaffolding. The Rust side calls Arc::from_raw to convert the pointer into an an Arc<> It wraps the Arc in std::mem::ManuallyDrop<>, which we never actually drop. This is because the Rust side is borrowing the Arc and shouldn't run the destructor and decrement the reference count. The Arc<> is cloned and passed to the Rust code Finally, when the foreign-language code frees the instance, it passes the raw pointer a special destructor function so that the Rust code can drop that initial reference (and if that happens to be the final reference, the Rust object will be dropped.). This simply calls Arc::from_raw, then lets the value drop. Passing instances as arguments and returning them as values works similarly, except that UniFFI does not automatically wrap/unwrap the containing Arc. To see this in action, use cargo expand to see the exact generated code.","breadcrumbs":"Managing Object References » Lifetimes","id":"138","title":"Lifetimes"},"139":{"body":"This document details the general system that UniFFI uses to render the foreign bindings code.","breadcrumbs":"Rendering Foreign Bindings » Rendering Foreign Bindings","id":"139","title":"Rendering Foreign Bindings"},"14":{"body":"Now we generate some Rust helper code to make the add method available to foreign-language bindings. First, add uniffi to your crate as both a dependency and build-dependency. Enable the build feature for the build-dependencies. This adds the runtime support code that powers UniFFI and build-time support for generating the Rust scaffolding code. [dependencies]\nuniffi = \"0.XX.0\" [build-dependencies]\nuniffi = { version = \"0.XX.0\", features = [\"build\"] } As noted in Describing the interface , UniFFI currently supports two methods of interface definitions: UDL files and proc macros. If you are using only proc macros, you can skip some boilerplate in your crate setup as well.","breadcrumbs":"Tutorial » Generating the Rust scaffolding code » Rust scaffolding code","id":"14","title":"Rust scaffolding code"},"140":{"body":"Our foreign bindings generation uses the Askama template rendering engine. Askama uses a compile-time macro system that allows the template code to use Rust types directly, calling their methods passing them to normal Rust functions. The task of the templates is to render the ComponentInterface, which is the Rust representation of the UDL file, into a bindings source file. This mainly consists of rendering source code for each Type from the UDL.","breadcrumbs":"Rendering Foreign Bindings » The Askama template engine","id":"140","title":"The Askama template engine"},"141":{"body":"One of the main sources of complexity when generating the bindings is handling types. UniFFI supports a large number of types, each of which corresponds to a variant of the Type enum . At one point there was a fairly large number of \"mega-match\" functions, each one matching against all Type variants. This made the code difficult to understand, because the functionality for one kind of type was split up. Our current system for handling this is to have exactly 2 matches against Type: One match lives in the template code. We map each Type variant to a template file that renders definitions and helper code, including: Class definitions for records, enums, and objects. Base classes and helper classes, for example ObjectRuntime.kt contains shared functionality for all the Type::Object types. The FfiConverter class definition. This handles lifting and lowering types across the FFI for the type. Initialization functions Importing dependencies See Types.kt for an example. The other match lives in the Rust code. We map each Type variant to a implementation of the CodeType trait that renders identifiers and names related to the type, including: The name of the type in the foreign language The name of the FfiConverter class The name of the initialization function See KotlinCodeOracle::create_code_type() for an example. Why is the code organized like this? For a few reasons: Defining Askama templates in Rust required a lot of boilerplate. When the Rust code was responsible for rendering the class definitions, helper classes, etc., it needed to define a lot of Askama template structs which lead to a lot of extra lines of code (see PR #1189 ) It's easier to access global state from the template code. Since the Rust code only handles names and identifiers, it only needs access to the Type instance itself, not the ComponentInterface or the Config . This simplifies the Rust side of things (see PR #1191 ). Accessing the ComponentInterface and Config from the template code is easy, we simply define these as fields on the top-level template Struct then they are accessible from all child templates. Putting logic in the template code makes it easier to implement external types . For example, at one point the logic to lift/lower a type lived in the Rust code as a function that generated the expression in the foreign language. However, it was not clear at all how to make this work for external types, it would probably require parsing multiple UDL files and managing multiple ComponentInterfaces. Putting the logic to lift/lower the type in the FfiConverter class simplifies this, because we can import the external FfiConverter class and use that. We only need to know the name of the FfiConverter class which is a simpler task.","breadcrumbs":"Rendering Foreign Bindings » Type matching","id":"141","title":"Type matching"},"142":{"body":"A couple parts of this system require us to \"extend\" the functionality of Askama (i.e. adding hacks to workaround its limitations).","breadcrumbs":"Rendering Foreign Bindings » Askama extensions","id":"142","title":"Askama extensions"},"143":{"body":"We want our type template files to specify what needs to be imported, but we don't want it to render the import statements directly. The imports should be rendered at the top of the file and de-duped in case multiple types require the same import. We handle this by: Defining a separate Askama template struct that loops over all types and renders the definition/helper code for them. That struct also stores a BTreeSet that contains the needed import statements and has an add_import() method that the template code calls. Using a BTreeSet ensures the imports stay de-duped and sorted. Rendering this template as a separate pass. The rendered string and the list of imports get passed to the main template which arranges for them to be placed in the correct location.","breadcrumbs":"Rendering Foreign Bindings » Adding imports","id":"143","title":"Adding imports"},"144":{"body":"We want our type template files to render runtime code, but only once. For example, we only want to render ObjectRuntime.kt once, even if there are multiple Object types defined in the UDL file. To handle this the type template defines an include_once_check() method, which tests if we've included a file before. The template code then uses that to guard the Askama {% include %} statement. See Object.kt for an example","breadcrumbs":"Rendering Foreign Bindings » Including templates once","id":"144","title":"Including templates once"},"15":{"body":"Crates using UDL need a build.rs file next to Cargo.toml. This uses uniffi to generate the Rust scaffolding code. fn main() { uniffi::generate_scaffolding(\"src/math.udl\").unwrap();\n} Lastly, we include the generated scaffolding code in our lib.rs using this handy macro: uniffi::include_scaffolding!(\"math\"); Note: The file name is always .uniffi.rs.","breadcrumbs":"Tutorial » Generating the Rust scaffolding code » Setup for crates using UDL","id":"15","title":"Setup for crates using UDL"},"16":{"body":"If you are only using proc macros, you can skip build.rs entirely! All you need to do is add this to the top of lib.rs NOTE: This function takes an optional parameter, the namespace used by the component. If not specified, the crate name will be used as the namespace. uniffi::setup_scaffolding!(); ⚠ Warning ⚠ Do not call both uniffi::setup_scaffolding!() and uniffi::include_scaffolding!!() in the same crate.","breadcrumbs":"Tutorial » Generating the Rust scaffolding code » Setup for crates using only proc macros","id":"16","title":"Setup for crates using only proc macros"},"17":{"body":"Suppose you want to create a shared library that includes one or more components using UniFFI. The typical way to achieve this is to create a new crate that depends on the component crates. However, this can run into rust-lang#50007 . Under certain circumstances, the scaffolding functions that the component crates export do not get re-exported by the dependent crate. Use the uniffi_reexport_scaffolding! macro to work around this issue. If your library depends on foo_component, then add foo_component::uniffi_reexport_scaffolding!(); to your lib.rs file and UniFFI will add workaround code that forces the functions to be re-exported. Each scaffolding function contains a hash that's derived from the UDL file. This avoids name collisions when combining multiple UniFFI components into one library.","breadcrumbs":"Tutorial » Generating the Rust scaffolding code » Libraries that depend on UniFFI components","id":"17","title":"Libraries that depend on UniFFI components"},"18":{"body":"As stated in the Overview , this library and tutorial does not cover how to ship a Rust library on mobile, but how to generate bindings for it, so this section will only cover that.","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Foreign-language bindings","id":"18","title":"Foreign-language bindings"},"19":{"body":"First, make sure you have installed all the prerequisites . Ideally you would then run the uniffi-bindgen binary from the uniffi crate to generate your bindings. However, this is only available with Cargo nightly . To work around this, you need to create a binary in your project that does the same thing. Add the following to your Cargo.toml: [[bin]]\n# This can be whatever name makes sense for your project, but the rest of this tutorial assumes uniffi-bindgen.\nname = \"uniffi-bindgen\"\npath = \"uniffi-bindgen.rs\" Create uniffi-bindgen.rs: fn main() { uniffi::uniffi_bindgen_main()\n} You can now run uniffi-bindgen from your project using cargo run --features=uniffi/cli --bin uniffi-bindgen [args]","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Creating the bindgen binary","id":"19","title":"Creating the bindgen binary"},"2":{"body":"Kotlin Swift Python Ruby","breadcrumbs":"Overview » Supported languages","id":"2","title":"Supported languages"},"20":{"body":"If your project consists of multiple crates in a Cargo workspace, then the process outlined above would require you creating a binary for each crate that uses UniFFI. You can avoid this by creating a separate crate for running uniffi-bindgen: Name the crate uniffi-bindgen Add this dependency to Cargo.toml: uniffi = {version = \"0.XX.0\", features = [\"cli\"] } Follow the steps from the previous section to add the uniffi-bindgen binary target Then your can run uniffi-bindgen from any create in your project using cargo run -p uniffi-bindgen [args]","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Multi-crate workspaces","id":"20","title":"Multi-crate workspaces"},"21":{"body":"Use generate --library to generate foreign bindings by using a cdylib file built for your library. This flag was added in UniFFI 0.24 and can be more convenient than specifying the UDL file -- especially when multiple UniFFI-ed crates are built together in one library. The plan is to make library mode the default in a future UniFFI version, and it is highly recommended to specify the flag for now (because some features simply don't work otherwise). Taking example/arithmetic as an example, you can generate the bindings with: cargo build --release\ncargo run --bin uniffi-bindgen generate --library target/release/libarithmetical.so --language kotlin --out-dir out Then check out the out directory. When using library mode, if multiple crates get built into the library that use UniFFI, all will have bindings generated for them. Library mode comes with some extra requirements: It must be run from within the cargo workspace of your project Each crate must use exactly 1 UDL file when compiling the Rust library. However, crates can have multiple UDL files as long as they ensure only one is used for any particular build, e.g. by using feature flags. Rust sources must use uniffi::include_scaffolding! to include the scaffolding code.","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Running uniffi-bindgen using a library file (RECOMMENDED)","id":"21","title":"Running uniffi-bindgen using a library file (RECOMMENDED)"},"22":{"body":"Use the generate command to generate bindings by specifying a UDL file.","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Running uniffi-bindgen with a single UDL file","id":"22","title":"Running uniffi-bindgen with a single UDL file"},"23":{"body":"From the example/arithmetic directory, run: cargo run --bin uniffi-bindgen generate src/arithmetic.udl --language kotlin then have a look at src/uniffi/arithmetic/arithmetic.kt","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Kotlin","id":"23","title":"Kotlin"},"24":{"body":"Run cargo run --bin uniffi-bindgen generate src/arithmetic.udl --language swift then check out src/arithmetic.swift Note that these commands could be integrated as part of your gradle/Xcode build process. This is it, you have an MVP integration of UniFFI in your project.","breadcrumbs":"Tutorial » Generating the foreign-language bindings » Swift","id":"24","title":"Swift"},"25":{"body":"This file defines which functions, methods and types are exposed to the foreign-language bindings. namespace sprites { Point translate([ByRef] Point position, Vector direction);\n}; dictionary Point { double x; double y;\n}; dictionary Vector { double dx; double dy;\n}; interface Sprite { constructor(Point? initial_position); Point get_position(); void move_to(Point position); void move_by(Vector direction);\n};","breadcrumbs":"The UDL file » The UDL file","id":"25","title":"The UDL file"},"26":{"body":"Every UDL file must have a namespace block: namespace math { double exp(double a);\n}; It serves multiple purposes: It identifies the name of the generated Rust scaffolding file .uniffi.rs. It identifies the package name of the generated foreign-language bindings (e.g. uniffi. in Kotlin) It also contains all top-level functions that get exposed to foreign-language bindings.","breadcrumbs":"The UDL file » Namespace » Namespace","id":"26","title":"Namespace"},"27":{"body":"The following built-in types can be passed as arguments/returned by Rust methods: Rust type UDL type Notes bool boolean u8/i8..u64/i64 u8/i8..u64/i64 f32 float f64 double String string Vec bytes Different from sequence only in foreign type mappings SystemTime timestamp Precision may be lost when converting to Python and Swift types Duration duration Precision may be lost when converting to Python and Swift types &T [ByRef] T This works for &str and &[T] Option T? Vec sequence HashMap record () void Empty return Result N/A See Errors section And of course you can use your own types, which is covered in the following sections.","breadcrumbs":"The UDL file » Built-in types » Built-in types","id":"27","title":"Built-in types"},"28":{"body":"An enumeration defined in Rust code as enum Animal { Dog, Cat,\n} Can be exposed in the UDL file with: enum Animal { \"Dog\", \"Cat\",\n};","breadcrumbs":"The UDL file » Enumerations » Enumerations","id":"28","title":"Enumerations"},"29":{"body":"Enumerations with associated data require a different syntax, due to the limitations of using WebIDL as the basis for UniFFI's interface language. An enum like this in Rust: enum IpAddr { V4 {q1: u8, q2: u8, q3: u8, q4: u8}, V6 {addr: string},\n} Can be exposed in the UDL file with: [Enum]\ninterface IpAddr { V4(u8 q1, u8 q2, u8 q3, u8 q4); V6(string addr);\n}; Only enums with named fields are supported by this syntax.","breadcrumbs":"The UDL file » Enumerations » Enums with fields","id":"29","title":"Enums with fields"},"3":{"body":"Kotlin Multiplatform Go bindings C# bindings","breadcrumbs":"Overview » Third-party foreign language bindings","id":"3","title":"Third-party foreign language bindings"},"30":{"body":"One corner case is an enum that's: Defined in another crate. Has the non_exhaustive` attribute . In this case, UniFFI needs to generate a default arm when matching against the enum variants, or else a compile error will be generated. Use the [NonExhaustive] attribute to handle this case: [Enum]\n[NonExhaustive]\ninterface Message { Send(u32 from, u32 to, string contents); Quit();\n}; Note: since UniFFI generates a default arm, if you leave out a variant, or if the upstream crate adds a new variant, this won't be caught at compile time. Any attempt to pass that variant across the FFI will result in a panic.","breadcrumbs":"The UDL file » Enumerations » Remote, non-exhaustive enums","id":"30","title":"Remote, non-exhaustive enums"},"31":{"body":"Dictionaries are how UniFFI represents structured data. They consist of one of more named fields , each of which holds a value of a particular type. Think of them like a Rust struct without any methods. A Rust struct like this: struct TodoEntry { done: bool, due_date: u64, text: String,\n} Can be exposed via UniFFI using UDL like this: dictionary TodoEntry { boolean done; u64 due_date; string text;\n}; The fields in a dictionary can be of almost any type, including objects or other dictionaries. The current limitations are: They cannot recursively contain another instance of the same dictionary type. They cannot contain references to callback interfaces.","breadcrumbs":"The UDL file » Structs/Dictionaries » Structs/Dictionaries","id":"31","title":"Structs/Dictionaries"},"32":{"body":"If a dictionary contains a field whose type is an interface , then that field will hold a reference to an underlying instance of a Rust struct. The Rust code for working with such fields must store them as an Arc in order to help properly manage the lifetime of the instance. So if the UDL interface looked like this: interface User { // Some sort of \"user\" object that can own todo items\n}; dictionary TodoEntry { User owner; string text;\n} Then the corresponding Rust code would need to look like this: struct TodoEntry { owner: std::sync::Arc, text: String,\n} Depending on the language, the foreign-language bindings may also need to be aware of these embedded references. For example in Kotlin, each Object instance must be explicitly destroyed to avoid leaking the underlying memory, and this also applies to Objects stored in record fields. You can read more about managing object references in the section on interfaces .","breadcrumbs":"The UDL file » Structs/Dictionaries » Fields holding Object References","id":"32","title":"Fields holding Object References"},"33":{"body":"Fields can be specified with a default value: dictionary TodoEntry { boolean done = false; string text;\n}; The corresponding generated Kotlin code would be equivalent to: data class TodoEntry ( var done: Boolean = false, var text: String\n) { // ...\n} This works for Swift and Python targets too. If not set otherwise the default value for a field is used when constructing the Rust struct.","breadcrumbs":"The UDL file » Structs/Dictionaries » Default values for fields","id":"33","title":"Default values for fields"},"34":{"body":"Fields can be made optional using a T? type. dictionary TodoEntry { boolean done; string? text;\n}; The corresponding Rust struct would need to look like this: struct TodoEntry { done: bool, text: Option,\n} The corresponding generated Kotlin code would be equivalent to: data class TodoEntry ( var done: Boolean, var text: String?\n) { // ...\n} Optional fields can also be set to a default null value: dictionary TodoEntry { boolean done; string? text = null;\n}; The corresponding generated Kotlin code would be equivalent to: data class TodoEntry ( var done: Boolean, var text: String? = null\n) { // ...\n} This works for Swift and Python targets too.","breadcrumbs":"The UDL file » Structs/Dictionaries » Optional fields and default values","id":"34","title":"Optional fields and default values"},"35":{"body":"All top-level functions get exposed through the UDL's namespace block. For example, if the crate's lib.rs file contains: fn hello_world() -> String { \"Hello World!\".to_owned()\n} The UDL file will look like: namespace Example { string hello_world();\n}","breadcrumbs":"The UDL file » Functions » Functions","id":"35","title":"Functions"},"36":{"body":"Function arguments can be marked optional with a default value specified. In the UDL file: namespace Example { string hello_name(optional string name = \"world\");\n} The Rust code will take a required argument: fn hello_name(name: String) -> String { format!(\"Hello {}\", name)\n} The generated foreign-language bindings will use function parameters with default values. This works for the Kotlin, Swift and Python targets. For example the generated Kotlin code will be equivalent to: fun helloName(name: String = \"world\" ): String { // ...\n}","breadcrumbs":"The UDL file » Functions » Optional arguments & default values","id":"36","title":"Optional arguments & default values"},"37":{"body":"Async functions can be exposed using the [Async] attribute: namespace Example { [Async] string async_hello();\n} See the Async/Future support section for details.","breadcrumbs":"The UDL file » Functions » Async","id":"37","title":"Async"},"38":{"body":"It is often the case that a function does not return T in Rust but Result to reflect that it is fallible. For UniFFI to expose this error, your error type (E) must be an enum and implement std::error::Error ( thiserror works!). Here's how you would write a Rust failible function and how you'd expose it in UDL: #[derive(Debug, thiserror::Error)]\nenum ArithmeticError { #[error(\"Integer overflow on an operation with {a} and {b}\")] IntegerOverflow { a: u64, b: u64 },\n} fn add(a: u64, b: u64) -> Result { a.checked_add(b).ok_or(ArithmeticError::IntegerOverflow { a, b })\n} And in UDL: [Error]\nenum ArithmeticError { \"IntegerOverflow\",\n}; namespace arithmetic { [Throws=ArithmeticError] u64 add(u64 a, u64 b);\n} On the other side (Kotlin, Swift etc.), a proper exception will be thrown if Result::is_err() is true. If you want to expose the associated data as fields on the exception, use this syntax: [Error]\ninterface ArithmeticError { IntegerOverflow(u64 a, u64 b);\n};","breadcrumbs":"The UDL file » Functions » Throwing errors » Throwing errors","id":"38","title":"Throwing errors"},"39":{"body":"Interfaces are represented in the Rust world as a struct with an impl block containing methods. In the Kotlin or Swift world, it's a class. Because Objects are passed by reference and Dictionaries by value, in the UniFFI world it is impossible to be both an Object and a Dictionary . The following Rust code: struct TodoList { items: RwLock>\n} impl TodoList { fn new() -> Self { TodoList { items: RwLock::new(Vec::new()) } } fn add_item(&self, todo: String) { self.items.write().unwrap().push(todo); } fn get_items(&self) -> Vec { self.items.read().unwrap().clone() }\n} would be exposed using: interface TodoList { constructor(); void add_item(string todo); sequence get_items();\n}; By convention, the constructor() calls the Rust's new() method. Conceptually, these interface objects are live Rust structs that have a proxy object on the foreign language side; calling any methods on them, including a constructor or destructor results in the corresponding methods being called in Rust. If you do not specify a constructor the bindings will be unable to create the interface directly. UniFFI will generate these proxies with an interface or protocol to help with testing in the foreign-language code. For example in Kotlin, the TodoList would generate: interface TodoListInterface { fun addItem(todo: String) fun getItems(): List\n} class TodoList : TodoListInterface { // implementations to call the Rust code.\n} When working with these objects, it may be helpful to always pass the interface or protocol, but construct the concrete implementation. For example in Swift: let todoList = TodoList()\ntodoList.addItem(todo: \"Write documentation\")\ndisplay(list: todoList) func display(list: TodoListProtocol) { let items = list.getItems() items.forEach { print($0) }\n} Following this pattern will make it easier for you to provide mock implementation of the Rust-based objects for testing.","breadcrumbs":"The UDL file » Interfaces/Objects » Interfaces/Objects","id":"39","title":"Interfaces/Objects"},"4":{"body":"We're interested in building re-useable components for sync- and storage-related browser functionality - things like storing and syncing passwords , working with bookmarks and signing in to your Firefox Account . We want to write the code for these components once, in Rust. We want to easily re-use these components from all the different languages and on all the different platforms for which we build browsers, which currently includes JavaScript for PCs, Kotlin for Android, and Swift for iOS. And of course, we want to do this in a way that's convenient, maintainable, and difficult to mess up.","breadcrumbs":"Motivation » What?","id":"4","title":"What?"},"40":{"body":"It's possible to have UniFFI expose a Rust trait as an interface by specifying a Trait attribute. For example, in the UDL file you might specify: [Trait]\ninterface Button { string name();\n}; With the following Rust implementation: pub trait Button: Send + Sync { fn name(&self) -> String;\n} struct StopButton {} impl Button for StopButton { fn name(&self) -> String { \"stop\".to_string() }\n} Uniffi explicitly checks all interfaces are Send + Sync - there's a ui-test which demonstrates obscure rust compiler errors when it's not true. Traits however need to explicitly add those bindings. References to traits are passed around like normal interface objects - in an Arc<>. For example, this UDL: namespace traits { sequence