1 #![allow(dead_code, unused_variables)]
2 /// To use `maybe-async`, we must know which block of codes is only used on
3 /// blocking implementation, and which on async. These two implementation should
4 /// share the same API except for async/await keywords, and use `sync_impl` and
5 /// `async_impl` to mark these implementation.
6 type Response = String;
7 type Url = &'static str;
8 type Method = String;
9 
10 /// InnerClient are used to actually send request,
11 /// which differ a lot between sync and async.
12 ///
13 /// Use native async function in trait
14 #[maybe_async::maybe_async(AFIT)]
15 trait InnerClient {
request(method: Method, url: Url, data: String) -> Response16     async fn request(method: Method, url: Url, data: String) -> Response;
17     #[inline]
post(url: Url, data: String) -> Response18     async fn post(url: Url, data: String) -> Response {
19         Self::request(String::from("post"), url, data).await
20     }
21     #[inline]
delete(url: Url, data: String) -> Response22     async fn delete(url: Url, data: String) -> Response {
23         Self::request(String::from("delete"), url, data).await
24     }
25 }
26 
27 /// The higher level API for end user.
28 pub struct ServiceClient;
29 
30 /// Synchronous  implementation, only compiles when `is_sync` feature is off.
31 /// Else the compiler will complain that *request is defined multiple times* and
32 /// blabla.
33 #[maybe_async::sync_impl]
34 impl InnerClient for ServiceClient {
request(method: Method, url: Url, data: String) -> Response35     fn request(method: Method, url: Url, data: String) -> Response {
36         // your implementation for sync, like use
37         // `reqwest::blocking` to send request
38         String::from("pretend we have a response")
39     }
40 }
41 
42 /// Asynchronous implementation, only compiles when `is_sync` feature is off.
43 #[maybe_async::async_impl(AFIT)]
44 impl InnerClient for ServiceClient {
request(method: Method, url: Url, data: String) -> Response45     async fn request(method: Method, url: Url, data: String) -> Response {
46         // your implementation for async, like use `reqwest::client`
47         // or `async_std` to send request
48         String::from("pretend we have a response")
49     }
50 }
51 
52 /// Code of upstream API are almost the same for sync and async,
53 /// except for async/await keyword.
54 impl ServiceClient {
55     #[maybe_async::maybe_async]
create_bucket(name: String) -> Response56     async fn create_bucket(name: String) -> Response {
57         Self::post("http://correct_url4create", String::from("my_bucket")).await
58         // When `is_sync` is toggle on, this block will compiles to:
59         // Self::post("http://correct_url4create", String::from("my_bucket"))
60     }
61     #[maybe_async::maybe_async]
delete_bucket(name: String) -> Response62     async fn delete_bucket(name: String) -> Response {
63         Self::delete("http://correct_url4delete", String::from("my_bucket")).await
64     }
65     // and another thousands of functions that interact with service side
66 }
67 
68 #[maybe_async::sync_impl]
main()69 fn main() {
70     let _ = ServiceClient::create_bucket("bucket".to_owned());
71 }
72 
73 #[maybe_async::async_impl]
74 #[tokio::main]
main()75 async fn main() {
76     let _ = ServiceClient::create_bucket("bucket".to_owned()).await;
77 }
78