1pub mod prelude {
2    pub use std::sync::{Arc, RwLock};
3    pub use tokio::runtime::Runtime;
4    pub use tokio::sync::oneshot::{channel, Sender};
5    pub use tokio::time::{interval, sleep, Duration};
6    const RUNTIME_INIT: Option<Runtime> = None;
7    lazy_static! {
8        pub static ref RUNTIMES: Arc<RwLock<[Option<Runtime>; 256]>> =
9            Arc::new(RwLock::new([RUNTIME_INIT; 256]));
10    }
11    #[derive(Debug)]
12    pub struct Context {
13        pub profile: u8,
14        pub timeout: Duration,
15    }
16
17    pub fn init_runtime(profile: u8) {
18        {
19            let r = RUNTIMES.read().unwrap();
20            if r[profile as usize].is_some() {
21                return;
22            }
23        }
24        let mut w = RUNTIMES.write().unwrap();
25        if w[profile as usize].is_none() {
26            w[profile as usize] = Some(Runtime::new().unwrap());
27        }
28    }
29}
30#[macro_export]
66macro_rules! go {
67    (|$x:ident : Sender<$t:ty>|$y:expr) => {
68        async {
69            let (sender, receiver) = channel::<$t>();
70            init_runtime(0);
71            let rts = RUNTIMES.read().unwrap();
72            let runtime = rts[0].as_ref().unwrap();
73            runtime.spawn((|$x: Sender<$t>| $y)(sender));
74            match receiver.await {
75                Ok(v) => Ok(v),
76                Err(_) => Err("unknown error"),
77            }
78        }
79    };
80    (|$x:ident : Sender<$t:ty>|$y:expr,$c:expr) => {
81        async {
82            let (sender, mut receiver) = channel::<$t>();
83            init_runtime($c.profile);
84            let rts = RUNTIMES.read().unwrap();
85            let runtime = rts[$c.profile as usize].as_ref().unwrap();
86            runtime.spawn((|$x: Sender<$t>| $y)(sender));
87            match $c.timeout {
88                Duration::ZERO => match receiver.await {
89                    Ok(v) => Ok(v),
90                    Err(_) => Err("unknown error"),
91                },
92                _ => {
93                    let mut interval = interval($c.timeout);
94                    tokio::select! {
95                        _=interval.tick()=>Err("timeout"),
96                        msg=&mut receiver =>match msg{
97                            Ok(v)=>Ok(v),
98                            Err(_)=>Err("unknown error")
99                        }
100
101                    }
102                }
103            }
104        }
105    };
106}
107
108#[macro_use]
109extern crate lazy_static;
110
111#[cfg(test)]
112mod tests {
113    use super::prelude::*;
114    use super::*;
115    use std::thread;
116
117    #[tokio::test]
118    async fn it_works() {
119        let r1 = go!(|sender: Sender<i32>| async move {
120            println!("Thread id: {:?}", thread::current().id());
121            if let Err(_) = sender.send(2) {
122                println!("the receiver dropped");
123            }
124        })
125        .await
126        .unwrap();
127        assert_eq!(r1, 2);
128        let r2 = go!(
129            |sender: Sender<String>| async move {
130                println!("Thread id: {:?}", thread::current().id());
131                if let Err(_) = sender.send("whocares".to_string()) {
132                    println!("the receiver dropped");
133                }
134            },
135            Context {
136                profile: 1,
137                timeout: Duration::from_secs(1)
138            }
139        )
140        .await
141        .unwrap();
142        assert_eq!(r2, "whocares");
143        let r3 = go!(
144            |sender: Sender<String>| async move {
145                println!("Thread id: {:?}", thread::current().id());
146                if let Err(_) = sender.send("whocares".to_string()) {
147                    println!("the receiver dropped");
148                }
149            },
150            Context {
151                profile: 1,
152                timeout: Duration::ZERO
153            }
154        )
155        .await
156        .unwrap();
157        assert_eq!(r3, "whocares");
158        let r4 = go!(|sender: Sender<()>| async move {
159            println!("Thread id: {:?}", thread::current().id());
160            if let Err(_) = sender.send(()) {
161                println!("the receiver dropped");
162            }
163        })
164        .await
165        .unwrap();
166        assert_eq!(r4, ());
167    }
168}