@@ -5,17 +5,18 @@ use crate::cass_error::CassErrorMessage;
5
5
use crate :: cass_error:: ToCassError ;
6
6
use crate :: execution_error:: CassErrorResult ;
7
7
use crate :: prepared:: CassPrepared ;
8
- use crate :: query_result:: CassResult ;
8
+ use crate :: query_result:: { CassNode , CassResult } ;
9
9
use crate :: types:: * ;
10
10
use crate :: uuid:: CassUuid ;
11
11
use futures:: future;
12
12
use std:: future:: Future ;
13
13
use std:: mem;
14
14
use std:: os:: raw:: c_void;
15
- use std:: sync:: { Arc , Condvar , Mutex } ;
15
+ use std:: sync:: { Arc , Condvar , Mutex , OnceLock } ;
16
16
use tokio:: task:: JoinHandle ;
17
17
use tokio:: time:: Duration ;
18
18
19
+ #[ derive( Debug ) ]
19
20
pub enum CassResultValue {
20
21
Empty ,
21
22
QueryResult ( Arc < CassResult > ) ,
@@ -50,14 +51,14 @@ impl BoundCallback {
50
51
51
52
#[ derive( Default ) ]
52
53
struct CassFutureState {
53
- value : Option < CassFutureResult > ,
54
54
err_string : Option < String > ,
55
55
callback : Option < BoundCallback > ,
56
56
join_handle : Option < JoinHandle < ( ) > > ,
57
57
}
58
58
59
59
pub struct CassFuture {
60
60
state : Mutex < CassFutureState > ,
61
+ result : OnceLock < CassFutureResult > ,
61
62
wait_for_value : Condvar ,
62
63
}
63
64
@@ -87,14 +88,18 @@ impl CassFuture {
87
88
) -> Arc < CassFuture > {
88
89
let cass_fut = Arc :: new ( CassFuture {
89
90
state : Mutex :: new ( Default :: default ( ) ) ,
91
+ result : OnceLock :: new ( ) ,
90
92
wait_for_value : Condvar :: new ( ) ,
91
93
} ) ;
92
94
let cass_fut_clone = Arc :: clone ( & cass_fut) ;
93
95
let join_handle = RUNTIME . spawn ( async move {
94
96
let r = fut. await ;
95
97
let maybe_cb = {
96
98
let mut guard = cass_fut_clone. state . lock ( ) . unwrap ( ) ;
97
- guard. value = Some ( r) ;
99
+ cass_fut_clone
100
+ . result
101
+ . set ( r)
102
+ . expect ( "Tried to resolve future result twice!" ) ;
98
103
// Take the callback and call it after releasing the lock
99
104
guard. callback . take ( )
100
105
} ;
@@ -115,16 +120,17 @@ impl CassFuture {
115
120
116
121
pub fn new_ready ( r : CassFutureResult ) -> Arc < Self > {
117
122
Arc :: new ( CassFuture {
118
- state : Mutex :: new ( CassFutureState {
119
- value : Some ( r) ,
120
- ..Default :: default ( )
121
- } ) ,
123
+ state : Mutex :: new ( CassFutureState :: default ( ) ) ,
124
+ result : OnceLock :: from ( r) ,
122
125
wait_for_value : Condvar :: new ( ) ,
123
126
} )
124
127
}
125
128
126
- pub fn with_waited_result < T > ( & self , f : impl FnOnce ( & mut CassFutureResult ) -> T ) -> T {
127
- self . with_waited_state ( |s| f ( s. value . as_mut ( ) . unwrap ( ) ) )
129
+ pub fn with_waited_result < ' s , T > ( & ' s self , f : impl FnOnce ( & ' s CassFutureResult ) -> T ) -> T
130
+ where
131
+ T : ' s ,
132
+ {
133
+ self . with_waited_state ( |_| f ( self . result . get ( ) . unwrap ( ) ) )
128
134
}
129
135
130
136
/// Awaits the future until completion.
@@ -153,7 +159,7 @@ impl CassFuture {
153
159
guard = self
154
160
. wait_for_value
155
161
. wait_while ( guard, |state| {
156
- state . value . is_none ( ) && state. join_handle . is_none ( )
162
+ self . result . get ( ) . is_none ( ) && state. join_handle . is_none ( )
157
163
} )
158
164
// unwrap: Error appears only when mutex is poisoned.
159
165
. unwrap ( ) ;
@@ -171,10 +177,10 @@ impl CassFuture {
171
177
172
178
fn with_waited_result_timed < T > (
173
179
& self ,
174
- f : impl FnOnce ( & mut CassFutureResult ) -> T ,
180
+ f : impl FnOnce ( & CassFutureResult ) -> T ,
175
181
timeout_duration : Duration ,
176
182
) -> Result < T , FutureError > {
177
- self . with_waited_state_timed ( |s | f ( s . value . as_mut ( ) . unwrap ( ) ) , timeout_duration)
183
+ self . with_waited_state_timed ( |_ | f ( self . result . get ( ) . unwrap ( ) ) , timeout_duration)
178
184
}
179
185
180
186
/// Tries to await the future with a given timeout.
@@ -242,7 +248,7 @@ impl CassFuture {
242
248
let ( guard_result, timeout_result) = self
243
249
. wait_for_value
244
250
. wait_timeout_while ( guard, remaining_timeout, |state| {
245
- state . value . is_none ( ) && state. join_handle . is_none ( )
251
+ self . result . get ( ) . is_none ( ) && state. join_handle . is_none ( )
246
252
} )
247
253
// unwrap: Error appears only when mutex is poisoned.
248
254
. unwrap ( ) ;
@@ -275,7 +281,7 @@ impl CassFuture {
275
281
return CassError :: CASS_ERROR_LIB_CALLBACK_ALREADY_SET ;
276
282
}
277
283
let bound_cb = BoundCallback { cb, data } ;
278
- if lock . value . is_some ( ) {
284
+ if self . result . get ( ) . is_some ( ) {
279
285
// The value is already available, we need to call the callback ourselves
280
286
mem:: drop ( lock) ;
281
287
bound_cb. invoke ( self_ptr) ;
@@ -345,8 +351,7 @@ pub unsafe extern "C" fn cass_future_ready(
345
351
return cass_false;
346
352
} ;
347
353
348
- let state_guard = future. state . lock ( ) . unwrap ( ) ;
349
- match state_guard. value {
354
+ match future. result . get ( ) {
350
355
None => cass_false,
351
356
Some ( _) => cass_true,
352
357
}
@@ -361,7 +366,7 @@ pub unsafe extern "C" fn cass_future_error_code(
361
366
return CassError :: CASS_ERROR_LIB_BAD_PARAMS ;
362
367
} ;
363
368
364
- future. with_waited_result ( |r : & mut CassFutureResult | match r {
369
+ future. with_waited_result ( |r : & CassFutureResult | match r {
365
370
Ok ( CassResultValue :: QueryError ( err) ) => err. to_cass_error ( ) ,
366
371
Err ( ( err, _) ) => * err,
367
372
_ => CassError :: CASS_OK ,
@@ -380,7 +385,7 @@ pub unsafe extern "C" fn cass_future_error_message(
380
385
} ;
381
386
382
387
future. with_waited_state ( |state : & mut CassFutureState | {
383
- let value = & state . value ;
388
+ let value = future . result . get ( ) ;
384
389
let msg = state
385
390
. err_string
386
391
. get_or_insert_with ( || match value. as_ref ( ) . unwrap ( ) {
@@ -407,7 +412,7 @@ pub unsafe extern "C" fn cass_future_get_result(
407
412
} ;
408
413
409
414
future
410
- . with_waited_result ( |r : & mut CassFutureResult | -> Option < Arc < CassResult > > {
415
+ . with_waited_result ( |r : & CassFutureResult | -> Option < Arc < CassResult > > {
411
416
match r. as_ref ( ) . ok ( ) ? {
412
417
CassResultValue :: QueryResult ( qr) => Some ( Arc :: clone ( qr) ) ,
413
418
_ => None ,
@@ -426,7 +431,7 @@ pub unsafe extern "C" fn cass_future_get_error_result(
426
431
} ;
427
432
428
433
future
429
- . with_waited_result ( |r : & mut CassFutureResult | -> Option < Arc < CassErrorResult > > {
434
+ . with_waited_result ( |r : & CassFutureResult | -> Option < Arc < CassErrorResult > > {
430
435
match r. as_ref ( ) . ok ( ) ? {
431
436
CassResultValue :: QueryError ( qr) => Some ( Arc :: clone ( qr) ) ,
432
437
_ => None ,
@@ -445,7 +450,7 @@ pub unsafe extern "C" fn cass_future_get_prepared(
445
450
} ;
446
451
447
452
future
448
- . with_waited_result ( |r : & mut CassFutureResult | -> Option < Arc < CassPrepared > > {
453
+ . with_waited_result ( |r : & CassFutureResult | -> Option < Arc < CassPrepared > > {
449
454
match r. as_ref ( ) . ok ( ) ? {
450
455
CassResultValue :: Prepared ( p) => Some ( Arc :: clone ( p) ) ,
451
456
_ => None ,
@@ -464,7 +469,7 @@ pub unsafe extern "C" fn cass_future_tracing_id(
464
469
return CassError :: CASS_ERROR_LIB_BAD_PARAMS ;
465
470
} ;
466
471
467
- future. with_waited_result ( |r : & mut CassFutureResult | match r {
472
+ future. with_waited_result ( |r : & CassFutureResult | match r {
468
473
Ok ( CassResultValue :: QueryResult ( result) ) => match result. tracing_id {
469
474
Some ( id) => {
470
475
unsafe { * tracing_id = CassUuid :: from ( id) } ;
@@ -476,6 +481,24 @@ pub unsafe extern "C" fn cass_future_tracing_id(
476
481
} )
477
482
}
478
483
484
+ #[ unsafe( no_mangle) ]
485
+ pub unsafe extern "C" fn cass_future_coordinator (
486
+ future_raw : CassBorrowedSharedPtr < CassFuture , CMut > ,
487
+ ) -> CassBorrowedSharedPtr < CassNode , CConst > {
488
+ let Some ( future) = ArcFFI :: as_ref ( future_raw) else {
489
+ tracing:: error!( "Provided null future to cass_future_coordinator!" ) ;
490
+ return RefFFI :: null ( ) ;
491
+ } ;
492
+
493
+ future. with_waited_result ( |r| match r {
494
+ Ok ( CassResultValue :: QueryResult ( result) ) => {
495
+ // unwrap: Coordinator is `None` only for tests.
496
+ RefFFI :: as_ptr ( result. coordinator . as_ref ( ) . unwrap ( ) )
497
+ }
498
+ _ => RefFFI :: null ( ) ,
499
+ } )
500
+ }
501
+
479
502
#[ cfg( test) ]
480
503
mod tests {
481
504
use crate :: testing:: { assert_cass_error_eq, assert_cass_future_error_message_eq} ;
0 commit comments