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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//!Client runtime
//!
//!Due to limitation of `async fn`, the global client is provided by means of macro
//![declare_global_client](../../macro.declare_global_client.html).
//!The macro defines global client in current scope, alongside companion `Request` wrapper and `GlobalRequest` trait.
//!Refer to macro documentation for details.
//!
//!## Usage
//!
//!```rust,no_run
//!use yukikaze::client::Request;
//!
//!mod generated {
//!    use yukikaze::client;
//!    use core::time;
//!
//!    pub struct TimeoutCfg;
//!
//!    impl client::config::Config for TimeoutCfg {
//!        type Connector = client::config::DefaultConnector;
//!        type Timer = client::config::DefaultTimer;
//!
//!        fn timeout() -> time::Duration {
//!            time::Duration::from_millis(50)
//!        }
//!    }
//!
//!    yukikaze::declare_global_client!(TimeoutCfg);
//!}
//!
//!use generated::{GlobalRequest};
//!
//!async fn google() {
//!    let res = Request::get("https://google.com").expect("To create get request")
//!                                                .empty()
//!                                                .global()
//!                                                .send();
//!    let result = yukikaze::matsu!(res).expect("To get without timeout")
//!                                       .expect("Successful response");
//!    assert!(result.is_success());
//!}
//!```

#[macro_export]
///Declares global client for use.
///
///If no argument is specified, uses [`DefaultCfg`](client/config/struct.DefaultCfg.html)
///Otherwise you must provide accessible type of unit struct that implements [`Config`](client/config/trait.Config.html)
///
///Creates following:
///
///- `GLOBAL_CLIENT` which is initialized using `lazy_static`
///- `Request` which uses `GLOBAL_CLIENT` and wraps `yukikaze::client::Request`
///- Creates and defines trait `GlobalRequest` for generated `Request`.
///
///See example of [generated](rt/client/generated/struct.Request.html)
///
///See [usage](rt/client/index.html)
macro_rules! declare_global_client {
    () => {
        use $crate::client::config::DefaultCfg;
        $crate::declare_global_client!(DefaultCfg);
    };
    ($config:ty) => {
        $crate::lazy_static::lazy_static! {
            ///Global client instance
            pub static ref GLOBAL_CLIENT: $crate::client::Client::<$config> = $crate::client::Client::<$config>::new();
        }

        ///Global request
        ///
        ///Implements `Deref` and `DerefMut` to access regular yukikaze's request.
        pub struct Request(pub $crate::client::Request);

        impl core::ops::Deref for Request {
            type Target = $crate::client::Request;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl core::ops::DerefMut for Request {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }

        ///Helper trait to convert request to global request.
        pub trait GlobalRequest {
            ///Type of global request
            type Result;

            ///Wraps request into global request
            fn global(self) -> Self::Result;
        }

        impl GlobalRequest for $crate::client::Request {
            type Result = Request;

            fn global(self) -> Self::Result {
                Request(self)
            }
        }

        use $crate::client::RequestResult;

        impl Request {
            #[inline(always)]
            ///Sends request, and returns future that resolves to response
            pub fn request(self) -> impl core::future::Future<Output=RequestResult> {
                GLOBAL_CLIENT.request(self.0)
            }

            #[inline(always)]
            ///Sends request and returns response. Timed version.
            ///
            ///On timeout error it returns `async_timer::Expired` as `Error`
            ///`Expired` implements `Future` that can be used to re-spawn ongoing request again.
            ///
            ///If request resolves in time returns `Result<response::Response, hyper::Error>` as `Ok`
            ///variant.
            pub fn send(self) -> impl core::future::Future<Output=Result<RequestResult, $crate::async_timer::Expired<impl core::future::Future<Output=RequestResult>, impl $crate::async_timer::Oneshot>>> {
                GLOBAL_CLIENT.send(self.0)
            }

            #[inline(always)]
            ///Sends request and returns response, while handling redirects. Timed version.
            ///
            ///On timeout error it returns `async_timer::Expired` as `Error`
            ///`Expired` implements `Future` that can be used to re-spawn ongoing request again.
            ///
            ///If request resolves in time returns `Result<response::Response, hyper::Error>` as `Ok`
            ///variant.
            pub fn send_redirect(self) -> impl core::future::Future<Output=Result<RequestResult, $crate::async_timer::Expired<impl core::future::Future<Output=RequestResult> + 'static, impl $crate::async_timer::Oneshot>>> {
                GLOBAL_CLIENT.send_redirect(self.0)
            }

            #[inline(always)]
            ///Sends request and returns response, while handling redirects.
            pub fn redirect_request(self) -> impl core::future::Future<Output=RequestResult> {
                GLOBAL_CLIENT.redirect_request(self.0)
            }
        }
    };
}

#[cfg(feature = "docs")]
///Example of generated global client
pub mod generated {
    declare_global_client!();
}