mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-10 20:12:25 +01:00
Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # src/dispatching/dispatchers/filter/mod.rs
This commit is contained in:
commit
65320feaf0
29 changed files with 440 additions and 182 deletions
BIN
hw.doc
Normal file
BIN
hw.doc
Normal file
Binary file not shown.
|
@ -2,20 +2,20 @@ use crate::{
|
|||
bot::Bot,
|
||||
requests::{
|
||||
AnswerCallbackQuery, AnswerPreCheckoutQuery, AnswerShippingQuery,
|
||||
DeleteChatStickerSet, EditMessageLiveLocation, ForwardMessage,
|
||||
DeleteChatPhoto, DeleteChatStickerSet, EditMessageLiveLocation,
|
||||
ExportCharInviteLink, ForwardMessage, GetChat, GetChatAdministrators,
|
||||
GetChatMember, GetChatMembersCount, GetFile, GetMe, GetUpdates,
|
||||
KickChatMember, PinChatMessage, PromoteChatMember, RestrictChatMember,
|
||||
SendAnimation, SendAudio, SendChatAction, SendContact, SendDocument,
|
||||
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendPoll,
|
||||
SendVenue, SendVideo, SendVideoNote, SendVoice, SetChatDescription,
|
||||
SetChatStickerSet, StopMessageLiveLocation, UnbanChatMember,
|
||||
UnpinChatMessage, SetChatTitle, DeleteChatPhoto, SetChatPhoto,
|
||||
ExportCharInviteLink, SetChatPermissions
|
||||
KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember,
|
||||
RestrictChatMember, SendAnimation, SendAudio, SendChatAction,
|
||||
SendContact, SendDocument, SendLocation, SendMediaGroup, SendMessage,
|
||||
SendPhoto, SendPoll, SendVenue, SendVideo, SendVideoNote, SendVoice,
|
||||
SetChatDescription, SetChatPermissions, SetChatPhoto,
|
||||
SetChatStickerSet, SetChatTitle, StopMessageLiveLocation,
|
||||
UnbanChatMember, UnpinChatMessage,
|
||||
},
|
||||
types::{ChatAction, ChatId, ChatPermissions, InputFile, InputMedia},
|
||||
};
|
||||
|
||||
/// Telegram functions
|
||||
impl Bot {
|
||||
pub fn get_me(&self) -> GetMe {
|
||||
GetMe::new(self)
|
||||
|
@ -120,6 +120,13 @@ impl Bot {
|
|||
AnswerPreCheckoutQuery::new(self, pre_checkout_query_id, ok)
|
||||
}
|
||||
|
||||
pub fn get_chat<I>(&self, chat_id: I) -> GetChat
|
||||
where
|
||||
I: Into<ChatId>,
|
||||
{
|
||||
GetChat::new(self, chat_id)
|
||||
}
|
||||
|
||||
pub fn answer_shipping_query<I, O>(
|
||||
&self,
|
||||
shipping_query_id: I,
|
||||
|
@ -323,6 +330,16 @@ impl Bot {
|
|||
GetChatMember::new(self, chat_id, user_id)
|
||||
}
|
||||
|
||||
pub fn get_chat_administrators<C, I>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
) -> GetChatAdministrators
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
GetChatAdministrators::new(self, chat_id)
|
||||
}
|
||||
|
||||
pub fn get_chat_members_count<C>(&self, chat_id: C) -> GetChatMembersCount
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
|
@ -366,21 +383,21 @@ impl Bot {
|
|||
SetChatTitle::new(self, chat_id, title)
|
||||
}
|
||||
|
||||
pub fn delete_chat_photo<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
) -> DeleteChatPhoto
|
||||
pub fn delete_chat_photo<C>(&self, chat_id: C) -> DeleteChatPhoto
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
DeleteChatPhoto::new(self, chat_id)
|
||||
}
|
||||
|
||||
pub fn set_chat_photo<C, P>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
photo: P,
|
||||
) -> SetChatPhoto
|
||||
pub fn leave_chat<C>(&self, chat_id: C) -> LeaveChat
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
LeaveChat::new(self, chat_id)
|
||||
}
|
||||
|
||||
pub fn set_chat_photo<C, P>(&self, chat_id: C, photo: P) -> SetChatPhoto
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
P: Into<InputFile>,
|
||||
|
@ -388,10 +405,7 @@ impl Bot {
|
|||
SetChatPhoto::new(self, chat_id, photo)
|
||||
}
|
||||
|
||||
pub fn export_chat_invite_link<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
) -> ExportCharInviteLink
|
||||
pub fn export_chat_invite_link<C>(&self, chat_id: C) -> ExportCharInviteLink
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
|
|
|
@ -3,9 +3,9 @@ use futures::StreamExt;
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
dispatcher::{
|
||||
filter::Filter, handler::Handler, simple::error_policy::ErrorPolicy,
|
||||
updater::Updater,
|
||||
dispatching::{
|
||||
dispatchers::filter::error_policy::ErrorPolicy, filters::Filter,
|
||||
handler::Handler, updater::Updater,
|
||||
},
|
||||
types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind},
|
||||
};
|
||||
|
@ -17,13 +17,13 @@ type Handlers<'a, T, E> =
|
|||
|
||||
/// Dispatcher that dispatches updates from telegram.
|
||||
///
|
||||
/// This is 'simple' implementation with following limitations:
|
||||
/// This is 'filter' implementation with following limitations:
|
||||
/// - Error (`E` generic parameter) _must_ implement [`std::fmt::Debug`]
|
||||
/// - All 'handlers' are boxed
|
||||
/// - Handler's fututres are also boxed
|
||||
/// - [Custom error policy] is also boxed
|
||||
/// - All errors from [updater] are ignored (TODO: remove this limitation)
|
||||
/// - All handlers executed in order (this means that in dispatcher have 2
|
||||
/// - All handlers executed in order (this means that in dispatching have 2
|
||||
/// upadtes it will first execute some handler into complition with first
|
||||
/// update and **then** search for handler for second update, this is probably
|
||||
/// wrong)
|
||||
|
@ -37,8 +37,8 @@ type Handlers<'a, T, E> =
|
|||
/// async fn run() {
|
||||
/// use std::convert::Infallible;
|
||||
/// use telebofr::{
|
||||
/// dispatcher::{
|
||||
/// simple::{error_policy::ErrorPolicy, Dispatcher},
|
||||
/// dispatching::{
|
||||
/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher},
|
||||
/// updater::polling,
|
||||
/// },
|
||||
/// };
|
||||
|
@ -49,9 +49,9 @@ type Handlers<'a, T, E> =
|
|||
///
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
///
|
||||
/// // create dispatcher which handlers can't fail
|
||||
/// // create dispatching which handlers can't fail
|
||||
/// // with error policy that just ignores all errors (that can't ever happen)
|
||||
/// let mut dp = Dispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
||||
/// let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
||||
/// // Add 'handler' that will handle all messages sent to the bot
|
||||
/// .message_handler(true, |mes: Message| {
|
||||
/// async move { println!("New message: {:?}", mes) }
|
||||
|
@ -67,9 +67,9 @@ type Handlers<'a, T, E> =
|
|||
///
|
||||
/// [`std::fmt::Debug`]: std::fmt::Debug
|
||||
/// [Custom error policy]:
|
||||
/// crate::dispatcher::simple::error_policy::ErrorPolicy::Custom [updater]:
|
||||
/// crate::dispatcher::updater
|
||||
pub struct Dispatcher<'a, E> {
|
||||
/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]:
|
||||
/// crate::dispatching::updater
|
||||
pub struct FilterDispatcher<'a, E> {
|
||||
message_handlers: Handlers<'a, Message, E>,
|
||||
edited_message_handlers: Handlers<'a, Message, E>,
|
||||
channel_post_handlers: Handlers<'a, Message, E>,
|
||||
|
@ -80,12 +80,12 @@ pub struct Dispatcher<'a, E> {
|
|||
error_policy: ErrorPolicy<'a, E>,
|
||||
}
|
||||
|
||||
impl<'a, E> Dispatcher<'a, E>
|
||||
impl<'a, E> FilterDispatcher<'a, E>
|
||||
where
|
||||
E: std::fmt::Debug, // TODO: Is this really necessary?
|
||||
{
|
||||
pub fn new(error_policy: ErrorPolicy<'a, E>) -> Self {
|
||||
Dispatcher {
|
||||
FilterDispatcher {
|
||||
message_handlers: Vec::new(),
|
||||
edited_message_handlers: Vec::new(),
|
||||
channel_post_handlers: Vec::new(),
|
||||
|
@ -197,16 +197,29 @@ where
|
|||
|
||||
match kind {
|
||||
UpdateKind::Message(mes) => {
|
||||
self.handle(mes, &self.message_handlers).await;
|
||||
self.handle(mes, &self.message_handlers)
|
||||
.await;
|
||||
}
|
||||
UpdateKind::EditedMessage(mes) => {
|
||||
self.handle(mes, &self.edited_message_handlers).await;
|
||||
self.handle(
|
||||
mes,
|
||||
&self.edited_message_handlers,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
UpdateKind::ChannelPost(post) => {
|
||||
self.handle(post, &self.channel_post_handlers).await;
|
||||
self.handle(
|
||||
post,
|
||||
&self.channel_post_handlers,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
UpdateKind::EditedChannelPost(post) => {
|
||||
self.handle(post, &self.edited_channel_post_handlers).await;
|
||||
self.handle(
|
||||
post,
|
||||
&self.edited_channel_post_handlers,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
UpdateKind::InlineQuery(query) => {
|
||||
self.handle(query, &self.inline_query_handlers).await;
|
||||
|
@ -249,13 +262,13 @@ where
|
|||
}
|
||||
|
||||
#[async_trait(? Send)]
|
||||
impl<'a, U, E> crate::dispatcher::Dispatcher<'a, U> for Dispatcher<'a, E>
|
||||
impl<'a, U, E> crate::dispatching::Dispatcher<'a, U> for FilterDispatcher<'a, E>
|
||||
where
|
||||
E: std::fmt::Debug,
|
||||
U: Updater + 'a,
|
||||
{
|
||||
async fn dispatch(&'a mut self, updater: U) {
|
||||
Dispatcher::dispatch(self, updater).await
|
||||
FilterDispatcher::dispatch(self, updater).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,8 +282,10 @@ mod tests {
|
|||
use futures::Stream;
|
||||
|
||||
use crate::{
|
||||
dispatcher::{
|
||||
simple::{error_policy::ErrorPolicy, Dispatcher},
|
||||
dispatching::{
|
||||
dispatchers::filter::{
|
||||
error_policy::ErrorPolicy, FilterDispatcher,
|
||||
},
|
||||
updater::StreamUpdater,
|
||||
},
|
||||
types::{
|
||||
|
@ -284,7 +299,7 @@ mod tests {
|
|||
let counter = &AtomicI32::new(0);
|
||||
let counter2 = &AtomicI32::new(0);
|
||||
|
||||
let mut dp = Dispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
||||
let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
||||
.message_handler(true, |_mes: Message| {
|
||||
async move {
|
||||
counter.fetch_add(1, Ordering::SeqCst);
|
3
src/dispatching/dispatchers/mod.rs
Normal file
3
src/dispatching/dispatchers/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub use filter::FilterDispatcher;
|
||||
|
||||
pub mod filter;
|
|
@ -6,7 +6,7 @@ pub trait Filter<T> {
|
|||
}
|
||||
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::Filter;
|
||||
/// use telebofr::dispatching::filters::Filter;
|
||||
///
|
||||
/// let closure = |i: &i32| -> bool { *i >= 42 };
|
||||
/// assert!(closure.test(&42));
|
||||
|
@ -22,7 +22,7 @@ impl<T, F: Fn(&T) -> bool> Filter<T> for F {
|
|||
}
|
||||
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::Filter;
|
||||
/// use telebofr::dispatching::filters::Filter;
|
||||
///
|
||||
/// assert!(true.test(&()));
|
||||
/// assert_eq!(false.test(&()), false);
|
||||
|
@ -42,7 +42,7 @@ impl<T> Filter<T> for bool {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{And, Filter};
|
||||
/// use telebofr::dispatching::filters::{And, Filter};
|
||||
///
|
||||
/// // Note: bool can be treated as `Filter` that always return self.
|
||||
/// assert_eq!(And::new(true, false).test(&()), false);
|
||||
|
@ -73,13 +73,13 @@ where
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{and, Filter};
|
||||
/// use telebofr::dispatching::filters::{and, Filter};
|
||||
///
|
||||
/// assert!(and(true, true).test(&()));
|
||||
/// assert_eq!(and(true, false).test(&()), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`And::new`]: crate::dispatcher::filter::And::new
|
||||
/// [`And::new`]: crate::dispatching::filter::And::new
|
||||
pub fn and<A, B>(a: A, b: B) -> And<A, B> {
|
||||
And::new(a, b)
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ pub fn and<A, B>(a: A, b: B) -> And<A, B> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{Filter, Or};
|
||||
/// use telebofr::dispatching::filters::{Filter, Or};
|
||||
///
|
||||
/// // Note: bool can be treated as `Filter` that always return self.
|
||||
/// assert!(Or::new(true, false).test(&()));
|
||||
|
@ -124,13 +124,13 @@ where
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{or, Filter};
|
||||
/// use telebofr::dispatching::filters::{or, Filter};
|
||||
///
|
||||
/// assert!(or(true, false).test(&()));
|
||||
/// assert_eq!(or(false, false).test(&()), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`Or::new`]: crate::dispatcher::filter::Or::new
|
||||
/// [`Or::new`]: crate::dispatching::filter::Or::new
|
||||
pub fn or<A, B>(a: A, b: B) -> Or<A, B> {
|
||||
Or::new(a, b)
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ pub fn or<A, B>(a: A, b: B) -> Or<A, B> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{Filter, Not};
|
||||
/// use telebofr::dispatching::filters::{Filter, Not};
|
||||
///
|
||||
/// // Note: bool can be treated as `Filter` that always return self.
|
||||
/// assert!(Not::new(false).test(&()));
|
||||
|
@ -169,13 +169,13 @@ where
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{not, Filter};
|
||||
/// use telebofr::dispatching::filters::{not, Filter};
|
||||
///
|
||||
/// assert!(not(false).test(&()));
|
||||
/// assert_eq!(not(true).test(&()), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`Not::new`]: crate::dispatcher::filter::Not::new
|
||||
/// [`Not::new`]: crate::dispatching::filter::Not::new
|
||||
pub fn not<A>(a: A) -> Not<A> {
|
||||
Not::new(a)
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ pub fn not<A>(a: A) -> Not<A> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::{all, dispatcher::filter::Filter};
|
||||
/// use telebofr::{all, dispatching::filters::Filter};
|
||||
///
|
||||
/// assert!(all![true].test(&()));
|
||||
/// assert!(all![true, true].test(&()));
|
||||
|
@ -199,12 +199,12 @@ pub fn not<A>(a: A) -> Not<A> {
|
|||
/// assert_eq!(all![false, false].test(&()), false);
|
||||
/// ```
|
||||
///
|
||||
/// [filter]: crate::dispatcher::filter::Filter
|
||||
/// [filter]: crate::dispatching::filter::Filter
|
||||
#[macro_export]
|
||||
macro_rules! all {
|
||||
($one:expr) => { $one };
|
||||
($head:expr, $($tail:tt)+) => {
|
||||
$crate::dispatcher::filter::And::new(
|
||||
$crate::dispatching::filters::And::new(
|
||||
$head,
|
||||
$crate::all!($($tail)+)
|
||||
)
|
||||
|
@ -218,7 +218,7 @@ macro_rules! all {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::{any, dispatcher::filter::Filter};
|
||||
/// use telebofr::{any, dispatching::filters::Filter};
|
||||
///
|
||||
/// assert!(any![true].test(&()));
|
||||
/// assert!(any![true, true].test(&()));
|
||||
|
@ -230,12 +230,12 @@ macro_rules! all {
|
|||
/// assert_eq!(any![false, false, false].test(&()), false);
|
||||
/// ```
|
||||
///
|
||||
/// [filter]: crate::dispatcher::filter::Filter
|
||||
/// [filter]: crate::dispatching::filter::Filter
|
||||
#[macro_export]
|
||||
macro_rules! any {
|
||||
($one:expr) => { $one };
|
||||
($head:expr, $($tail:tt)+) => {
|
||||
$crate::dispatcher::filter::Or::new(
|
||||
$crate::dispatching::filters::Or::new(
|
||||
$head,
|
||||
$crate::all!($($tail)+)
|
||||
)
|
||||
|
@ -246,7 +246,7 @@ macro_rules! any {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{f, And, Filter, Or, F};
|
||||
/// use telebofr::dispatching::filters::{f, And, Filter, Or, F};
|
||||
///
|
||||
/// let flt1 = |i: &i32| -> bool { *i > 17 };
|
||||
/// let flt2 = |i: &i32| -> bool { *i < 42 };
|
||||
|
@ -277,7 +277,7 @@ pub struct F<A>(A);
|
|||
|
||||
/// Constructor fn for [F]
|
||||
///
|
||||
/// [F]: crate::dispatcher::filter::F;
|
||||
/// [F]: crate::dispatching::filter::F;
|
||||
pub fn f<A>(a: A) -> F<A> {
|
||||
F(a)
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ pub trait FilterExt<T> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{Filter, FilterExt};
|
||||
/// use telebofr::dispatching::filters::{Filter, FilterExt};
|
||||
///
|
||||
/// let flt = |i: &i32| -> bool { *i > 0 };
|
||||
/// let flt = flt.not();
|
||||
|
@ -322,7 +322,7 @@ pub trait FilterExt<T> {
|
|||
/// assert_eq!(flt.test(&1), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`Not::new`]: crate::dispatcher::filter::Not::new
|
||||
/// [`Not::new`]: crate::dispatching::filter::Not::new
|
||||
fn not(self) -> Not<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -334,7 +334,7 @@ pub trait FilterExt<T> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{Filter, FilterExt};
|
||||
/// use telebofr::dispatching::filters::{Filter, FilterExt};
|
||||
///
|
||||
/// let flt = |i: &i32| -> bool { *i > 0 };
|
||||
/// let flt = flt.and(|i: &i32| *i < 42);
|
||||
|
@ -344,7 +344,7 @@ pub trait FilterExt<T> {
|
|||
/// assert_eq!(flt.test(&43), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`Not::new`]: crate::dispatcher::filter::And::new
|
||||
/// [`Not::new`]: crate::dispatching::filter::And::new
|
||||
fn and<B>(self, other: B) -> And<Self, B>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -356,7 +356,7 @@ pub trait FilterExt<T> {
|
|||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use telebofr::dispatcher::filter::{Filter, FilterExt};
|
||||
/// use telebofr::dispatching::filters::{Filter, FilterExt};
|
||||
///
|
||||
/// let flt = |i: &i32| -> bool { *i < 0 };
|
||||
/// let flt = flt.or(|i: &i32| *i > 42);
|
||||
|
@ -366,7 +366,7 @@ pub trait FilterExt<T> {
|
|||
/// assert_eq!(flt.test(&17), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`Not::new`]: crate::dispatcher::filter::Or::new
|
||||
/// [`Not::new`]: crate::dispatching::filter::Or::new
|
||||
fn or<B>(self, other: B) -> Or<Self, B>
|
||||
where
|
||||
Self: Sized,
|
|
@ -1,12 +1,12 @@
|
|||
//! Update dispatching.
|
||||
|
||||
use async_trait::async_trait;
|
||||
pub use filter::Filter;
|
||||
pub use filters::Filter;
|
||||
pub use handler::Handler;
|
||||
|
||||
pub mod filter;
|
||||
pub mod dispatchers;
|
||||
pub mod filters;
|
||||
pub mod handler;
|
||||
pub mod simple;
|
||||
pub mod updater;
|
||||
|
||||
#[async_trait(? Send)]
|
|
@ -12,6 +12,6 @@ mod errors;
|
|||
mod network;
|
||||
|
||||
mod bot;
|
||||
pub mod dispatcher;
|
||||
pub mod dispatching;
|
||||
pub mod requests;
|
||||
pub mod types;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use reqwest::StatusCode;
|
||||
|
||||
use crate::{
|
||||
requests::ResponseResult, types::ResponseParameters, RequestError,
|
||||
requests::ResponseResult,
|
||||
types::{False, ResponseParameters, True},
|
||||
RequestError,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -10,14 +12,14 @@ pub enum TelegramResponse<R> {
|
|||
Ok {
|
||||
/// A dummy field. Used only for deserialization.
|
||||
#[allow(dead_code)]
|
||||
ok: bool, // TODO: True type
|
||||
ok: True,
|
||||
|
||||
result: R,
|
||||
},
|
||||
Err {
|
||||
/// A dummy field. Used only for deserialization.
|
||||
#[allow(dead_code)]
|
||||
ok: bool, // TODO: False type
|
||||
ok: False,
|
||||
|
||||
description: String,
|
||||
error_code: u16,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::True,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Use this method to send answers to callback queries sent from inline
|
||||
/// keyboards. The answer will be displayed to the user as a notification at the
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::bot::Bot;
|
||||
use crate::types::{ChatId, True};
|
||||
use crate::requests::{ResponseResult, Request};
|
||||
use crate::network;
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, True},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct DeleteChatPhoto<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
bot: &'a Bot,
|
||||
|
||||
chat_id: ChatId
|
||||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -28,15 +30,16 @@ impl DeleteChatPhoto<'_> {
|
|||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"deleteChatPhoto",
|
||||
&self
|
||||
).await
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DeleteChatPhoto<'a> {
|
||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, True},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Use this method to delete a group sticker set from a supergroup. The bot
|
||||
/// must be an administrator in the chat for this to work and must have the
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::bot::Bot;
|
||||
use crate::types::ChatId;
|
||||
use crate::requests::{ResponseResult, Request};
|
||||
use crate::network;
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::ChatId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ExportCharInviteLink<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
bot: &'a Bot,
|
||||
|
||||
chat_id: ChatId
|
||||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -28,15 +30,16 @@ impl ExportCharInviteLink<'_> {
|
|||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"exportChatInviteLink",
|
||||
&self
|
||||
).await
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExportCharInviteLink<'a> {
|
||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
|
@ -64,7 +67,8 @@ mod tests {
|
|||
let method = ExportCharInviteLink::new(&bot, chat_id);
|
||||
|
||||
let expected = r#"{"chat_id":123}"#;
|
||||
let actual = serde_json::to_string::<ExportCharInviteLink>(&method).unwrap();
|
||||
let actual =
|
||||
serde_json::to_string::<ExportCharInviteLink>(&method).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,11 +42,21 @@ impl GetChat<'_> {
|
|||
}
|
||||
|
||||
impl<'a> GetChat<'a> {
|
||||
pub fn chat_id<C>(mut self, value: C) -> Self
|
||||
pub(crate) fn new<F>(bot: &'a Bot, chat_id: F) -> Self
|
||||
where
|
||||
F: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
chat_id: chat_id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_id<C>(mut self, chat_id: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = value.into();
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
64
src/requests/get_chat_administrators.rs
Normal file
64
src/requests/get_chat_administrators.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, ChatMember},
|
||||
};
|
||||
|
||||
/// Use this method to get a list of administrators in a chat. On success,
|
||||
/// returns an Array of ChatMember objects that contains information about all
|
||||
/// chat administrators except other bots. If the chat is a group or a
|
||||
/// supergroup and no administrators were appointed, only the creator will be
|
||||
/// returned
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct GetChatAdministrators<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
bot: &'a Bot,
|
||||
|
||||
/// Unique identifier for the target chat or username of the target
|
||||
/// supergroup or channel (in the format @channelusername)
|
||||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for GetChatAdministrators<'_> {
|
||||
type Output = Vec<ChatMember>;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::Output> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetChatAdministrators<'_> {
|
||||
async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
|
||||
network::request_json(
|
||||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"getChatAdministrators",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> GetChatAdministrators<'a> {
|
||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
chat_id: chat_id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_id<C>(mut self, value: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = value.into();
|
||||
self
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, ChatMember},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Use this method to get information about a member of a chat. Returns a
|
||||
/// ChatMember object on success.
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// A simple method for testing your bot's auth token. Requires no parameters.
|
||||
/// 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.
|
||||
pub struct GetMe<'a> {
|
||||
bot: &'a Bot,
|
||||
|
|
59
src/requests/leave_chat.rs
Normal file
59
src/requests/leave_chat.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::ChatId,
|
||||
};
|
||||
|
||||
/// Use this method for your bot to leave a group, supergroup or channel.
|
||||
/// Returns True on success.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct LeaveChat<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
bot: &'a Bot,
|
||||
/// Unique identifier for the target chat or username
|
||||
/// of the target supergroup or channel (in the format @channelusername)
|
||||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for LeaveChat<'_> {
|
||||
type Output = bool;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::Output> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl LeaveChat<'_> {
|
||||
pub async fn send(self) -> ResponseResult<bool> {
|
||||
network::request_json(
|
||||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"leaveChat",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LeaveChat<'a> {
|
||||
pub(crate) fn new<F>(bot: &'a Bot, chat_id: F) -> Self
|
||||
where
|
||||
F: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
chat_id: chat_id.into(),
|
||||
}
|
||||
}
|
||||
pub fn chat_id<C>(mut self, chat_id: C) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
//! API requests.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub use answer_callback_query::*;
|
||||
pub use answer_pre_checkout_query::*;
|
||||
pub use answer_shipping_query::*;
|
||||
|
@ -12,6 +9,7 @@ pub use edit_message_live_location::*;
|
|||
pub use export_chat_invite_link::*;
|
||||
pub use forward_message::*;
|
||||
pub use get_chat::*;
|
||||
pub use get_chat_administrators::*;
|
||||
pub use get_chat_member::*;
|
||||
pub use get_chat_members_count::*;
|
||||
pub use get_file::*;
|
||||
|
@ -19,6 +17,7 @@ pub use get_me::*;
|
|||
pub use get_updates::*;
|
||||
pub use get_user_profile_photos::*;
|
||||
pub use kick_chat_member::*;
|
||||
pub use leave_chat::*;
|
||||
pub use pin_chat_message::*;
|
||||
pub use promote_chat_member::*;
|
||||
pub use restrict_chat_member::*;
|
||||
|
@ -57,6 +56,7 @@ mod edit_message_live_location;
|
|||
mod export_chat_invite_link;
|
||||
mod forward_message;
|
||||
mod get_chat;
|
||||
mod get_chat_administrators;
|
||||
mod get_chat_member;
|
||||
mod get_chat_members_count;
|
||||
mod get_file;
|
||||
|
@ -64,6 +64,7 @@ mod get_me;
|
|||
mod get_updates;
|
||||
mod get_user_profile_photos;
|
||||
mod kick_chat_member;
|
||||
mod leave_chat;
|
||||
mod pin_chat_message;
|
||||
mod promote_chat_member;
|
||||
mod restrict_chat_member;
|
||||
|
@ -90,6 +91,9 @@ mod stop_message_live_location;
|
|||
mod unban_chat_member;
|
||||
mod unpin_chat_message;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
/// A type that is returned from `Request::send_boxed`.
|
||||
pub type ResponseResult<T> = Result<T, crate::RequestError>;
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::bot::Bot;
|
||||
use crate::types::{ChatId, ChatPermissions, True};
|
||||
use crate::requests::{ResponseResult, Request};
|
||||
use crate::network;
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, ChatPermissions, True},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct SetChatPermissions<'a> {
|
||||
|
@ -11,7 +13,7 @@ pub struct SetChatPermissions<'a> {
|
|||
bot: &'a Bot,
|
||||
|
||||
chat_id: ChatId,
|
||||
permissions: ChatPermissions
|
||||
permissions: ChatPermissions,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -29,17 +31,14 @@ impl SetChatPermissions<'_> {
|
|||
self.bot.client(),
|
||||
self.bot.token(),
|
||||
"setChatPermissions",
|
||||
&self
|
||||
).await
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SetChatPermissions<'a> {
|
||||
pub(crate) fn new<C, CP>(
|
||||
bot: &'a Bot,
|
||||
chat_id: C,
|
||||
permissions: CP,
|
||||
) -> Self
|
||||
pub(crate) fn new<C, CP>(bot: &'a Bot, chat_id: C, permissions: CP) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
CP: Into<ChatPermissions>,
|
||||
|
@ -61,7 +60,7 @@ impl<'a> SetChatPermissions<'a> {
|
|||
|
||||
pub fn permissions<CP>(mut self, permissions: CP) -> Self
|
||||
where
|
||||
CP: Into<ChatPermissions>
|
||||
CP: Into<ChatPermissions>,
|
||||
{
|
||||
self.permissions = permissions.into();
|
||||
self
|
||||
|
@ -84,12 +83,14 @@ mod tests {
|
|||
can_add_web_page_previews: None,
|
||||
can_change_info: None,
|
||||
can_invite_users: None,
|
||||
can_pin_messages: None
|
||||
can_pin_messages: None,
|
||||
};
|
||||
let method = SetChatPermissions::new(&bot, chat_id, permissions);
|
||||
|
||||
let expected = r#"{"chat_id":123,"permissions":{"can_send_messages":true}}"#;
|
||||
let actual = serde_json::to_string::<SetChatPermissions>(&method).unwrap();
|
||||
let expected =
|
||||
r#"{"chat_id":123,"permissions":{"can_send_messages":true}}"#;
|
||||
let actual =
|
||||
serde_json::to_string::<SetChatPermissions>(&method).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::bot::Bot;
|
||||
use crate::types::{ChatId, True, InputFile};
|
||||
use crate::requests::{Request, ResponseResult};
|
||||
use crate::network;
|
||||
use crate::requests::form_builder::FormBuilder;
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||
types::{ChatId, InputFile, True},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct SetChatPhoto<'a> {
|
||||
|
@ -35,16 +36,13 @@ impl SetChatPhoto<'_> {
|
|||
self.bot.token(),
|
||||
"setChatPhoto",
|
||||
params.build(),
|
||||
).await
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SetChatPhoto<'a> {
|
||||
pub(crate) fn new<C, P>(
|
||||
bot: &'a Bot,
|
||||
chat_id: C,
|
||||
photo: P
|
||||
) -> Self
|
||||
pub(crate) fn new<C, P>(bot: &'a Bot, chat_id: C, photo: P) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
P: Into<InputFile>,
|
||||
|
@ -82,7 +80,8 @@ mod tests {
|
|||
let bot = Bot::new("token");
|
||||
let chat_id = 123;
|
||||
let photo_url = "https://some_url".to_string();
|
||||
let method = SetChatPhoto::new(&bot, chat_id, InputFile::Url(photo_url));
|
||||
let method =
|
||||
SetChatPhoto::new(&bot, chat_id, InputFile::Url(photo_url));
|
||||
|
||||
let expected = r#"{"chat_id":123,"photo":"https://some_url"}"#;
|
||||
let actual = serde_json::to_string::<SetChatPhoto>(&method).unwrap();
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
bot::Bot,
|
||||
network,
|
||||
requests::{Request, ResponseResult},
|
||||
types::{ChatId, True},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Use this method to set a new group sticker set for a supergroup. The bot
|
||||
/// must be an administrator in the chat for this to work and must have the
|
||||
|
|
|
@ -38,14 +38,10 @@ impl SetChatTitle<'_> {
|
|||
}
|
||||
|
||||
impl<'a> SetChatTitle<'a> {
|
||||
pub(crate) fn new<C, T>(
|
||||
bot: &'a Bot,
|
||||
chat_id: C,
|
||||
title: T
|
||||
) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
T: Into<String>,
|
||||
pub(crate) fn new<C, T>(bot: &'a Bot, chat_id: C, title: T) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
T: Into<String>,
|
||||
{
|
||||
Self {
|
||||
bot,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// This object represents one button of the reply keyboard. For simple text
|
||||
/// This object represents one button of the reply keyboard. For filter text
|
||||
/// buttons String can be used instead of this object to specify text of the
|
||||
/// button. Optional fields are mutually exclusive.
|
||||
#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone)]
|
||||
|
|
|
@ -13,49 +13,14 @@ pub use chat_photo::*;
|
|||
pub use chosen_inline_result::*;
|
||||
pub use contact::*;
|
||||
pub use document::*;
|
||||
pub use encrypted_credentials::*;
|
||||
pub use encrypted_passport_element::*;
|
||||
pub use file::*;
|
||||
pub use force_reply::*;
|
||||
pub use game::*;
|
||||
pub use game_high_score::*;
|
||||
pub use inline_keyboard_button::*;
|
||||
pub use inline_keyboard_markup::*;
|
||||
pub use input_file::*;
|
||||
pub use input_media::*;
|
||||
pub use input_message_content::*;
|
||||
pub use invoice::*;
|
||||
pub use keyboard_button::*;
|
||||
pub use label_price::*;
|
||||
pub use location::*;
|
||||
pub use login_url::*;
|
||||
pub use mask_position::*;
|
||||
pub use message::*;
|
||||
pub use message_entity::*;
|
||||
pub use order_info::*;
|
||||
pub use parse_mode::*;
|
||||
pub use photo_size::*;
|
||||
pub use poll::*;
|
||||
pub use pre_checkout_query::*;
|
||||
pub use reply_keyboard_markup::*;
|
||||
pub use reply_keyboard_remove::*;
|
||||
pub use reply_markup::*;
|
||||
pub use response_parameters::*;
|
||||
pub use send_invoice::*;
|
||||
pub use shipping_address::*;
|
||||
pub use shipping_option::*;
|
||||
pub use shipping_query::*;
|
||||
pub use sticker::*;
|
||||
pub use sticker_set::*;
|
||||
pub use successful_payment::*;
|
||||
pub use unit_true::*;
|
||||
pub use update::*;
|
||||
pub use user::*;
|
||||
pub use user_profile_photos::*;
|
||||
pub use venue::*;
|
||||
pub use video::*;
|
||||
pub use video_note::*;
|
||||
pub use voice::*;
|
||||
pub use webhook_info::*;
|
||||
|
||||
pub use inline_query::*;
|
||||
pub use inline_query_result::*;
|
||||
pub use inline_query_result_article::*;
|
||||
|
@ -78,11 +43,45 @@ pub use inline_query_result_photo::*;
|
|||
pub use inline_query_result_venue::*;
|
||||
pub use inline_query_result_video::*;
|
||||
pub use inline_query_result_voice::*;
|
||||
|
||||
pub use encrypted_credentials::*;
|
||||
pub use encrypted_passport_element::*;
|
||||
pub use input_file::*;
|
||||
pub use input_media::*;
|
||||
pub use input_message_content::*;
|
||||
pub use invoice::*;
|
||||
pub use keyboard_button::*;
|
||||
pub use label_price::*;
|
||||
pub use location::*;
|
||||
pub use login_url::*;
|
||||
pub use mask_position::*;
|
||||
pub use message::*;
|
||||
pub use message_entity::*;
|
||||
pub use order_info::*;
|
||||
pub use parse_mode::*;
|
||||
pub use passport_data::*;
|
||||
pub use passport_file::*;
|
||||
pub use photo_size::*;
|
||||
pub use poll::*;
|
||||
pub use pre_checkout_query::*;
|
||||
pub use reply_keyboard_markup::*;
|
||||
pub use reply_keyboard_remove::*;
|
||||
pub use reply_markup::*;
|
||||
pub use response_parameters::*;
|
||||
pub use send_invoice::*;
|
||||
pub use shipping_address::*;
|
||||
pub use shipping_option::*;
|
||||
pub use shipping_query::*;
|
||||
pub use sticker::*;
|
||||
pub use sticker_set::*;
|
||||
pub use successful_payment::*;
|
||||
pub use unit_false::*;
|
||||
pub use unit_true::*;
|
||||
pub use update::*;
|
||||
pub use user::*;
|
||||
pub use user_profile_photos::*;
|
||||
pub use venue::*;
|
||||
pub use video::*;
|
||||
pub use video_note::*;
|
||||
pub use voice::*;
|
||||
pub use webhook_info::*;
|
||||
|
||||
mod animation;
|
||||
mod audio;
|
||||
|
@ -130,6 +129,7 @@ mod shipping_query;
|
|||
mod sticker;
|
||||
mod sticker_set;
|
||||
mod successful_payment;
|
||||
mod unit_false;
|
||||
mod unit_true;
|
||||
mod update;
|
||||
mod user;
|
||||
|
|
80
src/types/unit_false.rs
Normal file
80
src/types/unit_false.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct False;
|
||||
|
||||
impl std::convert::TryFrom<bool> for False {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: bool) -> Result<Self, Self::Error> {
|
||||
#[allow(clippy::match_bool)]
|
||||
match value {
|
||||
true => Err(()),
|
||||
false => Ok(False),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for False {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_bool(FalseVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct FalseVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for FalseVisitor {
|
||||
type Value = False;
|
||||
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut std::fmt::Formatter,
|
||||
) -> std::fmt::Result {
|
||||
write!(formatter, "bool, equal to `false`")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
#[allow(clippy::match_bool)]
|
||||
match value {
|
||||
true => Err(E::custom("expected `false`, found `true`")),
|
||||
false => Ok(False),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for False {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::False;
|
||||
|
||||
#[test]
|
||||
fn unit_false_de() {
|
||||
let json = "false";
|
||||
let expected = False;
|
||||
let actual = from_str(json).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_false_se() {
|
||||
let actual = to_string(&False).unwrap();
|
||||
let expected = "false";
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ use serde::{
|
|||
ser::{Serialize, Serializer},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct True;
|
||||
|
||||
impl std::convert::TryFrom<bool> for True {
|
||||
|
|
Loading…
Reference in a new issue