macro_rules! imports {
() => {
#[cfg(feature = "rustls")]
type HttpsConnector = hyper_rustls::HttpsConnector<hyper::client::HttpConnector>;
#[cfg(feature = "rust-native-tls")]
use hyper_tls;
#[cfg(feature = "rust-native-tls")]
type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
use async_trait::async_trait;
use hyper::client::Client;
use paste::paste;
use std::error::Error;
use std::sync::Arc;
use std::sync::RwLock;
use $crate::client::ApiResponse;
use $crate::client::Builder;
use $crate::client::Executor;
};
}
macro_rules! new_builder {
($(
$(#[$doc:meta])*
$i: ident
),* $(,)?) => (
$(paste! {
$(#[$doc])*
pub struct [<$i Builder>] {
pub(crate) builder: Result<RwLock<Builder>, Box<dyn Error>>,
pub(crate) client: Arc<Client<HttpsConnector>>,
}
unsafe impl Send for [<$i Builder>] {}
})*
);
}
macro_rules! exec {
($(
$(#[$doc:meta])*
$i: ident -> $t: ty
),* $(,)?
) => (
paste! {$(
$(#[$doc])*
#[async_trait]
impl Executor for [<$i Builder>] {
type T = $t;
async fn execute(self) -> Result<ApiResponse<Self::T>, Box<dyn Error>> {
let client = self.client;
let builder = self.builder?.into_inner().unwrap();
let req = builder.build();
let res = client.request(req).await?;
let (parts, body) = res.into_parts();
let body = hyper::body::to_bytes(body).await?;
let body = if parts.status.is_success() {
Ok(serde_json::from_slice::<Self::T>(&body)?)
} else {
Err(serde_json::from_slice::<$crate::client::ApiError>(&body)?)
};
Ok(ApiResponse {
status_code: parts.status,
headers: parts.headers.into(),
response: body,
})
}
}
)*}
);
}
macro_rules! from {
($(@$f: ident
$(
$(#[$doc:meta])*
-> $t: ident
),+ $(,)?
)+) => {
$($(paste! {
$(#[$doc])*
impl From<[<$f Builder>]> for [<$t Builder>] {
fn from(f: [<$f Builder>]) -> Self {
Self {
builder: f.builder,
client: f.client,
}
}
}
})+)+
};
}
macro_rules! impl_builder {
($(@$i: ident
$(
$(#[$doc:meta])*
// Case 1
// This case is for methods that don't need a route variable such as getting all users.
// The syntax looks like: `-> <method name> [<route path>] -> <builder name>`.
// Builder name should be a struct generated by the new_builder! macro.
$(-> $fn1:ident [$($p1:literal)?] -> $t1:ident)?
$(=> $fn2:ident [$($p2:literal)?] -> $t2:ident = $e2:ident)?
$(?> $fn3:ident [$q3:literal] -> $n3:ident: $t3:ty)?
),*
)+)=> (
$(paste! {
impl [<$i Builder>] {
$(
$(#[$doc])*
// Case 1
$(
pub fn $fn1(mut self) -> [<$t1 Builder>] {
join_path!(self, &[$($p1)?]);
self.into()
}
)?
$(
pub fn $fn2<T: ToString>(mut self, $e2: T) -> [<$t2 Builder>] {
join_path!(self, &[$($p2,)? &$e2.to_string()]);
self.into()
}
)?
$(
pub fn $fn3(mut self, $n3: $t3) -> [<$i Builder>] {
join_query!(self, $q3, $n3);
self.into()
}
)?
)*
}
})+
);
}
macro_rules! impl_client {
($(
$(#[$doc:meta])*
$(-> $fn:ident [$p:literal] -> $t:ident)?
),*)=> (
impl $crate::client::Coder {
$(paste! {
$(#[$doc])*
$(
pub fn $fn(&self) -> [<$t Builder>] {
let mut b = [<$t Builder>] {
builder: self.new_request().map(|r| RwLock::new(Builder{
url: self.url.clone(),
req: r,
})),
client: Arc::clone(&self.client),
};
join_path!(b, &[$p]);
b
}
)?
})*
}
);
}
macro_rules! join_path {
($e: ident, $p: expr) => {
if $e.builder.is_ok() {
let inner = $e.builder.unwrap();
inner
.write()
.unwrap()
.url
.path_segments_mut()
.unwrap()
.extend($p);
$e.builder = Ok(inner);
}
};
}
macro_rules! join_query {
($e: ident, $k: expr, $v: expr) => {
if $e.builder.is_ok() {
let inner = $e.builder.unwrap();
inner
.write()
.unwrap()
.url
.query_pairs_mut()
.append_pair($k, &$v.to_string());
$e.builder = Ok(inner);
}
};
}
macro_rules! id_string {
($($name:ident),*) => {
$(
impl std::ops::Deref for $name {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::convert::From<String> for $name {
fn from(i: String) -> Self {
Self(i)
}
}
impl std::convert::From<&str> for $name {
fn from(i: &str) -> Self {
Self(i.to_string())
}
}
)*
}
}