futures_async_runtime/
lib.rs

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
#![no_std]
#![cfg_attr(feature = "nightly", feature(generator_trait))]
#![cfg_attr(feature = "nightly", feature(on_unimplemented))]
#![cfg_attr(feature = "nightly", feature(arbitrary_self_types))]
#![cfg_attr(feature = "nightly", feature(optin_builtin_traits))]
#![cfg_attr(feature = "nightly", feature(pin))]

macro_rules! if_nightly_and_std {
    ($($i:item)*) => ($(
        #[cfg(all(feature = "nightly", feature = "std"))]
        $i
    )*)
}

#[cfg(all(feature = "nightly", feature = "std"))]
#[macro_use]
extern crate std;

if_nightly_and_std! {
    extern crate futures_core;
    extern crate futures_stable;

    mod future;
    mod stream;

    use std::cell::Cell;
    use std::mem;
    use std::ptr;
    use futures_core::task;

    pub use self::future::*;
    pub use self::stream::*;

    pub use futures_core::{Async, Future, Stream};
    pub use futures_stable::{StableFuture, StableStream};

    pub use std::ops::Generator;

#[rustc_on_unimplemented = "async functions must return a `Result` or \
                                a typedef of `Result`"]
    pub trait IsResult {
        type Ok;
        type Err;

        fn into_result(self) -> Result<Self::Ok, Self::Err>;
    }
    impl<T, E> IsResult for Result<T, E> {
        type Ok = T;
        type Err = E;

        fn into_result(self) -> Result<Self::Ok, Self::Err> { self }
    }

    pub fn diverge<T>() -> T { loop {} }

    type StaticContext = *mut task::Context<'static>;

    thread_local!(static CTX: Cell<StaticContext> = Cell::new(ptr::null_mut()));

    struct Reset<'a>(StaticContext, &'a Cell<StaticContext>);

    impl<'a> Reset<'a> {
        fn new(ctx: &mut task::Context, cell: &'a Cell<StaticContext>) -> Reset<'a> {
            let stored_ctx = unsafe { mem::transmute::<&mut task::Context, StaticContext>(ctx) };
            let ctx = cell.replace(stored_ctx);
            Reset(ctx, cell)
        }

        fn new_null(cell: &'a Cell<StaticContext>) -> Reset<'a> {
            let ctx = cell.replace(ptr::null_mut());
            Reset(ctx, cell)
        }
    }

    impl<'a> Drop for Reset<'a> {
        fn drop(&mut self) {
            self.1.set(self.0);
        }
    }

    pub fn in_ctx<F: FnOnce(&mut task::Context) -> T, T>(f: F) -> T {
        CTX.with(|cell| {
            let r = Reset::new_null(cell);
            if r.0 == ptr::null_mut() {
                panic!("Cannot use `await!`, `await_item!`, or `#[async] for` outside of an `async` function.")
            }
            f(unsafe { &mut *r.0 })
        })
    }
}