Skip to content

Commit

Permalink
Merge pull request #193 from tauri-apps/feat/async
Browse files Browse the repository at this point in the history
Feat: async host functions
  • Loading branch information
JonasKruckenberg authored Sep 14, 2023
2 parents 99e0a28 + ba766f3 commit c59ba49
Show file tree
Hide file tree
Showing 63 changed files with 4,291 additions and 1,218 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: install native dependecies
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libgtk-3-dev
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
Expand All @@ -54,7 +54,7 @@ jobs:
- name: install native dependecies
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libgtk-3-dev
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.70.0 # MSRV
Expand All @@ -71,7 +71,7 @@ jobs:
- name: install native dependecies
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libgtk-3-dev
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ serde = "1.0.188"
quote = "1.0.33"
proc-macro2 = "1.0.67"
syn = "2.0.33"
tauri = "2.0.0-alpha.14"

[dependencies]
clap.workspace = true
Expand Down
210 changes: 124 additions & 86 deletions crates/gen-host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

use heck::ToKebabCase;
use heck::{ToSnakeCase, ToUpperCamelCase};
use proc_macro2::TokenStream;
use proc_macro2::{Literal, TokenStream};
use quote::format_ident;
use quote::quote;
use std::collections::HashSet;
use std::path::PathBuf;
use tauri_bindgen_core::{Generate, GeneratorBuilder, TypeInfo, TypeInfos};
use tauri_bindgen_gen_rust::{print_generics, BorrowMode, FnSig, RustGenerator};
use wit_parser::{Function, FunctionResult, Interface, Type, TypeDefKind};
use wit_parser::{Function, Interface, Type, TypeDefKind};

#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
Expand Down Expand Up @@ -252,7 +252,7 @@ impl Host {

let functions = functions.map(|func| {
let sig = FnSig {
async_: false,
async_: self.opts.async_,
unsafe_: false,
private: true,
self_arg: Some(quote!(&self)),
Expand All @@ -266,7 +266,13 @@ impl Host {

let sized = sized.then_some(quote!(: Sized));

let async_trait = self
.opts
.async_
.then_some(quote! { #[::tauri_bindgen_host::async_trait] });

quote! {
#async_trait
pub trait #ident #sized {
#(#additional_items)*
#(#functions)*
Expand Down Expand Up @@ -304,114 +310,145 @@ impl Host {
}
}

fn print_add_to_router<'a>(
&self,
mod_ident: &str,
functions: impl Iterator<Item = &'a Function>,
methods: impl Iterator<Item = (&'a str, &'a Function)>,
) -> TokenStream {
let trait_ident = format_ident!("{}", mod_ident.to_upper_camel_case());

let mod_name = mod_ident.to_snake_case();

let functions = functions.map(|func| {
let func_name = func.ident.to_snake_case();
let func_ident = format_ident!("{}", func_name);

let params = self.print_function_params(&func.params, &BorrowMode::Owned);

let param_idents = func
.params
.iter()
.map(|(ident, _)| { format_ident!("{}", ident) });

let result = match func.result.as_ref() {
Some(FunctionResult::Anon(ty)) => {
let ty = self.print_ty(ty, &BorrowMode::Owned);

quote! { #ty }
}
Some(FunctionResult::Named(types)) if types.len() == 1 => {
let (_, ty) = &types[0];
let ty = self.print_ty(ty, &BorrowMode::Owned);

quote! { #ty }
}
Some(FunctionResult::Named(types)) => {
let types = types.iter().map(|(_, ty)| self.print_ty(ty, &BorrowMode::Owned));
fn print_router_fn_definition(&self, mod_name: &str, func: &Function) -> TokenStream {
let func_name = func.ident.to_snake_case();
let func_ident = format_ident!("{}", func_name);

quote! { (#(#types),*) }
}
_ => quote! { () },
};
let param_decl = match func.params.len() {
0 => quote! { () },
1 => {
let ty = &func.params.first().unwrap().1;
let ty = self.print_ty(ty, &BorrowMode::Owned);
quote! { #ty }
}
_ => {
let tys = func
.params
.iter()
.map(|(_, ty)| self.print_ty(ty, &BorrowMode::Owned));
quote! { (#(#tys),*) }
}
};

let param_acc = match func.params.len() {
0 => quote! {},
1 => quote! { p },
_ => {
let ids = func.params.iter().enumerate().map(|(i, _)| {
let i = Literal::usize_unsuffixed(i);
quote! { p.#i }
});
quote! { #(#ids),* }
}
};

if self.opts.async_ {
quote! {
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router.define_async(
#mod_name,
#func_name,
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, p: #param_decl| {
let get_cx = get_cx.clone();
Box::pin(async move {
let ctx = get_cx(ctx.data());
Ok(ctx.#func_ident(#param_acc).await)
})
})?;
}
} else {
quote! {
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router.func_wrap(
router.define(
#mod_name,
#func_name,
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, #params| -> ::tauri_bindgen_host::anyhow::Result<#result> {
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, p: #param_decl| {
let ctx = get_cx(ctx.data());

Ok(ctx.#func_ident(#(#param_idents),*))
Ok(ctx.#func_ident(#param_acc))
},
)?;
}
});

let methods = methods.map(|(resource_name, method)| {
let func_name = method.ident.to_snake_case();
let func_ident = format_ident!("{}", func_name);

let params = self.print_function_params(&method.params, &BorrowMode::Owned);

let param_idents = method
.params
.iter()
.map(|(ident, _)| format_ident!("{}", ident));

let result = match method.result.as_ref() {
Some(FunctionResult::Anon(ty)) => {
let ty = self.print_ty(ty, &BorrowMode::Owned);

quote! { #ty }
}
Some(FunctionResult::Named(types)) if types.len() == 1 => {
let (_, ty) = &types[0];
let ty = self.print_ty(ty, &BorrowMode::Owned);
}
}

quote! { #ty }
}
Some(FunctionResult::Named(types)) => {
let types = types
.iter()
.map(|(_, ty)| self.print_ty(ty, &BorrowMode::Owned));
fn print_router_method_definition(
&self,
mod_name: &str,
resource_name: &str,
method: &Function,
) -> TokenStream {
let func_name = method.ident.to_snake_case();
let func_ident = format_ident!("{}", func_name);

quote! { (#(#types),*) }
}
_ => quote! { () },
};
let param_decl = method
.params
.iter()
.map(|(_, ty)| self.print_ty(ty, &BorrowMode::Owned));

let param_acc = match method.params.len() {
0 => quote! {},
1 => quote! { p.1 },
_ => {
let ids = method.params.iter().enumerate().map(|(i, _)| {
let i = Literal::usize_unsuffixed(i + 1);
quote! { p.#i }
});
quote! { #(#ids),* }
}
};

let mod_name = format!("{mod_name}::resource::{resource_name}");
let get_r_ident = format_ident!("get_{}", resource_name.to_snake_case());
let mod_name = format!("{mod_name}::resource::{resource_name}");
let get_r_ident = format_ident!("get_{}", resource_name.to_snake_case());

if self.opts.async_ {
quote! {
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router.func_wrap(
router.define_async(
#mod_name,
#func_name,
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, p: (::tauri_bindgen_host::ResourceId, #(#param_decl),*)| {
let get_cx = get_cx.clone();
Box::pin(async move {
let ctx = get_cx(ctx.data());
let r = ctx.#get_r_ident(p.0)?;
Ok(r.#func_ident(#param_acc).await)
})
})?;
}
} else {
quote! {
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router.define(
#mod_name,
#func_name,
move |
ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>,
this_rid: ::tauri_bindgen_host::ResourceId,
#params
| -> ::tauri_bindgen_host::anyhow::Result<#result> {
p: (::tauri_bindgen_host::ResourceId, #(#param_decl),*)
| {
let ctx = get_cx(ctx.data());
let r = ctx.#get_r_ident(this_rid)?;

Ok(r.#func_ident(#(#param_idents),*))
let r = ctx.#get_r_ident(p.0)?;
Ok(r.#func_ident(#param_acc))
},
)?;
}
}
}

fn print_add_to_router<'a>(
&self,
mod_ident: &str,
functions: impl Iterator<Item = &'a Function>,
methods: impl Iterator<Item = (&'a str, &'a Function)>,
) -> TokenStream {
let trait_ident = format_ident!("{}", mod_ident.to_upper_camel_case());

let mod_name = mod_ident.to_snake_case();

let functions = functions.map(|func| self.print_router_fn_definition(&mod_name, func));

let methods = methods.map(|(resource_name, method)| {
self.print_router_method_definition(&mod_name, resource_name, method)
});

quote! {
Expand All @@ -420,6 +457,7 @@ impl Host {
get_cx: impl Fn(&T) -> &U + Send + Sync + 'static,
) -> Result<(), ::tauri_bindgen_host::ipc_router_wip::Error>
where
T: Send + Sync + 'static,
U: #trait_ident + Send + Sync + 'static,
{
let wrapped_get_cx = ::std::sync::Arc::new(get_cx);
Expand Down
50 changes: 50 additions & 0 deletions crates/gen-host/tests/async/chars.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#[allow(unused_imports, unused_variables, dead_code)]
#[rustfmt::skip]
pub mod chars {
use ::tauri_bindgen_host::serde;
use ::tauri_bindgen_host::bitflags;
#[::tauri_bindgen_host::async_trait]
pub trait Chars: Sized {
///A function that accepts a character
async fn take_char(&self, x: char);
///A function that returns a character
async fn return_char(&self) -> char;
}
pub fn add_to_router<T, U>(
router: &mut ::tauri_bindgen_host::ipc_router_wip::Router<T>,
get_cx: impl Fn(&T) -> &U + Send + Sync + 'static,
) -> Result<(), ::tauri_bindgen_host::ipc_router_wip::Error>
where
T: Send + Sync + 'static,
U: Chars + Send + Sync + 'static,
{
let wrapped_get_cx = ::std::sync::Arc::new(get_cx);
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router
.define_async(
"chars",
"take_char",
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, p: char| {
let get_cx = get_cx.clone();
Box::pin(async move {
let ctx = get_cx(ctx.data());
Ok(ctx.take_char(p).await)
})
},
)?;
let get_cx = ::std::sync::Arc::clone(&wrapped_get_cx);
router
.define_async(
"chars",
"return_char",
move |ctx: ::tauri_bindgen_host::ipc_router_wip::Caller<T>, p: ()| {
let get_cx = get_cx.clone();
Box::pin(async move {
let ctx = get_cx(ctx.data());
Ok(ctx.return_char().await)
})
},
)?;
Ok(())
}
}
Loading

0 comments on commit c59ba49

Please sign in to comment.