110 lines
3.6 KiB
Rust
110 lines
3.6 KiB
Rust
#[macro_export]
|
|
macro_rules! get {
|
|
// Case 1: no query
|
|
(
|
|
$name:ident,
|
|
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
|
) => {
|
|
get!($name(), ( $( $arg : $arg_ty ),* ) => $path -> $out);
|
|
};
|
|
|
|
// Case 2: empty query ()
|
|
(
|
|
$name:ident (),
|
|
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
|
) => {
|
|
#[bon::builder]
|
|
pub fn $name(
|
|
#[builder(finish_fn)] client: &restson::RestClient,
|
|
$( #[builder(finish_fn)] $arg: $arg_ty ),*
|
|
) -> impl std::future::Future<Output = Result<$out, restson::Error>> + '_ {
|
|
#[derive(serde::Deserialize)]
|
|
struct RP($out);
|
|
|
|
impl restson::RestPath<( $( $arg_ty ),* )> for RP {
|
|
fn get_path(args: ( $( $arg_ty ),* )) -> Result<String, restson::Error> {
|
|
let ( $( $arg ),* ) = args;
|
|
Ok(format!($path, $( $arg = $arg ),* ))
|
|
}
|
|
}
|
|
|
|
async move {
|
|
let result = client.get_with::<_, RP>(( $( $arg ),* ), &[]).await?;
|
|
Ok(result.into_inner().0)
|
|
}
|
|
}
|
|
};
|
|
|
|
// Case 3: query with flags / mixed types
|
|
(
|
|
$name:ident ( $( $query:tt ),* $(,)? ),
|
|
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
|
) => {
|
|
#[bon::builder]
|
|
pub fn $name(
|
|
#[builder(finish_fn)] client: &restson::RestClient,
|
|
$( #[builder(finish_fn)] $arg: $arg_ty, )*
|
|
$(
|
|
get!(@query_field $query)
|
|
)*
|
|
) -> impl std::future::Future<Output = Result<$out, restson::Error>> + '_ {
|
|
#[derive(serde::Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct Query<'a> {
|
|
$(
|
|
get!(@query_field_struct $query)
|
|
)*
|
|
}
|
|
|
|
impl Query<'_> {
|
|
fn as_pairs(&self) -> Vec<(&str, String)> {
|
|
let mut out = Vec::new();
|
|
$(
|
|
get!(@push_pair out, self, $query)
|
|
)*
|
|
out
|
|
}
|
|
}
|
|
|
|
let query = Query {
|
|
$(
|
|
get!(@query_field_init $query)
|
|
)*
|
|
};
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct RP($out);
|
|
|
|
impl restson::RestPath<( $( $arg_ty ),* )> for RP {
|
|
fn get_path(args: ( $( $arg_ty ),* )) -> Result<String, restson::Error> {
|
|
let ( $( $arg ),* ) = args;
|
|
Ok(format!($path, $( $arg = $arg ),* ))
|
|
}
|
|
}
|
|
|
|
async move {
|
|
let result = client.get_with::<_, RP>(( $( $arg ),* ), &query.as_pairs()).await?;
|
|
Ok(result.into_inner().0)
|
|
}
|
|
}
|
|
};
|
|
|
|
// Query helpers
|
|
(@query_field $field:ident) => { $field: Option<bool>, };
|
|
(@query_field $field:ident = $ty:ty) => { $field: $ty, };
|
|
|
|
(@query_field_struct $field:ident) => { $field: Option<bool>, };
|
|
(@query_field_struct $field:ident = $ty:ty) => { $field: $ty, };
|
|
|
|
(@query_field_init $field:ident) => { $field, };
|
|
(@query_field_init $field:ident = $ty:ty) => { $field, };
|
|
|
|
(@push_pair $vec:ident, $self:ident, $field:ident = $ty:ty) => {
|
|
$vec.push((stringify!($field), $self.$field.to_string()));
|
|
};
|
|
(@push_pair $vec:ident, $self:ident, $field:ident) => {
|
|
if let Some(v) = &$self.$field {
|
|
$vec.push((stringify!($field), v.to_string()));
|
|
}
|
|
};
|
|
}
|