Tauri Bindgen Versions Save

Typesafe language bindings generator for the Tauri IPC bridge

v0.2.0

11 months ago

🔦 Highlights

New IPC Router

As part of the ongoing IPC improvements for Tauri, we're working on a new IPC router that is faster, simpler, offers a better developer experience than the current one and brings new features to the table that weren't possible before.

This release let's you play with a preview WIP version of this router (re-exported as tauri_bindgen_host::ipc_router_wip). Defining commands looks like this now:

use tauri_bindgen_host::ipc_router_wip::{Router, BuilderExt};

fn main() {
    // notice that router is generic, this is the so called "Context"
    // for this simple example we don't need to worry about it
    let mut router = Router::new(());

    router.func_wrap("app", "foo", || -> tauri_bindgen_host::Result<()> {
        println!("foo");

        Ok(())
    });

    router.func_wrap("app", "add", |a: u32, b: u32| -> tauri_bindgen_host::Result<u32> {
        Ok(a + b)
    });

    tauri::Builder::default()
        .ipc_router(router)
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

The Router keeps track of all the commands defined within it, as well as maintaining "Context" data that your commands can access:

use tauri_bindgen_host::ipc_router_wip::{Router, Caller, BuilderExt};

fn main() {
    #[derive(Default)]
    struct Context {
        ch: Option<char>
    }

    let mut router = Router::new(Context::default());

    router.func_wrap("app", "take_char", |ctx:: Caller<Context>, ch: char| -> tauri_bindgen_host::Result<()> {
        ctx.data_mut().ch = Some(ch);

        Ok(())
    })

    router.func_wrap("app", "return_char", |ctx:: Caller<Context>| -> tauri_bindgen_host::Result<Option<ch>> {
        Ok(ctx.data_mut().ch.take())
    })

    tauri::Builder::default()
        .ipc_router(router)
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

When using tauri-bindgens code generation, the generated module exports an add_to_router function that takes care of defining your commands for you:

use tauri_bindgen_host::ipc_router_wip::{Router, Caller, BuilderExt};

tauri_bindgen_host::generate!({
    path: "example/chars.wit"
});

#[derive(Default)]
struct CharsCtx {
    ch: Option<char>
}

impl chars::Chars for CharsCtx {
    fn take_char(&mut self, ch: char) -> tauri_bindgen_host::Result<()> {
        self.ch = Some(ch);
        Ok(())
    }

    fn return_char(&mut self) -> tauri_bindgen_host::Result<Option<char>> {
        Ok(self.ch.take())
    }
}

fn main() {
    #[derive(Default)]
    struct Context {
        chars_ctx: CharsCtx
    }

    let mut router = Router::new(Context::default());

    chars::add_to_router(&mut router, |ctx| ctx.chars_ctx)

    tauri::Builder::default()
        .ipc_router(router)
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Note All of this is subject to change over time, feel free to give feedback!

This WIP IPC router implementation also packs another cool punch: It uses a custom protocol to transmit messages between the Webview and Core. This means that performance will be much better and we finally have support for sending arbitrary binary payloads something we make use of for the next feature:

New Data Serialization Format

One bottleneck we identified is that dues to web view limitations the current IPC system is limited to sending JSON. This caused many problems, for one JSON can't encode arbitrary binary data, so sending bytes across the IPC boundary was a big performance issue. Another problem is the the overly simplistic type system of JSON, we would love to send Option<T> or Result<T, E> values across the IPC boundary and have them be preserved correctly, but not with JSON.

That's why this release also switches to a new data serialisation format: postcard. This means IPC messages are much smaller, support sending binary data without overhead and allow more expressive types.

Stabilized host, guest rust, guest javascript, and guest typescript Codegen Targets

All these changes means that almost all of this project is now in a state where I would consider it usable. So all targets except for markdown doc generation will be enabled by default now.

Known issues with guest javascript and guest typescript

Currently the javascript targets have a couple known issues pertaining to the encoding and decoding:

  1. u64 and s64 JavaScript's number type can't represent u64 and s64 numbers, so sending them across the IPC boundary currently results in wrong data. We are still discussing a way forward here (BigInt would be the suitable type for u64, but for s64?), take a look at #122
  2. nested option<T> Currently we decode option<T> types as T | null but that means that means nested options aren't preserved. If you have ideas around this take a look at #123

v0.1.1

1 year ago

🔦 Highlights

Initial resource implementation

This adds the initial implementation of the resource type.

A resource represents a handle to a resource owned by the Host - similar to a file descriptor in posix - resources have associated methods that allow Guests to interact with them. A resource is essentially just syntactic sugar for a u64. This identifier is guaranteed to be unique and will be used by the Host to index into a ResourceTable to retrieve the actual data backing the resource.

interface foo {
    resource bar {
        func greet(name: string) -> string
    }

    func get_bar() -> bar
}

This represents an important addition to the type system of tauri-bindgen as resources allow us to better model many real-world situations (like Tauri's Window objects) while minimising the amount of data being sent over the IPC bridge as well as restricting Guests access to system resources.

To try this initial implementation, enable the unstable feature flag.

Fixes

Better code generation empty return types

Previously in some situations functions that didn't return anything (func foo(x: string)) would generate code that returned an empty tuple. This version doesn't generate these empty tuples anymore, making generated code easier to use.

Reject deprecated or invalid unicode characters

Files containing deprecated or discouraged unicode code points will now be rejected, this makes .wit files more portable and reliable as a IDL format.

Fixed parsing of comments containing non-latin script characters

Previously parsing a .wit file with comments that contained non-latin unicode code points would cause a panic. This version fixes that issue which means comments can be written in all scripts supported by unicode.

v0.1.0

1 year ago

🔦 Highlights

Online playground

There is now an online version of this tool!

It always reflects the latest developments and allows you to play around with the interface definition language and see the code generated results or any produced errors. It is very bare bones right now, but it will receive more features and better design as time goes on.

Visit bindgen.tauri.tech to check it out!

New check subcommand

The tauri-bindgen command let's you check .wit files for errors.

Currently check makes sure no identifier is undefined or defined twice, that types aren't recursively referring to themselves and that no type definitions are unused.

Stabilized syntax

This release also stabilized the syntax and grammar of .wit files.

This means that no breaking changes in the file format are expected! You can find details about the interface definition language in the docs subfolder.

New Rust codegen

The rust code generation has been completely rewritten from scratch to use the quote, proc_macro2 and syn crates.

This makes rust code generation much more maintainable, easier to reason about and much more future proof than the old string based approach. The refactor is not yet complete though, so for the time being all code generation is hidden behind the unstable flag. Stay tuned to a future release when this restriction is lifted.