@@ -100,11 +100,8 @@ impl<Err> TransactionBuilder<Err> {
100
100
// untested and unsupported code path.
101
101
pub async fn run < Ret > (
102
102
self ,
103
- transaction : impl ' static + AsyncFnOnce ( Transaction < Err > ) -> crate :: Result < Ret , Err > ,
103
+ transaction : impl AsyncFnOnce ( Transaction < Err > ) -> crate :: Result < Ret , Err > ,
104
104
) -> crate :: Result < Ret , Err >
105
- where
106
- Ret : ' static ,
107
- Err : ' static ,
108
105
{
109
106
let t = self
110
107
. db
@@ -131,7 +128,19 @@ impl<Err> TransactionBuilder<Err> {
131
128
return_value
132
129
}
133
130
} ;
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) ;
135
144
let res = rx. await ;
136
145
if unsafe_jar:: POLLED_FORBIDDEN_THING . get ( ) {
137
146
panic ! ( "Transaction blocked without any request under way" ) ;
0 commit comments