Skip to content

Commit 3fd6661

Browse files
authored
[workerd-cxx] rust->c++ future passing (#19)
1 parent 867a8b4 commit 3fd6661

File tree

5 files changed

+94
-19
lines changed

5 files changed

+94
-19
lines changed

gen/src/write.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,9 @@ fn write_rust_function_decl_impl(
941941
}
942942
write!(out, "*");
943943
}
944+
Type::Future(_) => {
945+
write!(out, "::kj_rs::repr::RustFuture ");
946+
}
944947
ret => write_type_space(out, ret),
945948
}
946949
write!(out, "*return$");
@@ -1050,6 +1053,9 @@ fn write_rust_function_shim_impl(
10501053
}
10511054
write!(out, "*");
10521055
}
1056+
Type::Future(_) => {
1057+
write!(out, "::kj_rs::repr::RustFuture");
1058+
}
10531059
ret => write_type(out, ret),
10541060
}
10551061
writeln!(out, "> return$;");

macro/src/expand.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::type_id::Crate;
1414
use crate::{derive, generics};
1515
use proc_macro2::{Ident, Span, TokenStream};
1616
use quote::{format_ident, quote, quote_spanned, ToTokens};
17-
use syn::spanned::Spanned;
1817
use std::mem;
18+
use syn::spanned::Spanned;
1919
use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token};
2020

2121
pub(crate) fn bridge(mut ffi: Module) -> Result<TokenStream> {
@@ -87,7 +87,12 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
8787
expanded.extend(expand_rust_type_impl(ety));
8888
hidden.extend(expand_rust_type_layout(ety, types));
8989
}
90-
Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
90+
Api::RustFunction(efn) => {
91+
if efn.asyncness.is_some() {
92+
// todo!("expand_rust_function_shim\n{}", expand_rust_function_shim(efn, types).to_string());
93+
}
94+
hidden.extend(expand_rust_function_shim(efn, types));
95+
}
9196
Api::TypeAlias(alias) => {
9297
expanded.extend(expand_type_alias(alias));
9398
hidden.extend(expand_type_alias_verify(alias, types));
@@ -723,10 +728,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
723728
false => quote_spanned!(span=> #call.as_slice::<#inner>()),
724729
true => quote_spanned!(span=> #call.as_mut_slice::<#inner>()),
725730
}
726-
},
731+
}
727732
Type::Future(_) => {
728733
quote_spanned!(span=> ::kj_rs::new_callbacks_promise_future(#call))
729-
},
734+
}
730735
_ => call,
731736
},
732737
};
@@ -1115,6 +1120,11 @@ fn expand_rust_function_shim_impl(
11151120
false => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_ref)),
11161121
true => Some(quote_spanned!(span=> ::cxx::private::RustSlice::from_mut)),
11171122
},
1123+
Type::Future(fut) => if fut.throws_tokens.is_some() {
1124+
Some(quote_spanned!(span=> ::kj_rs::repr::future))
1125+
} else {
1126+
Some(quote_spanned!(span=> ::kj_rs::repr::infallible_future))
1127+
},
11181128
_ => None,
11191129
});
11201130

@@ -1132,7 +1142,17 @@ fn expand_rust_function_shim_impl(
11321142

11331143
// always indirect return when there's a return value
11341144
let out_param = sig.ret.as_ref().map(|ret| {
1135-
let ret = expand_extern_type(ret, types, false);
1145+
let ret = if let Type::Future(fut) = ret {
1146+
let span = sig.ret.span();
1147+
let output = &fut.output;
1148+
if fut.throws_tokens.is_some() {
1149+
quote_spanned!(span=>::kj_rs::repr::RustFuture::<#output>)
1150+
} else {
1151+
quote_spanned!(span=>::kj_rs::repr::RustInfallibleFuture::<#output>)
1152+
}
1153+
} else {
1154+
expand_extern_type(ret, types, false)
1155+
};
11361156
quote_spanned!(span=> __return: *mut #ret,)
11371157
});
11381158
let out = match sig.ret {
@@ -1223,6 +1243,13 @@ fn expand_rust_function_shim_super(
12231243
quote_spanned!(rangle.span=> ::cxx::core::fmt::Display>)
12241244
};
12251245
quote!(-> #result_begin #result_end)
1246+
} else if let Some(Type::Future(fut)) = &sig.ret {
1247+
let output = &fut.output;
1248+
if fut.throws_tokens.is_some() {
1249+
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = ::std::result::Result<#output, String>> + Send>>)
1250+
} else {
1251+
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = #output> + Send>>)
1252+
}
12261253
} else {
12271254
expand_return_type(&sig.ret)
12281255
};
@@ -1239,7 +1266,15 @@ fn expand_rust_function_shim_super(
12391266
}
12401267
};
12411268

1242-
let mut body = quote_spanned!(span=> #call(#(#vars,)*));
1269+
let mut body = if let Some(Type::Future(fut)) = &sig.ret {
1270+
if fut.throws_tokens.is_some() {
1271+
quote_spanned!(span=> Box::pin(async move {#call(#(#vars,)*).await.map_err(|e| e.to_string())}))
1272+
} else {
1273+
quote_spanned!(span=> Box::pin(#call(#(#vars,)*)))
1274+
}
1275+
} else {
1276+
quote_spanned!(span=> #call(#(#vars,)*))
1277+
};
12431278
let mut allow_unused_unsafe = None;
12441279
if unsafety.is_some() {
12451280
body = quote_spanned!(span=> unsafe { #body });
@@ -1939,8 +1974,8 @@ fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
19391974
let rust_slice = Ident::new("RustSlice", ty.bracket.span.join());
19401975
quote_spanned!(span=> ::cxx::private::#rust_slice)
19411976
}
1942-
Type::Future(ty) => {
1943-
let span = ty.span();
1977+
Type::Future(output) => {
1978+
let span = output.span();
19441979
quote_spanned!(span=> ::kj_rs::KjPromiseNodeImpl)
19451980
}
19461981
_ => quote!(#ty),

syntax/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ pub(crate) struct Array {
322322

323323
pub(crate) struct Future {
324324
pub output: Type,
325+
pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
325326
}
326327

327328
#[derive(Copy, Clone, PartialEq)]

syntax/parse.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use syn::{
1818
Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
1919
GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
2020
Pat, PathArguments, Result, ReturnType, Signature as RustSignature, Token, TraitBound,
21-
TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound,
22-
TypePath, TypePtr, TypeReference, Variant as RustVariant, Visibility,
21+
TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypePtr,
22+
TypeReference, Variant as RustVariant, Visibility,
2323
};
2424

2525
pub(crate) mod kw {
@@ -649,13 +649,19 @@ fn parse_extern_fn(
649649

650650
let mut throws_tokens = None;
651651
let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
652-
let throws = throws_tokens.is_some();
653652
let asyncness = foreign_fn.sig.asyncness;
654-
let ret = if asyncness.is_some() {
655-
Some(Type::Future(Box::new(Future{ output: ret.unwrap_or(Type::Void(foreign_fn.sig.fn_token.span)) })))
653+
let (ret, throws_tokens) = if asyncness.is_some() {
654+
(
655+
Some(Type::Future(Box::new(Future {
656+
output: ret.unwrap_or(Type::Void(foreign_fn.sig.fn_token.span)),
657+
throws_tokens,
658+
}))),
659+
None,
660+
)
656661
} else {
657-
ret
662+
(ret, throws_tokens)
658663
};
664+
let throws = throws_tokens.is_some();
659665
let unsafety = foreign_fn.sig.unsafety;
660666
let fn_token = foreign_fn.sig.fn_token;
661667
let inherited_span = unsafety.map_or(fn_token.span, |unsafety| unsafety.span);

tests/kj-rs/lib.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#![allow(dead_code)]
2+
#![allow(clippy::unused_async)]
3+
4+
type Result<T> = std::io::Result<T>;
5+
16
#[cxx::bridge(namespace = "kj_rs")]
27
pub mod ffi {
38
struct Shared {
@@ -8,13 +13,35 @@ pub mod ffi {
813
include!("tests/kj-rs/tests.h");
914

1015
async fn c_async_void_fn();
16+
async fn c_async_int_fn() -> i64;
17+
async fn c_async_struct_fn() -> Shared;
18+
}
1119

12-
// todo
13-
// async fn c_async_int_fn() -> i64;
14-
// async fn c_async_struct_fn() -> Shared;
20+
extern "Rust" {
21+
// todo(soon): enable once kj-rs side is landed.
22+
//
23+
// async fn rust_async_void_fn();
24+
// async fn rust_async_int_fn() -> i64;
25+
26+
// async fn rust_async_void_result_fn() -> Result<()>;
27+
// async fn rust_async_int_result_fn() -> Result<i64>;
1528
}
1629
}
1730

31+
async fn rust_async_void_fn() {
32+
}
33+
34+
async fn rust_async_int_fn() -> i64 {
35+
42
36+
}
37+
38+
async fn rust_async_void_result_fn() -> Result<()> {
39+
Ok(())
40+
}
41+
42+
async fn rust_async_int_result_fn() -> Result<i64> {
43+
Ok(42)
44+
}
1845

1946
#[cfg(test)]
2047
mod tests {
@@ -25,7 +52,7 @@ mod tests {
2552
#[test]
2653
fn compilation() {
2754
let _ = ffi::c_async_void_fn();
28-
// let _ = ffi::c_async_int_fn();
29-
// let _ = ffi::c_async_struct_fn();
55+
let _ = ffi::c_async_int_fn();
56+
let _ = ffi::c_async_struct_fn();
3057
}
3158
}

0 commit comments

Comments
 (0)