mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-24 09:16:12 +01:00
79b5c41bb5
Co-authored-by: Temirkhan Myrzamadi <hirrolot@gmail.com>
367 lines
11 KiB
Rust
367 lines
11 KiB
Rust
#[macro_use]
|
|
macro_rules! forward_to_unsuported_ty {
|
|
(
|
|
supported: $supported:expr;
|
|
simple { $( $method:ident $arg:ty )* }
|
|
unit { $( $method1:ident $ty:expr )* }
|
|
compound {
|
|
$( $method2:ident $( <$T:ident: ?Sized + Serialize> )? ( $( $args:tt )* ) -> $ret:ty => $message:expr )*
|
|
}
|
|
) => {
|
|
$(
|
|
fn $method(self, _: $arg) -> Result<Self::Ok, Self::Error> {
|
|
Err(Self::Error::UnsupportedType {
|
|
ty: stringify!($arg),
|
|
supported: $supported,
|
|
})
|
|
}
|
|
)+
|
|
|
|
$(
|
|
fn $method1(self) -> Result<Self::Ok, Self::Error> {
|
|
Err(Self::Error::UnsupportedType {
|
|
ty: $ty,
|
|
supported: $supported,
|
|
})
|
|
}
|
|
)+
|
|
|
|
$(
|
|
fn $method2 $( <$T: ?Sized + Serialize> )? (self, $( $args )*) -> Result<$ret, Self::Error> {
|
|
Err(Self::Error::UnsupportedType {
|
|
ty: $message,
|
|
supported: $supported,
|
|
})
|
|
}
|
|
)+
|
|
};
|
|
}
|
|
|
|
#[macro_use]
|
|
macro_rules! req_future {
|
|
(
|
|
$v2:vis def: | $( $arg:ident: $ArgTy:ty ),* $(,)? | $body:block
|
|
|
|
$(#[$($meta:tt)*])*
|
|
$v:vis $i:ident<$T:ident> ($inner:ident) -> $Out:ty
|
|
$(where $($wh:tt)*)?
|
|
) => {
|
|
#[pin_project::pin_project]
|
|
$v struct $i<$T>
|
|
$(where $($wh)*)?
|
|
{
|
|
#[pin]
|
|
inner: $inner::$i<$T>
|
|
}
|
|
|
|
impl<$T> $i<$T>
|
|
$(where $($wh)*)?
|
|
{
|
|
$v2 fn new($( $arg: $ArgTy ),*) -> Self {
|
|
Self { inner: $inner::def($( $arg ),*) }
|
|
}
|
|
}
|
|
|
|
// HACK(waffle): workaround for https://github.com/rust-lang/rust/issues/55997
|
|
mod $inner {
|
|
#![allow(type_alias_bounds)]
|
|
|
|
// Mostly to bring `use`s
|
|
#[allow(unused_imports)]
|
|
use super::{*, $i as _};
|
|
|
|
#[cfg(feature = "nightly")]
|
|
pub(crate) type $i<$T>
|
|
$(where $($wh)*)? = impl ::core::future::Future<Output = $Out>;
|
|
|
|
#[cfg(feature = "nightly")]
|
|
pub(crate) fn def<$T>($( $arg: $ArgTy ),*) -> $i<$T>
|
|
$(where $($wh)*)?
|
|
{
|
|
$body
|
|
}
|
|
|
|
#[cfg(not(feature = "nightly"))]
|
|
pub(crate) type $i<$T>
|
|
$(where $($wh)*)? = ::core::pin::Pin<Box<dyn ::core::future::Future<Output = $Out> + ::core::marker::Send + 'static>>;
|
|
|
|
#[cfg(not(feature = "nightly"))]
|
|
pub(crate) fn def<$T>($( $arg: $ArgTy ),*) -> $i<$T>
|
|
$(where $($wh)*)?
|
|
{
|
|
Box::pin($body)
|
|
}
|
|
}
|
|
|
|
impl<$T> ::core::future::Future for $i<$T>
|
|
$(where $($wh)*)?
|
|
{
|
|
type Output = $Out;
|
|
|
|
fn poll(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) -> ::core::task::Poll<Self::Output> {
|
|
let this = self.project();
|
|
this.inner.poll(cx)
|
|
}
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
/// Declares an item with a doc attribute computed by some macro expression.
|
|
/// This allows documentation to be dynamically generated based on input.
|
|
/// Necessary to work around https://github.com/rust-lang/rust/issues/52607.
|
|
#[macro_use]
|
|
macro_rules! calculated_doc {
|
|
(
|
|
$(
|
|
#[doc = $doc:expr]
|
|
$thing:item
|
|
)*
|
|
) => (
|
|
$(
|
|
#[doc = $doc]
|
|
$thing
|
|
)*
|
|
);
|
|
}
|
|
|
|
/// Declare payload type, implement `Payload` trait amd ::new method for it,
|
|
/// declare setters trait and implement it for all type which have payload.
|
|
#[macro_use]
|
|
macro_rules! impl_payload {
|
|
(
|
|
$(
|
|
#[ $($method_meta:tt)* ]
|
|
)*
|
|
$vi:vis $Method:ident ($Setters:ident) => $Ret:ty {
|
|
$(
|
|
required {
|
|
$(
|
|
$(
|
|
#[ $($field_meta:tt)* ]
|
|
)*
|
|
$v:vis $fields:ident : $FTy:ty $([$conv:ident])?
|
|
,
|
|
)*
|
|
}
|
|
)?
|
|
|
|
$(
|
|
optional {
|
|
$(
|
|
$(
|
|
#[ $($opt_field_meta:tt)* ]
|
|
)*
|
|
$opt_v:vis $opt_fields:ident : $OptFTy:ty $([$opt_conv:ident])?
|
|
),*
|
|
$(,)?
|
|
}
|
|
)?
|
|
}
|
|
) => {
|
|
#[serde_with_macros::skip_serializing_none]
|
|
#[must_use = "Requests do nothing unless sent"]
|
|
$(
|
|
#[ $($method_meta)* ]
|
|
)*
|
|
$vi struct $Method {
|
|
$(
|
|
$(
|
|
$(
|
|
#[ $($field_meta)* ]
|
|
)*
|
|
$v $fields : $FTy,
|
|
)*
|
|
)?
|
|
$(
|
|
$(
|
|
$(
|
|
#[ $($opt_field_meta)* ]
|
|
)*
|
|
$opt_v $opt_fields : core::option::Option<$OptFTy>,
|
|
)*
|
|
)?
|
|
}
|
|
|
|
impl $Method {
|
|
// We mirror Telegram API and can't do anything with too many arguments.
|
|
#[allow(clippy::too_many_arguments)]
|
|
// It's just easier for macros to generate such code.
|
|
#[allow(clippy::redundant_field_names)]
|
|
$vi fn new($($($fields : impl_payload!(@convert? $FTy $([$conv])?)),*)?) -> Self {
|
|
Self {
|
|
$(
|
|
$(
|
|
$fields: impl_payload!(@convert_map ($fields) $([$conv])?),
|
|
)*
|
|
)?
|
|
$(
|
|
$(
|
|
$opt_fields: None,
|
|
)*
|
|
)?
|
|
}
|
|
}
|
|
}
|
|
|
|
impl $crate::requests::Payload for $Method {
|
|
type Output = $Ret;
|
|
|
|
const NAME: &'static str = stringify!($Method);
|
|
}
|
|
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setters for fields of [`",
|
|
stringify!($Method),
|
|
"`]"
|
|
)]
|
|
$vi trait $Setters: $crate::requests::HasPayload<Payload = $Method> + ::core::marker::Sized {
|
|
$(
|
|
$(
|
|
impl_payload! { @setter $Method $fields : $FTy $([$conv])? }
|
|
)*
|
|
)?
|
|
$(
|
|
$(
|
|
impl_payload! { @setter_opt $Method $opt_fields : $OptFTy $([$opt_conv])? }
|
|
)*
|
|
)?
|
|
}
|
|
}
|
|
|
|
impl<P> $Setters for P where P: crate::requests::HasPayload<Payload = $Method> {}
|
|
};
|
|
(@setter_opt $Method:ident $field:ident : $FTy:ty [into]) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field<T>(mut self, value: T) -> Self
|
|
where
|
|
T: Into<$FTy>,
|
|
{
|
|
self.payload_mut().$field = Some(value.into());
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@setter_opt $Method:ident $field:ident : $FTy:ty [collect]) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field<T>(mut self, value: T) -> Self
|
|
where
|
|
T: ::core::iter::IntoIterator<Item = <$FTy as ::core::iter::IntoIterator>::Item>,
|
|
{
|
|
self.payload_mut().$field = Some(value.into_iter().collect());
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@setter_opt $Method:ident $field:ident : $FTy:ty) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field(mut self, value: $FTy) -> Self {
|
|
self.payload_mut().$field = Some(value);
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@setter $Method:ident $field:ident : $FTy:ty [into]) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field<T>(mut self, value: T) -> Self
|
|
where
|
|
T: Into<$FTy>,
|
|
{
|
|
self.payload_mut().$field = value.into();
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@setter $Method:ident $field:ident : $FTy:ty [collect]) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field<T>(mut self, value: T) -> Self
|
|
where
|
|
T: ::core::iter::IntoIterator<Item = <$FTy as ::core::iter::IntoIterator>::Item>,
|
|
{
|
|
self.payload_mut().$field = value.into_iter().collect();
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@setter $Method:ident $field:ident : $FTy:ty) => {
|
|
calculated_doc! {
|
|
#[doc = concat!(
|
|
"Setter for [`",
|
|
stringify!($field),
|
|
"`](",
|
|
stringify!($Method),
|
|
"::",
|
|
stringify!($field),
|
|
") field."
|
|
)]
|
|
fn $field(mut self, value: $FTy) -> Self {
|
|
self.payload_mut().$field = value;
|
|
self
|
|
}
|
|
}
|
|
};
|
|
(@convert? $T:ty [into]) => {
|
|
impl ::core::convert::Into<$T>
|
|
};
|
|
(@convert? $T:ty [collect]) => {
|
|
impl ::core::iter::IntoIterator<Item = <$T as ::core::iter::IntoIterator>::Item>
|
|
};
|
|
(@convert? $T:ty) => {
|
|
$T
|
|
};
|
|
(@convert_map ($e:expr) [into]) => {
|
|
$e.into()
|
|
};
|
|
(@convert_map ($e:expr) [collect]) => {
|
|
$e.into_iter().collect()
|
|
};
|
|
(@convert_map ($e:expr)) => {
|
|
$e
|
|
};
|
|
}
|