1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use futures_core::task::{LocalWaker, UnsafeWake, Wake, Waker};
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use std::sync::Arc;

/// An implementation of [`Wake`](futures_core::task::Wake) that panics when
/// woken.
///
/// # Examples
///
/// ```should_panic
/// #![feature(futures_api)]
/// use futures_test::task::{noop_context, panic_local_waker_ref};
///
/// let mut cx = noop_context();
/// let cx = &mut cx.with_waker(panic_local_waker_ref());
///
/// cx.waker().wake(); // Will panic
/// ```
#[derive(Debug)]
pub struct PanicWake {
    _reserved: (),
}

impl PanicWake {
    /// Create a new instance
    pub fn new() -> Self {
        Self { _reserved: () }
    }
}

impl Default for PanicWake {
    fn default() -> Self {
        Self::new()
    }
}

impl Wake for PanicWake {
    fn wake(_arc_self: &Arc<Self>) {
        panic!("should not be woken")
    }
}

unsafe impl UnsafeWake for PanicWake {
    unsafe fn clone_raw(&self) -> Waker {
        panic_waker()
    }

    unsafe fn drop_raw(&self) {}

    unsafe fn wake(&self) {
        panic!("should not be woken")
    }
}

fn panic_unsafe_wake() -> NonNull<dyn UnsafeWake> {
    static mut INSTANCE: PanicWake = PanicWake { _reserved: () };
    unsafe { NonNull::new_unchecked(&mut INSTANCE as *mut dyn UnsafeWake) }
}

fn panic_waker() -> Waker {
    unsafe { Waker::new(panic_unsafe_wake()) }
}

/// Create a new [`LocalWaker`](futures_core::task::LocalWaker) referencing
/// a singleton instance of [`PanicWake`].
pub fn panic_local_waker() -> LocalWaker {
    unsafe { LocalWaker::new(panic_unsafe_wake()) }
}

/// Get a thread local reference to a
/// [`LocalWaker`](futures_core::task::LocalWaker) referencing a singleton
/// instance of [`PanicWake`].
///
/// # Examples
///
/// ```should_panic
/// #![feature(async_await, futures_api)]
/// use futures::task;
/// use futures_test::task::{panic_local_waker_ref, panic_spawner_mut};
///
/// let mut cx = task::Context::new(
///     panic_local_waker_ref(),
///     panic_spawner_mut(),
/// );
///
/// cx.waker().wake(); // Will panic
/// ```
pub fn panic_local_waker_ref() -> &'static LocalWaker {
    thread_local! {
        static LOCAL_WAKER_INSTANCE: UnsafeCell<LocalWaker> =
            UnsafeCell::new(panic_local_waker());
    }
    LOCAL_WAKER_INSTANCE.with(|l| unsafe { &*l.get() })
}