mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
Merge pull request #18 from teloxide/impl_payload_macro
Add internal impl_payload macro
This commit is contained in:
commit
8a5081db61
4 changed files with 245 additions and 130 deletions
|
@ -106,3 +106,204 @@ macro_rules! req_future {
|
|||
|
||||
};
|
||||
}
|
||||
|
||||
/// 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 $([$into:ident])?
|
||||
,
|
||||
)*
|
||||
}
|
||||
)?
|
||||
|
||||
$(
|
||||
optional {
|
||||
$(
|
||||
$(
|
||||
#[ $($opt_field_meta:tt)* ]
|
||||
)*
|
||||
$opt_v:vis $opt_fields:ident : $OptFTy:ty $([$opt_into:ident])?
|
||||
),*
|
||||
$(,)?
|
||||
}
|
||||
)?
|
||||
}
|
||||
) => {
|
||||
$(
|
||||
#[ $($method_meta)* ]
|
||||
)*
|
||||
$vi struct $Method {
|
||||
$(
|
||||
$(
|
||||
$(
|
||||
#[ $($field_meta)* ]
|
||||
)*
|
||||
$v $fields : $FTy,
|
||||
)*
|
||||
)?
|
||||
$(
|
||||
$(
|
||||
$(
|
||||
#[ $($opt_field_meta)* ]
|
||||
)*
|
||||
$opt_v $opt_fields : core::option::Option<$OptFTy>,
|
||||
)*
|
||||
)?
|
||||
}
|
||||
|
||||
impl $Method {
|
||||
$vi fn new($($($fields : impl_payload!(@into? $FTy $([$into])?)),*)?) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$(
|
||||
$fields: $fields $(.$into())?,
|
||||
)*
|
||||
)?
|
||||
$(
|
||||
$(
|
||||
$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 $([$into])? }
|
||||
)*
|
||||
)?
|
||||
$(
|
||||
$(
|
||||
impl_payload! { @setter_opt $Method $opt_fields : $OptFTy $([$opt_into])? }
|
||||
)*
|
||||
)?
|
||||
}
|
||||
}
|
||||
|
||||
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) => {
|
||||
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) => {
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
(@into? $T:ty [into]) => {
|
||||
impl ::core::convert::Into<$T>
|
||||
};
|
||||
(@into? $T:ty) => {
|
||||
$T
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,29 +1,12 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
requests::{HasPayload, Payload},
|
||||
types::User,
|
||||
};
|
||||
use crate::types::User;
|
||||
|
||||
/// A filter method for testing your bot's auth token. Requires no parameters.
|
||||
/// Returns basic information about the bot in form of a [`User`] object.
|
||||
///
|
||||
/// [`User`]: crate::types::User
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default, Deserialize, Serialize)]
|
||||
pub struct GetMe {}
|
||||
|
||||
impl GetMe {
|
||||
pub const fn new() -> Self {
|
||||
GetMe {}
|
||||
}
|
||||
impl_payload! {
|
||||
/// A filter method for testing your bot's auth token. Requires no parameters.
|
||||
/// Returns basic information about the bot in form of a [`User`] object.
|
||||
///
|
||||
/// [`User`]: crate::types::User
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default, Deserialize, Serialize)]
|
||||
pub GetMe (GetMeSetters) => User {}
|
||||
}
|
||||
|
||||
impl Payload for GetMe {
|
||||
type Output = User;
|
||||
|
||||
const NAME: &'static str = "getMe";
|
||||
}
|
||||
|
||||
pub trait GetMeSetters: HasPayload<Payload = GetMe> + Sized {}
|
||||
|
||||
impl<P> GetMeSetters for P where P: HasPayload<Payload = GetMe> {}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/// Payloads - data types sended to relegram
|
||||
//! Payloads - data types sended to relegram
|
||||
|
||||
pub mod setters;
|
||||
|
||||
mod get_me;
|
||||
|
|
|
@ -1,112 +1,42 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
requests::{HasPayload, Payload},
|
||||
types::{ChatId, Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
use crate::types::{ChatId, Message, ParseMode, ReplyMarkup};
|
||||
|
||||
/// Use this method to send text messages.
|
||||
///
|
||||
/// On success, the sent [`Message`] is returned.
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
|
||||
pub struct SendMessage {
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub chat_id: ChatId,
|
||||
/// Text of the message to be sent
|
||||
pub text: String,
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show
|
||||
/// [bold, italic, fixed-width text or inline URLs] in your bot's message.
|
||||
impl_payload! {
|
||||
/// Use this method to send text messages.
|
||||
///
|
||||
/// [Markdown]: crate::types::ParseMode::Markdown
|
||||
/// [HTML]: crate::types::ParseMode::HTML
|
||||
/// [bold, italic, fixed-width text or inline URLs]:
|
||||
/// crate::types::ParseMode
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
/// Disables link previews for links in this message
|
||||
pub disable_web_page_preview: Option<bool>,
|
||||
/// Sends the message silently.
|
||||
/// Users will receive a notification with no sound.
|
||||
pub disable_notification: Option<bool>,
|
||||
/// If the message is a reply, [id] of the original message
|
||||
/// On success, the sent [`Message`] is returned.
|
||||
///
|
||||
/// [id]: crate::types::Message::id
|
||||
pub reply_to_message_id: Option<i32>,
|
||||
/// Additional interface options.
|
||||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl Payload for SendMessage {
|
||||
type Output = Message;
|
||||
|
||||
const NAME: &'static str = "sendMessage";
|
||||
}
|
||||
|
||||
impl SendMessage {
|
||||
pub fn new<C, T>(chat_id: C, text: T) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
T: Into<String>,
|
||||
{
|
||||
SendMessage {
|
||||
chat_id: chat_id.into(),
|
||||
text: text.into(),
|
||||
parse_mode: None,
|
||||
disable_web_page_preview: None,
|
||||
disable_notification: None,
|
||||
reply_to_message_id: None,
|
||||
reply_markup: None,
|
||||
/// [`Message`]: crate::types::Message
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
|
||||
pub SendMessage (SendMessageSetters) => Message {
|
||||
required {
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub chat_id: ChatId [into],
|
||||
/// Text of the message to be sent
|
||||
pub text: String [into],
|
||||
}
|
||||
optional {
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show
|
||||
/// [bold, italic, fixed-width text or inline URLs] in your bot's message.
|
||||
///
|
||||
/// [Markdown]: crate::types::ParseMode::Markdown
|
||||
/// [HTML]: crate::types::ParseMode::HTML
|
||||
/// [bold, italic, fixed-width text or inline URLs]: crate::types::ParseMode
|
||||
pub parse_mode: ParseMode,
|
||||
/// Disables link previews for links in this message
|
||||
pub disable_web_page_preview: bool,
|
||||
/// Sends the message silently.
|
||||
/// Users will receive a notification with no sound.
|
||||
pub disable_notification: bool,
|
||||
/// If the message is a reply, [id] of the original message
|
||||
///
|
||||
/// [id]: crate::types::Message::id
|
||||
pub reply_to_message_id: i32,
|
||||
/// Additional interface options.
|
||||
pub reply_markup: ReplyMarkup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SendMessageSetters: HasPayload<Payload = SendMessage> + Sized {
|
||||
fn chat_id<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.payload_mut().chat_id = value.into();
|
||||
self
|
||||
}
|
||||
|
||||
fn text<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<String>, // TODO: into?
|
||||
{
|
||||
self.payload_mut().text = value.into();
|
||||
self
|
||||
}
|
||||
|
||||
fn parse_mode(mut self, value: ParseMode) -> Self {
|
||||
self.payload_mut().parse_mode = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
fn disable_web_page_preview(mut self, value: bool) -> Self {
|
||||
self.payload_mut().disable_web_page_preview = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
fn disable_notification(mut self, value: bool) -> Self {
|
||||
self.payload_mut().disable_notification = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
fn reply_to_message_id(mut self, value: i32) -> Self {
|
||||
self.payload_mut().reply_to_message_id = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
fn reply_markup<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ReplyMarkup>,
|
||||
{
|
||||
self.payload_mut().reply_markup = Some(value.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> SendMessageSetters for P where P: HasPayload<Payload = SendMessage> {}
|
||||
|
|
Loading…
Add table
Reference in a new issue