Skip to content

Commit 38f1341

Browse files
committed
POC on having non-static closure in TransactionBuilder::run
1 parent 340492d commit 38f1341

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

src/transaction.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,8 @@ impl<Err> TransactionBuilder<Err> {
100100
// untested and unsupported code path.
101101
pub async fn run<Ret>(
102102
self,
103-
transaction: impl 'static + AsyncFnOnce(Transaction<Err>) -> crate::Result<Ret, Err>,
103+
transaction: impl AsyncFnOnce(Transaction<Err>) -> crate::Result<Ret, Err>,
104104
) -> crate::Result<Ret, Err>
105-
where
106-
Ret: 'static,
107-
Err: 'static,
108105
{
109106
let t = self
110107
.db
@@ -131,7 +128,19 @@ impl<Err> TransactionBuilder<Err> {
131128
return_value
132129
}
133130
};
134-
unsafe_jar::run(t, fut);
131+
132+
let fut_pin = std::pin::pin!(fut);
133+
let fut_pin_with_dyn_dispatch: std::pin::Pin<&mut dyn std::future::Future<Output=Result<(), ()>>> = fut_pin;
134+
// SAFETY: this is fine as long as we don't return from the current function since
135+
// the future is pinned here.
136+
let fut_pin_with_dyn_dispatch_and_static_lifetime: std::pin::Pin<&'static mut dyn std::future::Future<Output=Result<(), ()>>> = unsafe { std::mem::transmute(fut_pin_with_dyn_dispatch) };
137+
// TODO: A possible safety could be added to ensure the future is not polled after
138+
// the current function has returned (which would cause UB).
139+
// The idea would be to check `tx.is_cancelled()` is false before polling the
140+
// `Pin<&dyn Future> reference on the future (since this check indicates that `rx`
141+
// still exists, which itself lives in this function just like our pinned future).
142+
143+
unsafe_jar::run(t, fut_pin_with_dyn_dispatch_and_static_lifetime);
135144
let res = rx.await;
136145
if unsafe_jar::POLLED_FORBIDDEN_THING.get() {
137146
panic!("Transaction blocked without any request under way");

tests/common/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,28 @@ async fn smoke_test() {
214214
})
215215
.await
216216
.unwrap();
217+
218+
// Run a non-static async function
219+
let key = "key2".to_string();
220+
let value = "value2".to_string();
221+
let key_ref = key.as_ref();
222+
let value_ref = value.as_ref();
223+
224+
db.transaction(&["objects"])
225+
.rw()
226+
.run(async move |t| {
227+
let objects = t.object_store("objects")?;
228+
229+
objects
230+
.add_kv(&JsString::from(key_ref), &JsString::from(value_ref))
231+
.await?;
232+
assert_eq!(
233+
objects.get(&JsString::from(key_ref)).await?.unwrap(),
234+
**JsString::from(value_ref)
235+
);
236+
237+
Ok(())
238+
}).await.unwrap();
217239
}
218240

219241
#[wasm_bindgen_test]

0 commit comments

Comments
 (0)