1use std::{
2 fmt::Debug,
3 future::Future,
4 pin::Pin,
5 sync::{Arc, Mutex, PoisonError},
6 task::{Context, Poll, Waker},
7};
8
9use crate::{Promise, PromiseRejection, TaskFailure};
10
11#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
14#[error("all resolver handles were dropped without settling the promise")]
15pub struct ResolversDropped;
16
17impl<T, E> Promise<T, E>
18where
19 T: Send + 'static,
20 E: PromiseRejection,
21{
22 #[must_use = "Dropping the handles rejects the Promise!"]
32 pub fn with_resolvers() -> (Self, Resolve<T, E>, Reject<T, E>) {
33 let slot = Arc::new(Mutex::new(Slot {
34 settled: false,
35 outcome: None,
36 waker: None,
37 }));
38
39 let guard = Arc::new(HandleGuard { slot: slot.clone() });
40
41 (
42 Self::lazy(SlotFuture { slot }),
43 Resolve {
44 guard: guard.clone(),
45 },
46 Reject { guard },
47 )
48 }
49}
50
51pub struct Resolve<T, E>
56where
57 E: PromiseRejection,
58{
59 guard: Arc<HandleGuard<T, E>>,
60}
61
62impl<T, E> Clone for Resolve<T, E>
63where
64 E: PromiseRejection,
65{
66 fn clone(&self) -> Self {
67 Self {
68 guard: self.guard.clone(),
69 }
70 }
71}
72
73impl<T, E> Debug for Resolve<T, E>
74where
75 E: PromiseRejection,
76{
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("Resolve").finish_non_exhaustive()
79 }
80}
81
82impl<T, E> Resolve<T, E>
83where
84 E: PromiseRejection,
85{
86 pub fn resolve(self, value: T) {
90 settle(&self.guard.slot, Ok(value));
91 }
92}
93
94pub struct Reject<T, E>
99where
100 E: PromiseRejection,
101{
102 guard: Arc<HandleGuard<T, E>>,
103}
104
105impl<T, E> Clone for Reject<T, E>
106where
107 E: PromiseRejection,
108{
109 fn clone(&self) -> Self {
110 Self {
111 guard: self.guard.clone(),
112 }
113 }
114}
115
116impl<T, E> Debug for Reject<T, E>
117where
118 E: PromiseRejection,
119{
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.debug_struct("Reject").finish_non_exhaustive()
122 }
123}
124
125impl<T, E> Reject<T, E>
126where
127 E: PromiseRejection,
128{
129 pub fn reject(self, err: E) {
133 settle(&self.guard.slot, Err(err));
134 }
135}
136
137struct Slot<T, E> {
138 settled: bool,
139 outcome: Option<Result<T, E>>,
140 waker: Option<Waker>,
141}
142
143type SharedSlot<T, E> = Arc<Mutex<Slot<T, E>>>;
144
145fn settle<T, E>(slot: &SharedSlot<T, E>, outcome: Result<T, E>) {
148 let mut guard = slot.lock().unwrap_or_else(PoisonError::into_inner);
149
150 if !guard.settled {
151 guard.settled = true;
152 guard.outcome = Some(outcome);
153
154 if let Some(waker) = guard.waker.take() {
155 drop(guard);
156
157 waker.wake();
158 }
159 }
160}
161
162struct HandleGuard<T, E>
165where
166 E: PromiseRejection,
167{
168 slot: SharedSlot<T, E>,
169}
170
171impl<T, E> Drop for HandleGuard<T, E>
172where
173 E: PromiseRejection,
174{
175 fn drop(&mut self) {
176 settle(
177 &self.slot,
178 Err(E::task_failed(TaskFailure::Error(Arc::new(
179 ResolversDropped,
180 )))),
181 );
182 }
183}
184
185struct SlotFuture<T, E> {
186 slot: SharedSlot<T, E>,
187}
188
189impl<T, E> Future for SlotFuture<T, E>
190where
191 E: PromiseRejection,
192{
193 type Output = Result<T, E>;
194
195 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
196 let Ok(mut guard) = self.slot.lock() else {
197 return Poll::Ready(Err(E::task_failed(TaskFailure::Panic(
198 "a panic corrupted the promise's settlement state".into(),
199 ))));
200 };
201
202 if !guard.settled {
203 if let Some(waker) = &mut guard.waker {
204 waker.clone_from(cx.waker());
205 } else {
206 guard.waker = Some(cx.waker().clone());
207 }
208
209 return Poll::Pending;
210 }
211
212 Poll::Ready(
213 guard
214 .outcome
215 .take()
216 .unwrap_or_else(|| Err(E::already_consumed())),
217 )
218 }
219}
220
221#[cfg(test)]
222#[allow(clippy::expect_used)]
223mod tests {
224 use std::{
225 future::Future,
226 pin::Pin,
227 sync::{
228 atomic::{AtomicUsize, Ordering},
229 Arc, Mutex,
230 },
231 task::{Context, Poll, Wake, Waker},
232 thread,
233 };
234
235 use crate::{Promise, PromiseRejection, TaskFailure};
236
237 use super::{settle, ResolversDropped, SharedSlot, Slot, SlotFuture};
238
239 const POISONED_MSG: &str = "task panicked: a panic corrupted the promise's settlement state";
240
241 #[derive(Debug, PartialEq)]
242 enum E {
243 AlreadyConsumed,
244 Fail,
245 TaskFailed(String),
246 }
247
248 impl PromiseRejection for E {
249 fn already_consumed() -> Self {
250 Self::AlreadyConsumed
251 }
252
253 fn task_failed(failure: TaskFailure) -> Self {
254 Self::TaskFailed(failure.to_string())
255 }
256 }
257
258 fn resolvers_dropped() -> E {
260 E::TaskFailed(ResolversDropped.to_string())
261 }
262
263 fn cx() -> Context<'static> {
264 Context::from_waker(Waker::noop())
265 }
266
267 fn poll_future<F: Future + Unpin>(future: &mut F) -> Poll<F::Output> {
268 Pin::new(future).poll(&mut cx())
269 }
270
271 fn empty_slot() -> SharedSlot<i32, E> {
272 Arc::new(Mutex::new(Slot {
273 settled: false,
274 outcome: None,
275 waker: None,
276 }))
277 }
278
279 fn poison(slot: &SharedSlot<i32, E>) {
281 let poisoner = slot.clone();
282
283 thread::spawn(move || {
284 let _guard = poisoner.lock().expect("first lock of a fresh slot");
285
286 panic!("poison the slot");
287 })
288 .join()
289 .expect_err("poisoning thread must panic");
290 }
291
292 struct CountingWaker {
293 count: AtomicUsize,
294 }
295
296 impl Wake for CountingWaker {
297 fn wake(self: Arc<Self>) {
298 self.count.fetch_add(1, Ordering::Relaxed);
299 }
300
301 fn wake_by_ref(self: &Arc<Self>) {
302 self.count.fetch_add(1, Ordering::Relaxed);
303 }
304 }
305
306 fn counting_waker() -> (Arc<CountingWaker>, Waker) {
307 let counter = Arc::new(CountingWaker {
308 count: AtomicUsize::new(0),
309 });
310
311 let waker = Waker::from(counter.clone());
312
313 (counter, waker)
314 }
315
316 #[test]
317 fn resolve_settles_promise() {
318 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
319
320 resolve.resolve(42);
321 promise.poll_settled(&mut cx());
322
323 assert_eq!(promise.consume(), Some(Ok(42)));
324 }
325
326 #[test]
327 fn reject_settles_promise() {
328 let (mut promise, _resolve, reject) = Promise::<i32, E>::with_resolvers();
329
330 reject.reject(E::Fail);
331 promise.poll_settled(&mut cx());
332
333 assert_eq!(promise.consume(), Some(Err(E::Fail)));
334 }
335
336 #[test]
337 fn pending_until_settled() {
338 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
339
340 assert!(promise.poll_pending(&mut cx()));
341
342 resolve.resolve(7);
343
344 assert!(promise.poll_settled(&mut cx()));
345 assert_eq!(promise.consume(), Some(Ok(7)));
346 }
347
348 #[test]
349 fn first_settlement_wins() {
350 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
351
352 resolve.resolve(1);
353 reject.reject(E::Fail);
354 promise.poll_settled(&mut cx());
355
356 assert_eq!(promise.consume(), Some(Ok(1)));
357 }
358
359 #[test]
360 fn rejects_when_handles_dropped() {
361 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
362
363 drop(resolve);
364 drop(reject);
365 promise.poll_settled(&mut cx());
366
367 assert_eq!(promise.consume(), Some(Err(resolvers_dropped())));
368 }
369
370 #[test]
371 fn settles_even_if_other_handle_dropped_later() {
372 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
373
374 resolve.resolve(9);
375 drop(reject);
376 promise.poll_settled(&mut cx());
377
378 assert_eq!(promise.consume(), Some(Ok(9)));
379 }
380
381 #[test]
382 fn clone_can_settle_after_originals_are_dropped() {
383 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
384
385 let clone = resolve.clone();
386
387 drop(resolve);
388 drop(reject);
389
390 clone.resolve(3);
391 promise.poll_settled(&mut cx());
392
393 assert_eq!(promise.consume(), Some(Ok(3)));
394 }
395
396 #[test]
397 fn first_settlement_wins_across_clones() {
398 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
399
400 let clone = resolve.clone();
401
402 clone.resolve(1);
403 resolve.resolve(2);
404 promise.poll_settled(&mut cx());
405
406 assert_eq!(promise.consume(), Some(Ok(1)));
407 }
408
409 #[test]
410 fn live_clone_keeps_the_promise_pending() {
411 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
412
413 let clone = reject.clone();
414
415 drop(resolve);
416 drop(reject);
417
418 assert!(promise.poll_pending(&mut cx()));
419
420 clone.reject(E::Fail);
421 promise.poll_settled(&mut cx());
422
423 assert_eq!(promise.consume(), Some(Err(E::Fail)));
424 }
425
426 #[test]
427 fn rejects_only_when_every_clone_is_dropped() {
428 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
429
430 let resolve_clone = resolve.clone();
431 let reject_clone = reject.clone();
432
433 drop(resolve);
434 drop(reject);
435
436 assert!(promise.poll_pending(&mut cx()));
437
438 drop(resolve_clone);
439 drop(reject_clone);
440 promise.poll_settled(&mut cx());
441
442 assert_eq!(promise.consume(), Some(Err(resolvers_dropped())));
443 }
444
445 #[test]
446 fn debug_output_names_the_handles() {
447 let (_promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
448
449 assert_eq!(format!("{resolve:?}"), "Resolve { .. }");
450 assert_eq!(format!("{reject:?}"), "Reject { .. }");
451 }
452
453 #[test]
454 fn resolve_wakes_pending_consumer() {
455 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
456
457 let (counter, waker) = counting_waker();
458
459 assert!(promise.poll_pending(&mut Context::from_waker(&waker)));
460 assert_eq!(counter.count.load(Ordering::SeqCst), 0);
461
462 resolve.resolve(8);
463
464 assert_eq!(counter.count.load(Ordering::SeqCst), 1);
465
466 assert!(promise.poll_settled(&mut cx()));
467 assert_eq!(promise.consume(), Some(Ok(8)));
468 }
469
470 #[test]
471 fn reject_wakes_pending_consumer() {
472 let (mut promise, _resolve, reject) = Promise::<i32, E>::with_resolvers();
473
474 let (counter, waker) = counting_waker();
475
476 assert!(promise.poll_pending(&mut Context::from_waker(&waker)));
477 assert_eq!(counter.count.load(Ordering::SeqCst), 0);
478
479 reject.reject(E::Fail);
480
481 assert_eq!(counter.count.load(Ordering::SeqCst), 1);
482
483 assert!(promise.poll_settled(&mut cx()));
484 assert_eq!(promise.consume(), Some(Err(E::Fail)));
485 }
486
487 #[test]
488 fn dropping_last_handle_wakes_pending_consumer() {
489 let (mut promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
490
491 let (counter, waker) = counting_waker();
492
493 assert!(promise.poll_pending(&mut Context::from_waker(&waker)));
494
495 drop(resolve);
496
497 assert_eq!(counter.count.load(Ordering::SeqCst), 0);
498
499 drop(reject);
500
501 assert_eq!(counter.count.load(Ordering::SeqCst), 1);
502
503 assert!(promise.poll_settled(&mut cx()));
504 assert_eq!(promise.consume(), Some(Err(resolvers_dropped())));
505 }
506
507 #[test]
511 fn repoll_replaces_the_stored_waker() {
512 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
513
514 let (counter_a, waker_a) = counting_waker();
515 let (counter_b, waker_b) = counting_waker();
516
517 assert!(promise.poll_pending(&mut Context::from_waker(&waker_a)));
518 assert!(promise.poll_pending(&mut Context::from_waker(&waker_b)));
519
520 resolve.resolve(4);
521
522 assert_eq!(counter_a.count.load(Ordering::SeqCst), 0);
523 assert_eq!(counter_b.count.load(Ordering::SeqCst), 1);
524
525 assert!(promise.poll_settled(&mut cx()));
526 assert_eq!(promise.consume(), Some(Ok(4)));
527 }
528
529 #[test]
530 fn settlement_from_another_thread_wakes_and_delivers() {
531 let (mut promise, resolve, _reject) = Promise::<i32, E>::with_resolvers();
532
533 let (counter, waker) = counting_waker();
534
535 assert!(promise.poll_pending(&mut Context::from_waker(&waker)));
536
537 thread::spawn(move || resolve.resolve(21))
538 .join()
539 .expect("settler thread");
540
541 assert!(counter.count.load(Ordering::SeqCst) >= 1);
542
543 assert!(promise.poll_settled(&mut cx()));
544 assert_eq!(promise.consume(), Some(Ok(21)));
545 }
546
547 #[test]
548 fn settling_after_promise_dropped_is_ignored() {
549 let (promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
550
551 drop(promise);
552
553 resolve.resolve(1);
554 reject.reject(E::Fail);
555 }
556
557 #[test]
558 fn dropping_handles_after_promise_dropped_is_ignored() {
559 let (promise, resolve, reject) = Promise::<i32, E>::with_resolvers();
560
561 drop(promise);
562 drop(resolve);
563 drop(reject);
564 }
565
566 #[test]
567 fn settle_before_first_poll_delivers_immediately() {
568 let slot = empty_slot();
569
570 settle(&slot, Ok(11));
571
572 let mut future = SlotFuture { slot };
573
574 assert_eq!(poll_future(&mut future), Poll::Ready(Ok(11)));
575 }
576
577 #[test]
581 fn repoll_after_delivery_reports_already_consumed() {
582 let slot = empty_slot();
583
584 let mut future = SlotFuture { slot: slot.clone() };
585
586 assert_eq!(poll_future(&mut future), Poll::Pending);
587
588 settle(&slot, Ok(5));
589
590 assert_eq!(poll_future(&mut future), Poll::Ready(Ok(5)));
591 assert_eq!(
592 poll_future(&mut future),
593 Poll::Ready(Err(E::AlreadyConsumed))
594 );
595 }
596
597 #[test]
600 fn settlement_after_delivery_is_ignored() {
601 let slot = empty_slot();
602
603 let mut future = SlotFuture { slot: slot.clone() };
604
605 settle(&slot, Ok(1));
606
607 assert_eq!(poll_future(&mut future), Poll::Ready(Ok(1)));
608
609 settle(&slot, Ok(2));
610
611 assert_eq!(
612 poll_future(&mut future),
613 Poll::Ready(Err(E::AlreadyConsumed))
614 );
615 }
616
617 #[test]
618 fn poisoned_slot_rejects_with_panic_failure() {
619 let slot = empty_slot();
620
621 poison(&slot);
622
623 let mut future = SlotFuture { slot };
624
625 assert_eq!(
626 poll_future(&mut future),
627 Poll::Ready(Err(E::TaskFailed(POISONED_MSG.into())))
628 );
629 }
630
631 #[test]
635 fn poisoned_slot_rejects_even_after_settlement() {
636 let slot = empty_slot();
637
638 settle(&slot, Ok(9));
639 poison(&slot);
640
641 let mut future = SlotFuture { slot };
642
643 assert_eq!(
644 poll_future(&mut future),
645 Poll::Ready(Err(E::TaskFailed(POISONED_MSG.into())))
646 );
647 }
648
649 #[test]
652 fn settling_a_poisoned_slot_does_not_panic() {
653 let slot = empty_slot();
654
655 poison(&slot);
656
657 settle(&slot, Ok(3));
658 }
659
660 #[test]
661 fn resolvers_dropped_error_message() {
662 assert_eq!(
663 ResolversDropped.to_string(),
664 "all resolver handles were dropped without settling the promise"
665 );
666 }
667}