-
Notifications
You must be signed in to change notification settings - Fork 240
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cleanup the docs, splitting UDL or proc-macro details from the genera…
…l concepts. (#2347) For example, types/interfaces.md is generic information about objects/interfaces which applied to both proc_macros and UDL. udl/interfaces.md has info relevant only to UDL and proc_macro/interfaces.md has info relevant only to macros. The general page (types/interfaces.md) has numerous links to the specialized pages. There's a lot more we can do here, but this seems like a nice improvement.
- Loading branch information
Showing
37 changed files
with
1,254 additions
and
1,056 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Describing the interface | ||
|
||
UniFFI allows you to define your object model using both [Procedural Macros](./proc_macro/index.md) | ||
and via stand-alone [UDL files](./udl/index.md). | ||
|
||
Each library can choose to use either or both of these techniques. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Docstrings | ||
|
||
In proc-macros, Rust docstrings will be captured and rendered in the bindings. | ||
|
||
For example: | ||
```rust | ||
/// This is the docstring for MyObject | ||
#[derive(uniffi::Object)] | ||
pub struct MyObject {} | ||
``` | ||
|
||
Will cause Python, Swift and Kotlin to all generate a wrapper for `MyObject` with appropriate docstrings for that language. | ||
|
||
You can see examples of how they are rendered in the [UDL docstrings documentation](../udl/docstrings.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
## The `uniffi::Enum` derive | ||
|
||
The `Enum` derive macro works much like the [`Record`](./records.md) derive macro. Any fields inside variants must | ||
be named. All types that are supported as parameter and return types by `#[uniffi::export]` are | ||
also supported as field types. | ||
|
||
It is permitted to use this macro on a type that is also defined in the UDL file as long as the | ||
two definitions are equal in the names and ordering of variants and variant fields, and any field | ||
types inside variants are UniFFI builtin types; user-defined types might be allowed in the future. | ||
|
||
```rust | ||
#[derive(uniffi::Enum)] | ||
pub enum MyEnum { | ||
Fieldless, | ||
WithFields { | ||
foo: u8, | ||
bar: Vec<i32>, | ||
}, | ||
WithValue = 3, | ||
} | ||
``` | ||
|
||
### Variant Discriminants | ||
|
||
Variant discriminants are accepted by the macro but how they are used depends on the bindings. | ||
|
||
For example this enum: | ||
|
||
```rust | ||
#[derive(uniffi::Enum)] | ||
pub enum MyEnum { | ||
Foo = 3, | ||
Bar = 4, | ||
} | ||
``` | ||
|
||
would give you in Kotlin & Swift: | ||
|
||
```swift | ||
// kotlin | ||
enum class MyEnum { | ||
FOO, | ||
BAR; | ||
companion object | ||
} | ||
// swift | ||
public enum MyEnum { | ||
case foo | ||
case bar | ||
} | ||
``` | ||
|
||
which means you cannot use the platforms helpful methods like `value` or `rawValue` to get the underlying discriminants. Adding a `repr` will allow the type to be defined in the foreign bindings. | ||
|
||
For example: | ||
|
||
```rust | ||
// added the repr(u8), also u16 -> u64 supported | ||
#[repr(u8)] | ||
#[derive(uniffi::Enum)] | ||
pub enum MyEnum { | ||
Foo = 3, | ||
Bar = 4, | ||
} | ||
``` | ||
|
||
will now generate: | ||
|
||
```swift | ||
// kotlin | ||
enum class MyEnum(val value: UByte) { | ||
FOO(3u), | ||
BAR(4u); | ||
companion object | ||
} | ||
|
||
// swift | ||
public enum MyEnum : UInt8 { | ||
case foo = 3 | ||
case bar = 4 | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# The `uniffi::Error` derive | ||
|
||
The `Error` derive registers a type as an error and can be used on any enum that the `Enum` derive also accepts. | ||
By default, it exposes any variant fields to the foreign code. | ||
This type can then be used as the `E` in a `Result<T, E>` return type of an exported function or method. | ||
The generated foreign function for an exported function with a `Result<T, E>` return type | ||
will have the result's `T` as its return type and throw the error in case the Rust call returns `Err(e)`. | ||
|
||
```rust | ||
#[derive(uniffi::Error)] | ||
pub enum MyError { | ||
MissingInput, | ||
IndexOutOfBounds { | ||
index: u32, | ||
size: u32, | ||
} | ||
// tuple-enums work. | ||
Generic(String), | ||
} | ||
|
||
#[uniffi::export] | ||
fn do_thing() -> Result<(), MyError> { | ||
// ... | ||
} | ||
``` | ||
|
||
You can also use the helper attribute `#[uniffi(flat_error)]` to expose just the variants but none of the fields. | ||
In this case the error will be serialized using Rust's `ToString` trait | ||
and will be accessible as the only field on each of the variants. | ||
The types of the fields can be any UniFFI supported type and don't need to implement any special traits. | ||
|
||
```rust | ||
#[derive(uniffi::Error)] | ||
#[uniffi(flat_error)] | ||
pub enum MyApiError { | ||
Http(reqwest::Error), | ||
Json(serde_json::Error), | ||
} | ||
|
||
// ToString is not usually implemented directly, but you get it for free by implementing Display. | ||
// This impl could also be generated by a proc-macro, for example thiserror::Error. | ||
impl std::fmt::Display for MyApiError { | ||
// ... | ||
} | ||
|
||
#[uniffi::export] | ||
fn do_http_request() -> Result<(), MyApiError> { | ||
// ... | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# Functions, Constructors, Methods | ||
|
||
Functions are exported to the namespace with the `#[uniffi::export]` attribute | ||
|
||
```rust | ||
#[uniffi::export] | ||
fn hello_world() -> String { | ||
"Hello World!".to_owned() | ||
} | ||
``` | ||
|
||
All our owned types can be used as arguments and return types. | ||
|
||
Arguments and receivers can also be references to these types, for example: | ||
|
||
```rust | ||
// Input data types as references | ||
#[uniffi::export] | ||
fn process_data(a: &MyRecord, b: &MyEnum, c: &Option<MyRecord>) { | ||
... | ||
} | ||
``` | ||
|
||
To export methods of an interface you can use the [`#[uniffi::export]` attribute on an impl block](./interfaces.md). | ||
|
||
## Default values | ||
|
||
Exported functions/methods can have default values using the `default` argument of the attribute macro that wraps them. | ||
`default` inputs a comma-separated list of `[name]=[value]` items. | ||
|
||
```rust | ||
#[uniffi::export(default(text = " ", max_splits = None))] | ||
pub fn split( | ||
text: String, | ||
sep: String, | ||
max_splits: Option<u32>, | ||
) -> Vec<String> { | ||
... | ||
} | ||
|
||
#[derive(uniffi::Object)] | ||
pub struct TextSplitter { ... } | ||
|
||
#[uniffi::export] | ||
impl TextSplitter { | ||
#[uniffi::constructor(default(ignore_unicode_errors = false))] | ||
fn new(ignore_unicode_errors: boolean) -> Self { | ||
... | ||
} | ||
|
||
#[uniffi::method(default(text = " ", max_splits = None))] | ||
fn split( | ||
text: String, | ||
sep: String, | ||
max_splits: Option<u32>, | ||
) -> Vec<String> { | ||
... | ||
} | ||
} | ||
``` | ||
|
||
Supported default values: | ||
- String, integer, float, and boolean literals | ||
- `[]` for empty Vecs | ||
- `Option<T>` allows either `None` or `Some(T)` | ||
|
||
### Renaming functions, methods and constructors | ||
|
||
A single exported function can specify an alternate name to be used by the bindings by specifying a `name` attribute. | ||
|
||
```rust | ||
#[uniffi::export(name = "something")] | ||
fn do_something() { | ||
} | ||
``` | ||
will be exposed to foreign bindings as a namespace function `something()` | ||
|
||
You can also rename constructors and methods: | ||
```rust | ||
#[uniffi::export] | ||
impl Something { | ||
// Set this as the default constructor by naming it `new` | ||
#[uniffi::constructor(name = "new")] | ||
fn make_new() -> Arc<Self> { ... } | ||
|
||
// Expose this as `obj.something()` | ||
#[uniffi::method(name = "something")] | ||
fn do_something(&self) { } | ||
} | ||
``` |
Oops, something went wrong.