Skip to content

Commit dc79287

Browse files
authored
[workerd-cxx] rust future lifetimes support (#25)
Futures capture all lifetimes. We need to generate code appropriately in such a case. Part of kj::AsyncInputStream implementation effort.
1 parent 4fff6f2 commit dc79287

File tree

4 files changed

+58
-19
lines changed

4 files changed

+58
-19
lines changed

kj-rs/future.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,22 @@ pub(crate) mod repr {
3838

3939
type DropCallback = unsafe extern "C" fn(fut: *mut c_void);
4040

41-
type FuturePtr<T> = *mut (dyn Future<Output = Result<T, String>> + Send);
41+
type FuturePtr<'a, T> = *mut (dyn Future<Output = Result<T, String>> + Send + 'a);
4242

4343
/// Represents a `dyn Future<Output = Result<T, String>>` + Send.
4444
#[repr(C)]
45-
pub struct RustFuture<T> {
46-
pub fut: FuturePtr<T>,
45+
pub struct RustFuture<'a, T> {
46+
pub fut: FuturePtr<'a, T>,
4747
pub poll: PollCallback,
4848
pub drop: DropCallback,
4949
}
5050

51-
type InfallibleFuturePtr<T> = *mut (dyn Future<Output = T> + Send);
51+
type InfallibleFuturePtr<'a, T> = *mut (dyn Future<Output = T> + Send + 'a);
5252

5353
/// Represents a `dyn Future<Output = T> + Send` where T is not a Result.
5454
#[repr(C)]
55-
pub struct RustInfallibleFuture<T> {
56-
pub fut: InfallibleFuturePtr<T>,
55+
pub struct RustInfallibleFuture<'a, T> {
56+
pub fut: InfallibleFuturePtr<'a, T>,
5757
pub poll: PollCallback,
5858
pub drop: DropCallback,
5959
}
@@ -65,7 +65,7 @@ pub(crate) mod repr {
6565
assert_eq_size!(RustFuture<()>, [*mut c_void; 4]);
6666
assert_eq_size!(RustInfallibleFuture<()>, [*mut c_void; 4]);
6767

68-
impl<T: Unpin> RustFuture<T> {
68+
impl<T: Unpin> RustFuture<'_, T> {
6969
pub(crate) unsafe extern "C" fn poll(
7070
fut: *mut c_void,
7171
waker: *const c_void,
@@ -97,7 +97,7 @@ pub(crate) mod repr {
9797
}
9898
}
9999

100-
impl<T: Unpin> RustInfallibleFuture<T> {
100+
impl<T: Unpin> RustInfallibleFuture<'_, T> {
101101
pub(crate) unsafe extern "C" fn poll(
102102
fut: *mut c_void,
103103
waker: *const c_void,
@@ -126,19 +126,19 @@ pub(crate) mod repr {
126126
}
127127

128128
#[must_use]
129-
pub fn future<T: Unpin>(
130-
fut: Pin<Box<dyn Future<Output = Result<T, String>> + Send>>,
131-
) -> RustFuture<T> {
129+
pub fn future<'a, T: Unpin>(
130+
fut: Pin<Box<dyn Future<Output = Result<T, String>> + Send + 'a>>,
131+
) -> RustFuture<'a, T> {
132132
let fut = Box::into_raw(unsafe { Pin::into_inner_unchecked(fut) });
133133
let poll = RustFuture::<T>::poll;
134134
let drop = RustFuture::<T>::drop_in_place;
135135
RustFuture { fut, poll, drop }
136136
}
137137

138138
#[must_use]
139-
pub fn infallible_future<T: Unpin>(
140-
fut: Pin<Box<dyn Future<Output = T> + Send>>,
141-
) -> RustInfallibleFuture<T> {
139+
pub fn infallible_future<'a, T: Unpin>(
140+
fut: Pin<Box<dyn Future<Output = T> + Send + 'a>>,
141+
) -> RustInfallibleFuture<'a, T> {
142142
let fut = Box::into_raw(unsafe { Pin::into_inner_unchecked(fut) });
143143
let poll = RustInfallibleFuture::<T>::poll;
144144
let drop = RustInfallibleFuture::<T>::drop_in_place;

kj-rs/tests/BUILD.bazel

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load("@rules_cc//cc:defs.bzl", "cc_library")
2-
load("@rules_rust//rust:defs.bzl", "rust_library")
2+
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
33
load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
44

55
# https://bazel.build/configure/windows#clang
@@ -24,6 +24,14 @@ rust_library(
2424
],
2525
)
2626

27+
rust_test(
28+
name = "awaitables-rust_test",
29+
crate = "awaitables-rust",
30+
deps = [
31+
":test-promises",
32+
],
33+
)
34+
2735
rust_cxx_bridge(
2836
name = "bridge",
2937
src = "lib.rs",

kj-rs/tests/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#![allow(clippy::needless_lifetimes)]
2+
#![allow(clippy::missing_errors_doc)]
3+
#![allow(clippy::unused_async)]
4+
15
mod test_futures;
26

37
use test_futures::{
@@ -59,4 +63,17 @@ mod ffi {
5963
async fn new_awaiting_future_i32() -> Result<()>;
6064
async fn new_ready_future_i32(value: i32) -> Result<i32>;
6165
}
66+
67+
// these are used to check compilation only
68+
extern "Rust" {
69+
70+
async unsafe fn lifetime_arg_void<'a>(buf: &'a [u8]);
71+
async unsafe fn lifetime_arg_result<'a>(buf: &'a [u8]) -> Result<()>;
72+
}
73+
}
74+
75+
pub async fn lifetime_arg_void<'a>(_buf: &'a [u8]) {}
76+
77+
pub async fn lifetime_arg_result<'a>(_buf: &'a [u8]) -> Result<()> {
78+
Ok(())
6279
}

macro/src/expand.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,10 +1145,17 @@ fn expand_rust_function_shim_impl(
11451145
let ret = if let Type::Future(fut) = ret {
11461146
let span = sig.ret.span();
11471147
let output = &fut.output;
1148+
let lifetimes: Vec<_> = sig.generics.lifetimes().map(|lt| quote!(#lt)).collect();
1149+
let lifetimes = if lifetimes.is_empty() {
1150+
quote!()
1151+
} else {
1152+
assert_eq!(lifetimes.len(), 1, "workerd-cxx: expected single lifetime (todo: do we need to support multiple?)");
1153+
quote!(#(#lifetimes),*, )
1154+
};
11481155
if fut.throws_tokens.is_some() {
1149-
quote_spanned!(span=> ::kj_rs::repr::RustFuture::<#output>)
1156+
quote_spanned!(span=> ::kj_rs::repr::RustFuture::<#lifetimes #output>)
11501157
} else {
1151-
quote_spanned!(span=> ::kj_rs::repr::RustInfallibleFuture::<#output>)
1158+
quote_spanned!(span=> ::kj_rs::repr::RustInfallibleFuture::<#lifetimes #output>)
11521159
}
11531160
} else {
11541161
expand_extern_type(ret, types, false)
@@ -1245,10 +1252,17 @@ fn expand_rust_function_shim_super(
12451252
quote!(-> #result_begin #result_end)
12461253
} else if let Some(Type::Future(fut)) = &sig.ret {
12471254
let output = &fut.output;
1255+
let lifetimes: Vec<_> = sig.generics.lifetimes().map(|lt| quote!(#lt)).collect();
1256+
let lifetimes = if lifetimes.is_empty() {
1257+
quote!()
1258+
} else {
1259+
quote!( + #(#lifetimes)+* )
1260+
};
1261+
12481262
if fut.throws_tokens.is_some() {
1249-
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = ::std::result::Result<#output, String>> + Send>>)
1263+
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = ::std::result::Result<#output, String>> + Send #lifetimes>>)
12501264
} else {
1251-
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = #output> + Send>>)
1265+
quote!(-> std::pin::Pin<Box<dyn ::std::future::Future<Output = #output> + Send #lifetimes>>)
12521266
}
12531267
} else {
12541268
expand_return_type(&sig.ret)

0 commit comments

Comments
 (0)