Skip to content
This repository has been archived by the owner on Dec 4, 2023. It is now read-only.

Commit

Permalink
solved merge
Browse files Browse the repository at this point in the history
  • Loading branch information
MeerKatDev committed Oct 26, 2023
2 parents 10c37b4 + 2fdaae1 commit 3116377
Show file tree
Hide file tree
Showing 175 changed files with 5,228 additions and 3,142 deletions.
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ orbs:
jobs:
Check Rust formatting:
docker:
- image: cimg/rust:1.69
- image: cimg/rust:1.72
resource_class: small
steps:
- checkout
Expand All @@ -49,7 +49,7 @@ jobs:
- run: cargo fmt -- --check
Lint Rust with clippy:
docker:
- image: cimg/rust:1.69
- image: cimg/rust:1.72
resource_class: small
steps:
- checkout
Expand All @@ -59,7 +59,7 @@ jobs:
- run: cargo clippy --all --all-targets -- -D warnings
Lint Rust Docs:
docker:
- image: cimg/rust:1.69
- image: cimg/rust:1.72
resource_class: small
steps:
- checkout
Expand Down Expand Up @@ -117,7 +117,7 @@ jobs:
- run: cargo test -- --skip trybuild_ui_tests
Deploy website:
docker:
- image: cimg/rust:1.69
- image: cimg/rust:1.72
resource_class: small
steps:
- checkout
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
[All changes in [[UnreleasedUniFFIVersion]]](https://github.com/mozilla/uniffi-rs/compare/v0.24.3...HEAD).

### What's new
- Proc-macros can now expose standard Rust traits (eg, `Display`, `Eq`, etc)
- Fixed issues when trying to combine UDL and procmacros in the same crate when the "namespace" is
different from the crate name. This meant that the "ffi namespace" has changed to consistently be
the crate name, rather than either the crate name or the namespace name depending on whether the
Expand All @@ -33,12 +34,21 @@
- Proc-macros: Added support for ByRef arguments
- Proc-macros: Implemented custom type conversion error handling (https://mozilla.github.io/uniffi-rs/udl/custom_types.html#error-handling-during-conversion)
- Error types must now implement `Error + Send + Sync + 'static`.
- Proc-macros: The `handle_unknown_callback_error` attribute is no longer needed for callback
interface errors
- Foreign types can now implement trait interfaces

### What's Fixed

- Updated the async functionality to correctly handle cancellation (#1669)
- Kotlin: Fixed low-level issue with exported async APIs

### What's changed?

- Implementing `From<uniffi::UnexpectedUniFFICallbackError` is now optional for callback interface error types.
If the error type implements that, things will continue to work as before.
If not, then any unexpected callback error will result in a Rust panic.

## v0.24.3 (backend crates: v0.24.3) - (_2023-08-01_)

[All changes in v0.24.3](https://github.com/mozilla/uniffi-rs/compare/v0.24.2...v0.24.3).
Expand Down
27 changes: 14 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions docs/manual/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,28 @@
- [Procedural Macros: Attributes and Derives](./proc_macro/index.md)
- [Futures and async support](./futures.md)

# Kotlin
# Bindings

- [Generating bindings](./bindings)
- [Customizing binding generation](./bindings#customizing-the-binding-generation)
- [Implementing Rust traits in foreign bindings](./foreign_traits)

## Kotlin

- [Configuration](./kotlin/configuration)
- [Integrating with Gradle](./kotlin/gradle.md)
- [Kotlin Lifetimes](./kotlin/lifetimes.md)

# Swift
## Swift

- [Overview](./swift/overview.md)
- [Configuration](./swift/configuration.md)
- [Building a Swift module](./swift/module.md)
- [Integrating with Xcode](./swift/xcode.md)

## Python
- [Configuration](./python/configuration)

# Internals
- [Design Principles](./internals/design_principles.md)
- [Navigating the Code](./internals/crates.md)
Expand Down
16 changes: 16 additions & 0 deletions docs/manual/src/bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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
examples.

UniFFI comes with a `uniffi_bindgen` which generates these bindings. For introductory
information, see [Foreign Language Bindings in the tutorial](./tutorial/foreign_language_bindings.md)

# Customizing the binding generation.

Each of the bindings reads a file `uniffi.toml` in the root of a crate which supports
various options which influence how the bindings are generated. Default options will be used
if this file is missing.

Each binding supports different options, so please see the documentation for each binding language.
146 changes: 146 additions & 0 deletions docs/manual/src/foreign_traits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Foreign traits

UniFFI traits can be implemented by foreign code.
This means traits implemented in Python/Swift/Kotlin etc can provide Rust code with capabilities not easily implemented in Rust, such as:

* device APIs not directly available to Rust.
* provide glue to clip together Rust components at runtime.
* access shared resources and assets bundled with the app.

# Example

To implement a Rust trait in a foreign language, you might:

## 1. Define a Rust trait

This toy example defines a way of Rust accessing a key-value store exposed
by the host operating system (e.g. the key chain).

All methods of the Rust trait should return a `Result<>` with the error half being
a [compatible error type](./udl/errors.md) - see below for more on error handling.

For example:

```rust,no_run
pub trait Keychain: Send + Sync + Debug {
fn get(&self, key: String) -> Result<Option<String>, KeyChainError>;
fn put(&self, key: String, value: String) -> Result<(), KeyChainError>;
}
```

If you are using macros add `#[uniffi::export]` above the trait.
Otherwise define this trait in your UDL file:

```webidl
[Trait]
interface Keychain {
[Throws=KeyChainError]
string? get(string key);
[Throws=KeyChainError]
void put(string key, string data);
};
```

## 2. Allow it to be passed into Rust

Here, we define a new object with a constructor which takes a keychain.

```webidl
interface Authenticator {
constructor(Keychain keychain);
void login();
};
```

In Rust we'd write:

```rust,no_run
struct Authenticator {
keychain: Arc<dyn Keychain>,
}
impl Authenticator {
pub fn new(keychain: Arc<dyn Keychain>) -> Self {
Self { keychain }
}
pub fn login(&self) {
let username = self.keychain.get("username".into());
let password = self.keychain.get("password".into());
}
}
```

## 3. Create a foreign language implementation of the trait

Here's a Kotlin implementation:

```kotlin
class KotlinKeychain: Keychain {
override fun get(key: String): String? {
// … elide the implementation.
return value
}
override fun put(key: String) {
// … elide the implementation.
}
}
```

…and Swift:

```swift
class SwiftKeychain: Keychain {
func get(key: String) -> String? {
// … elide the implementation.
return value
}
func put(key: String) {
// … elide the implementation.
}
}
```

## 4. Pass the implementation to Rust

Again, in Kotlin

```kt
val authenticator = Authenticator(KotlinKeychain())
// later on:
authenticator.login()
```

and in Swift:

```swift
let authenticator = Authenticator(SwiftKeychain())
// later on:
authenticator.login()
```

Care is taken to ensure that things are cleaned up in the foreign language once all Rust references drop.

## ⚠️ Avoid cycles

Foreign trait implementations make it easy to create cycles between Rust and foreign objects causing memory leaks.
For example a foreign implementation holding a reference to a Rust object which also holds a reference to the same foreign implementation.

UniFFI doesn't try to help here and there's no universal advice; take the usual precautions.

# Error handling

We must handle foreign code failing, so all methods of the Rust trait should return a `Result<>` with a [compatible error type](./udl/errors.md) otherwise these errors will panic.

## Unexpected Error handling.

So long as your function returns a `Result<>`, it's possible for you to define how "unexpected" errors
(ie, errors not directly covered by your `Result<>` type, panics, etc) are converted to your `Result<>`'s `Err`.

If your code defines a `From<uniffi::UnexpectedUniFFICallbackError>` impl for your error type, then those errors will be converted into your error type which will be returned to the Rust caller.
If your code does not define this implementation the generated code will panic.
In other words, you really should implement this!

See our [callbacks example](https://github.com/mozilla/uniffi-rs/tree/main/examples/callbacks) for more.

Loading

0 comments on commit 3116377

Please sign in to comment.