From e1b3ba2227b4dfd13efcdde53cc4211346757950 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 22:45:22 +0600 Subject: [PATCH 01/31] Remove PartialOrd, Ord for True, False --- hw.doc | Bin 0 -> 33280 bytes src/dispatcher/simple/mod.rs | 29 +++++++++++++++++++++++------ src/network/telegram_response.rs | 5 +++-- src/types/mod.rs | 2 +- src/types/unit_false.rs | 16 +++++++++------- src/types/unit_true.rs | 2 +- 6 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 hw.doc diff --git a/hw.doc b/hw.doc new file mode 100644 index 0000000000000000000000000000000000000000..0bdb82bf7864fcf9f8101fb143c11cc9a5ea15fb GIT binary patch literal 33280 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 TlUhDHeKfxf{iCaaL?iwmfn32* literal 0 HcmV?d00001 diff --git a/src/dispatcher/simple/mod.rs b/src/dispatcher/simple/mod.rs index d9301228..2c4bdbb3 100644 --- a/src/dispatcher/simple/mod.rs +++ b/src/dispatcher/simple/mod.rs @@ -227,16 +227,29 @@ where match kind { UpdateKind::Message(mes) => { - self.handle_message(mes, &self.message_handlers).await; + self.handle_message(mes, &self.message_handlers) + .await; } UpdateKind::EditedMessage(mes) => { - self.handle_message(mes, &self.edited_message_handlers).await; + self.handle_message( + mes, + &self.edited_message_handlers, + ) + .await; } UpdateKind::ChannelPost(post) => { - self.handle_message(post, &self.channel_post_handlers).await; + self.handle_message( + post, + &self.channel_post_handlers, + ) + .await; } UpdateKind::EditedChannelPost(post) => { - self.handle_message(post, &self.edited_channel_post_handlers).await; + self.handle_message( + post, + &self.edited_channel_post_handlers, + ) + .await; } UpdateKind::InlineQuery(query) => { call!(self.inline_query_handlers, query) @@ -253,8 +266,12 @@ where .await; } - async fn handle_message(&self, message: Message, handlers: &Handlers<'a, Message, E>) { - let handler = handlers.iter().find_map(|e|{ + async fn handle_message( + &self, + message: Message, + handlers: &Handlers<'a, Message, E>, + ) { + let handler = handlers.iter().find_map(|e| { let (filter, handler) = e; if filter.test(&message) { Some(handler) diff --git a/src/network/telegram_response.rs b/src/network/telegram_response.rs index a3c77b4e..82185c0c 100644 --- a/src/network/telegram_response.rs +++ b/src/network/telegram_response.rs @@ -1,8 +1,9 @@ use reqwest::StatusCode; use crate::{ - requests::ResponseResult, types::ResponseParameters, RequestError, - types::{True, False} + requests::ResponseResult, + types::{False, ResponseParameters, True}, + RequestError, }; #[derive(Deserialize)] diff --git a/src/types/mod.rs b/src/types/mod.rs index eadb5942..4205e755 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -46,8 +46,8 @@ pub use shipping_query::*; pub use sticker::*; pub use sticker_set::*; pub use successful_payment::*; -pub use unit_true::*; pub use unit_false::*; +pub use unit_true::*; pub use update::*; pub use user::*; pub use user_profile_photos::*; diff --git a/src/types/unit_false.rs b/src/types/unit_false.rs index 78299be1..f5039f8e 100644 --- a/src/types/unit_false.rs +++ b/src/types/unit_false.rs @@ -1,7 +1,6 @@ -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde::de::Visitor; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; -#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)] pub struct False; impl std::convert::TryFrom for False { @@ -19,7 +18,7 @@ impl std::convert::TryFrom for False { impl<'de> Deserialize<'de> for False { fn deserialize(deserializer: D) -> Result where - D: Deserializer<'de> + D: Deserializer<'de>, { deserializer.deserialize_bool(FalseVisitor) } @@ -30,7 +29,10 @@ struct FalseVisitor; impl<'de> Visitor<'de> for FalseVisitor { type Value = False; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting( + &self, + formatter: &mut std::fmt::Formatter, + ) -> std::fmt::Result { write!(formatter, "bool, equal to `false`") } @@ -41,7 +43,7 @@ impl<'de> Visitor<'de> for FalseVisitor { #[allow(clippy::match_bool)] match value { true => Err(E::custom("expected `false`, found `true`")), - false => Ok(False) + false => Ok(False), } } } @@ -49,7 +51,7 @@ impl<'de> Visitor<'de> for FalseVisitor { impl Serialize for False { fn serialize(&self, serializer: S) -> Result where - S: Serializer + S: Serializer, { serializer.serialize_bool(false) } diff --git a/src/types/unit_true.rs b/src/types/unit_true.rs index a953dcb2..ed953d46 100644 --- a/src/types/unit_true.rs +++ b/src/types/unit_true.rs @@ -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 for True { From 089ff82b2d35b53c7d440d5d5d4728fe5752c465 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 22:48:05 +0600 Subject: [PATCH 02/31] Rename Dispatcher to FilterDispatcher Related to https://github.com/telebofr/telebofr/issues/59. --- src/dispatcher/simple/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dispatcher/simple/mod.rs b/src/dispatcher/simple/mod.rs index 2c4bdbb3..4bcc77c1 100644 --- a/src/dispatcher/simple/mod.rs +++ b/src/dispatcher/simple/mod.rs @@ -38,7 +38,7 @@ type Handlers<'a, T, E> = /// use std::convert::Infallible; /// use telebofr::{ /// dispatcher::{ -/// simple::{error_policy::ErrorPolicy, Dispatcher}, +/// simple::{error_policy::ErrorPolicy, FilterDispatcher}, /// updater::polling, /// }, /// }; @@ -51,7 +51,7 @@ type Handlers<'a, T, E> = /// /// // create dispatcher which handlers can't fail /// // with error policy that just ignores all errors (that can't ever happen) -/// let mut dp = Dispatcher::::new(ErrorPolicy::Ignore) +/// let mut dp = FilterDispatcher::::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) } @@ -69,7 +69,7 @@ type Handlers<'a, T, E> = /// [Custom error policy]: /// crate::dispatcher::simple::error_policy::ErrorPolicy::Custom [updater]: /// crate::dispatcher::updater -pub struct Dispatcher<'a, E> { +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(), @@ -293,13 +293,13 @@ where } #[async_trait(? Send)] -impl<'a, U, E> crate::dispatcher::Dispatcher<'a, U> for Dispatcher<'a, E> +impl<'a, U, E> crate::dispatcher::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 } } @@ -314,7 +314,7 @@ mod tests { use crate::{ dispatcher::{ - simple::{error_policy::ErrorPolicy, Dispatcher}, + simple::{error_policy::ErrorPolicy, FilterDispatcher}, updater::StreamUpdater, }, types::{ @@ -328,7 +328,7 @@ mod tests { let counter = &AtomicI32::new(0); let counter2 = &AtomicI32::new(0); - let mut dp = Dispatcher::::new(ErrorPolicy::Ignore) + let mut dp = FilterDispatcher::::new(ErrorPolicy::Ignore) .message_handler(true, |_mes: Message| { async move { counter.fetch_add(1, Ordering::SeqCst); From e9f68c67e9509b99932b0949632dadb4baca1693 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 22:50:59 +0600 Subject: [PATCH 03/31] Rename dispatcher.simple to dispatcher.filter --- src/dispatcher/{simple => filter}/error_policy.rs | 0 src/dispatcher/{simple => filter}/mod.rs | 10 +++++----- src/dispatcher/mod.rs | 2 +- src/requests/get_me.rs | 2 +- src/types/keyboard_button.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename src/dispatcher/{simple => filter}/error_policy.rs (100%) rename src/dispatcher/{simple => filter}/mod.rs (97%) diff --git a/src/dispatcher/simple/error_policy.rs b/src/dispatcher/filter/error_policy.rs similarity index 100% rename from src/dispatcher/simple/error_policy.rs rename to src/dispatcher/filter/error_policy.rs diff --git a/src/dispatcher/simple/mod.rs b/src/dispatcher/filter/mod.rs similarity index 97% rename from src/dispatcher/simple/mod.rs rename to src/dispatcher/filter/mod.rs index 4bcc77c1..b6cf7205 100644 --- a/src/dispatcher/simple/mod.rs +++ b/src/dispatcher/filter/mod.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use crate::{ dispatcher::{ - filter::Filter, handler::Handler, simple::error_policy::ErrorPolicy, + filter::Filter, handler::Handler, filter::error_policy::ErrorPolicy, updater::Updater, }, types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind}, @@ -17,7 +17,7 @@ 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 @@ -38,7 +38,7 @@ type Handlers<'a, T, E> = /// use std::convert::Infallible; /// use telebofr::{ /// dispatcher::{ -/// simple::{error_policy::ErrorPolicy, FilterDispatcher}, +/// filter::{error_policy::ErrorPolicy, FilterDispatcher}, /// updater::polling, /// }, /// }; @@ -67,7 +67,7 @@ type Handlers<'a, T, E> = /// /// [`std::fmt::Debug`]: std::fmt::Debug /// [Custom error policy]: -/// crate::dispatcher::simple::error_policy::ErrorPolicy::Custom [updater]: +/// crate::dispatcher::filter::error_policy::ErrorPolicy::Custom [updater]: /// crate::dispatcher::updater pub struct FilterDispatcher<'a, E> { message_handlers: Handlers<'a, Message, E>, @@ -314,7 +314,7 @@ mod tests { use crate::{ dispatcher::{ - simple::{error_policy::ErrorPolicy, FilterDispatcher}, + filter::{error_policy::ErrorPolicy, FilterDispatcher}, updater::StreamUpdater, }, types::{ diff --git a/src/dispatcher/mod.rs b/src/dispatcher/mod.rs index 06f2471d..c13fb8b9 100644 --- a/src/dispatcher/mod.rs +++ b/src/dispatcher/mod.rs @@ -6,7 +6,7 @@ pub use handler::Handler; pub mod filter; pub mod handler; -pub mod simple; +pub mod filter; pub mod updater; #[async_trait(? Send)] diff --git a/src/requests/get_me.rs b/src/requests/get_me.rs index 29d5a546..6efe9543 100644 --- a/src/requests/get_me.rs +++ b/src/requests/get_me.rs @@ -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, diff --git a/src/types/keyboard_button.rs b/src/types/keyboard_button.rs index 41d1b156..01929838 100644 --- a/src/types/keyboard_button.rs +++ b/src/types/keyboard_button.rs @@ -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)] From 2bd8734482058ca0e995f45778d8cf30d1329fb2 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 22:52:48 +0600 Subject: [PATCH 04/31] Rename 'dispatcher' to 'dispatching' --- .../filter/error_policy.rs | 0 src/{dispatcher => dispatching}/filter/mod.rs | 10 ++-- .../filter.rs => dispatching/filters.rs} | 46 +++++++++---------- src/{dispatcher => dispatching}/handler.rs | 0 src/{dispatcher => dispatching}/mod.rs | 4 +- src/{dispatcher => dispatching}/updater.rs | 0 src/lib.rs | 2 +- 7 files changed, 31 insertions(+), 31 deletions(-) rename src/{dispatcher => dispatching}/filter/error_policy.rs (100%) rename src/{dispatcher => dispatching}/filter/mod.rs (98%) rename src/{dispatcher/filter.rs => dispatching/filters.rs} (86%) rename src/{dispatcher => dispatching}/handler.rs (100%) rename src/{dispatcher => dispatching}/mod.rs (87%) rename src/{dispatcher => dispatching}/updater.rs (100%) diff --git a/src/dispatcher/filter/error_policy.rs b/src/dispatching/filter/error_policy.rs similarity index 100% rename from src/dispatcher/filter/error_policy.rs rename to src/dispatching/filter/error_policy.rs diff --git a/src/dispatcher/filter/mod.rs b/src/dispatching/filter/mod.rs similarity index 98% rename from src/dispatcher/filter/mod.rs rename to src/dispatching/filter/mod.rs index b6cf7205..6645b41e 100644 --- a/src/dispatcher/filter/mod.rs +++ b/src/dispatching/filter/mod.rs @@ -23,7 +23,7 @@ type Handlers<'a, T, E> = /// - 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,7 +37,7 @@ type Handlers<'a, T, E> = /// async fn run() { /// use std::convert::Infallible; /// use telebofr::{ -/// dispatcher::{ +/// dispatching::{ /// filter::{error_policy::ErrorPolicy, FilterDispatcher}, /// updater::polling, /// }, @@ -49,7 +49,7 @@ 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 = FilterDispatcher::::new(ErrorPolicy::Ignore) /// // Add 'handler' that will handle all messages sent to the bot @@ -67,8 +67,8 @@ type Handlers<'a, T, E> = /// /// [`std::fmt::Debug`]: std::fmt::Debug /// [Custom error policy]: -/// crate::dispatcher::filter::error_policy::ErrorPolicy::Custom [updater]: -/// crate::dispatcher::updater +/// 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>, diff --git a/src/dispatcher/filter.rs b/src/dispatching/filters.rs similarity index 86% rename from src/dispatcher/filter.rs rename to src/dispatching/filters.rs index bcb59f16..6317a2e3 100644 --- a/src/dispatcher/filter.rs +++ b/src/dispatching/filters.rs @@ -6,7 +6,7 @@ pub trait Filter { } /// ``` -/// use telebofr::dispatcher::filter::Filter; +/// use telebofr::dispatching::filter::Filter; /// /// let closure = |i: &i32| -> bool { *i >= 42 }; /// assert!(closure.test(&42)); @@ -22,7 +22,7 @@ impl bool> Filter for F { } /// ``` -/// use telebofr::dispatcher::filter::Filter; +/// use telebofr::dispatching::filter::Filter; /// /// assert!(true.test(&())); /// assert_eq!(false.test(&()), false); @@ -42,7 +42,7 @@ impl Filter for bool { /// /// ## Examples /// ``` -/// use telebofr::dispatcher::filter::{And, Filter}; +/// use telebofr::dispatching::filter::{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::filter::{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: A, b: B) -> And { And::new(a, b) } @@ -93,7 +93,7 @@ pub fn and(a: A, b: B) -> And { /// /// ## Examples /// ``` -/// use telebofr::dispatcher::filter::{Filter, Or}; +/// use telebofr::dispatching::filter::{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::filter::{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: A, b: B) -> Or { Or::new(a, b) } @@ -141,7 +141,7 @@ pub fn or(a: A, b: B) -> Or { /// /// ## Examples /// ``` -/// use telebofr::dispatcher::filter::{Filter, Not}; +/// use telebofr::dispatching::filter::{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::filter::{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) -> Not { Not::new(a) } @@ -187,7 +187,7 @@ pub fn not(a: A) -> Not { /// /// ## Examples /// ``` -/// use telebofr::{all, dispatcher::filter::Filter}; +/// use telebofr::{all, dispatching::filter::Filter}; /// /// assert!(all![true].test(&())); /// assert!(all![true, true].test(&())); @@ -199,7 +199,7 @@ pub fn not(a: A) -> Not { /// 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 }; @@ -218,7 +218,7 @@ macro_rules! all { /// /// ## Examples /// ``` -/// use telebofr::{any, dispatcher::filter::Filter}; +/// use telebofr::{any, dispatching::filter::Filter}; /// /// assert!(any![true].test(&())); /// assert!(any![true, true].test(&())); @@ -230,7 +230,7 @@ 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 }; @@ -246,7 +246,7 @@ macro_rules! any { /// /// ## Examples /// ``` -/// use telebofr::dispatcher::filter::{f, And, Filter, Or, F}; +/// use telebofr::dispatching::filter::{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); /// Constructor fn for [F] /// -/// [F]: crate::dispatcher::filter::F; +/// [F]: crate::dispatching::filter::F; pub fn f(a: A) -> F { F(a) } @@ -314,7 +314,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatcher::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filter::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i > 0 }; /// let flt = flt.not(); @@ -322,7 +322,7 @@ pub trait FilterExt { /// assert_eq!(flt.test(&1), false); /// ``` /// - /// [`Not::new`]: crate::dispatcher::filter::Not::new + /// [`Not::new`]: crate::dispatching::filter::Not::new fn not(self) -> Not where Self: Sized, @@ -334,7 +334,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatcher::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filter::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i > 0 }; /// let flt = flt.and(|i: &i32| *i < 42); @@ -344,7 +344,7 @@ pub trait FilterExt { /// assert_eq!(flt.test(&43), false); /// ``` /// - /// [`Not::new`]: crate::dispatcher::filter::And::new + /// [`Not::new`]: crate::dispatching::filter::And::new fn and(self, other: B) -> And where Self: Sized, @@ -356,7 +356,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatcher::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filter::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i < 0 }; /// let flt = flt.or(|i: &i32| *i > 42); @@ -366,7 +366,7 @@ pub trait FilterExt { /// assert_eq!(flt.test(&17), false); /// ``` /// - /// [`Not::new`]: crate::dispatcher::filter::Or::new + /// [`Not::new`]: crate::dispatching::filter::Or::new fn or(self, other: B) -> Or where Self: Sized, diff --git a/src/dispatcher/handler.rs b/src/dispatching/handler.rs similarity index 100% rename from src/dispatcher/handler.rs rename to src/dispatching/handler.rs diff --git a/src/dispatcher/mod.rs b/src/dispatching/mod.rs similarity index 87% rename from src/dispatcher/mod.rs rename to src/dispatching/mod.rs index c13fb8b9..6c5cc912 100644 --- a/src/dispatcher/mod.rs +++ b/src/dispatching/mod.rs @@ -4,9 +4,9 @@ use async_trait::async_trait; pub use filter::Filter; pub use handler::Handler; -pub mod filter; +pub mod filters; pub mod handler; -pub mod filter; +pub mod filters; pub mod updater; #[async_trait(? Send)] diff --git a/src/dispatcher/updater.rs b/src/dispatching/updater.rs similarity index 100% rename from src/dispatcher/updater.rs rename to src/dispatching/updater.rs diff --git a/src/lib.rs b/src/lib.rs index 533071c7..838a211a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,6 @@ mod errors; mod network; mod bot; -pub mod dispatcher; +pub mod dispatching; pub mod requests; pub mod types; From 7268c39c8867c69009591685c45e25832cf7e9d1 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 22:53:33 +0600 Subject: [PATCH 05/31] Create dispatching.dispatchers --- src/dispatching/{ => dispatchers}/filter/error_policy.rs | 0 src/dispatching/{ => dispatchers}/filter/mod.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/dispatching/{ => dispatchers}/filter/error_policy.rs (100%) rename src/dispatching/{ => dispatchers}/filter/mod.rs (100%) diff --git a/src/dispatching/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs similarity index 100% rename from src/dispatching/filter/error_policy.rs rename to src/dispatching/dispatchers/filter/error_policy.rs diff --git a/src/dispatching/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs similarity index 100% rename from src/dispatching/filter/mod.rs rename to src/dispatching/dispatchers/filter/mod.rs From ecf2aec3962a14220baf818b9bc839b22c9bd4e0 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 23:06:12 +0600 Subject: [PATCH 06/31] Fix all the errors --- src/dispatching/dispatchers/filter/mod.rs | 16 ++++--- src/dispatching/dispatchers/mod.rs | 3 ++ src/dispatching/filters.rs | 32 +++++++------- src/dispatching/mod.rs | 4 +- src/requests/answer_callback_query.rs | 3 +- src/requests/delete_chat_sticker_set.rs | 3 +- src/requests/get_chat_administrators.rs | 3 +- src/requests/get_chat_member.rs | 3 +- src/requests/mod.rs | 2 +- src/requests/set_chat_sticker_set.rs | 3 +- src/types/mod.rs | 54 +++++++++++------------ 11 files changed, 67 insertions(+), 59 deletions(-) create mode 100644 src/dispatching/dispatchers/mod.rs diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index 6645b41e..6689120e 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -3,9 +3,9 @@ use futures::StreamExt; use async_trait::async_trait; use crate::{ - dispatcher::{ - filter::Filter, handler::Handler, filter::error_policy::ErrorPolicy, - updater::Updater, + dispatching::{ + dispatchers::filter::error_policy::ErrorPolicy, filters::Filter, + handler::Handler, updater::Updater, }, types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind}, }; @@ -38,7 +38,7 @@ type Handlers<'a, T, E> = /// use std::convert::Infallible; /// use telebofr::{ /// dispatching::{ -/// filter::{error_policy::ErrorPolicy, FilterDispatcher}, +/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher}, /// updater::polling, /// }, /// }; @@ -293,7 +293,7 @@ where } #[async_trait(? Send)] -impl<'a, U, E> crate::dispatcher::Dispatcher<'a, U> for FilterDispatcher<'a, E> +impl<'a, U, E> crate::dispatching::Dispatcher<'a, U> for FilterDispatcher<'a, E> where E: std::fmt::Debug, U: Updater + 'a, @@ -313,8 +313,10 @@ mod tests { use futures::Stream; use crate::{ - dispatcher::{ - filter::{error_policy::ErrorPolicy, FilterDispatcher}, + dispatching::{ + dispatchers::filter::{ + error_policy::ErrorPolicy, FilterDispatcher, + }, updater::StreamUpdater, }, types::{ diff --git a/src/dispatching/dispatchers/mod.rs b/src/dispatching/dispatchers/mod.rs new file mode 100644 index 00000000..1ec549e1 --- /dev/null +++ b/src/dispatching/dispatchers/mod.rs @@ -0,0 +1,3 @@ +pub use filter::FilterDispatcher; + +pub mod filter; diff --git a/src/dispatching/filters.rs b/src/dispatching/filters.rs index 6317a2e3..8c513405 100644 --- a/src/dispatching/filters.rs +++ b/src/dispatching/filters.rs @@ -6,7 +6,7 @@ pub trait Filter { } /// ``` -/// use telebofr::dispatching::filter::Filter; +/// use telebofr::dispatching::filters::Filter; /// /// let closure = |i: &i32| -> bool { *i >= 42 }; /// assert!(closure.test(&42)); @@ -22,7 +22,7 @@ impl bool> Filter for F { } /// ``` -/// use telebofr::dispatching::filter::Filter; +/// use telebofr::dispatching::filters::Filter; /// /// assert!(true.test(&())); /// assert_eq!(false.test(&()), false); @@ -42,7 +42,7 @@ impl Filter for bool { /// /// ## Examples /// ``` -/// use telebofr::dispatching::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,7 +73,7 @@ where /// /// ## Examples /// ``` -/// use telebofr::dispatching::filter::{and, Filter}; +/// use telebofr::dispatching::filters::{and, Filter}; /// /// assert!(and(true, true).test(&())); /// assert_eq!(and(true, false).test(&()), false); @@ -93,7 +93,7 @@ pub fn and(a: A, b: B) -> And { /// /// ## Examples /// ``` -/// use telebofr::dispatching::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,7 +124,7 @@ where /// /// ## Examples /// ``` -/// use telebofr::dispatching::filter::{or, Filter}; +/// use telebofr::dispatching::filters::{or, Filter}; /// /// assert!(or(true, false).test(&())); /// assert_eq!(or(false, false).test(&()), false); @@ -141,7 +141,7 @@ pub fn or(a: A, b: B) -> Or { /// /// ## Examples /// ``` -/// use telebofr::dispatching::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,7 +169,7 @@ where /// /// ## Examples /// ``` -/// use telebofr::dispatching::filter::{not, Filter}; +/// use telebofr::dispatching::filters::{not, Filter}; /// /// assert!(not(false).test(&())); /// assert_eq!(not(true).test(&()), false); @@ -187,7 +187,7 @@ pub fn not(a: A) -> Not { /// /// ## Examples /// ``` -/// use telebofr::{all, dispatching::filter::Filter}; +/// use telebofr::{all, dispatching::filters::Filter}; /// /// assert!(all![true].test(&())); /// assert!(all![true, true].test(&())); @@ -204,7 +204,7 @@ pub fn not(a: A) -> Not { 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, dispatching::filter::Filter}; +/// use telebofr::{any, dispatching::filters::Filter}; /// /// assert!(any![true].test(&())); /// assert!(any![true, true].test(&())); @@ -235,7 +235,7 @@ macro_rules! all { 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::dispatching::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 }; @@ -314,7 +314,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatching::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filters::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i > 0 }; /// let flt = flt.not(); @@ -334,7 +334,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatching::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filters::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i > 0 }; /// let flt = flt.and(|i: &i32| *i < 42); @@ -356,7 +356,7 @@ pub trait FilterExt { /// /// ## Examples /// ``` - /// use telebofr::dispatching::filter::{Filter, FilterExt}; + /// use telebofr::dispatching::filters::{Filter, FilterExt}; /// /// let flt = |i: &i32| -> bool { *i < 0 }; /// let flt = flt.or(|i: &i32| *i > 42); diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index 6c5cc912..c239778f 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -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 dispatchers; pub mod filters; pub mod handler; -pub mod filters; pub mod updater; #[async_trait(? Send)] diff --git a/src/requests/answer_callback_query.rs b/src/requests/answer_callback_query.rs index 9d62af18..6bc42024 100644 --- a/src/requests/answer_callback_query.rs +++ b/src/requests/answer_callback_query.rs @@ -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 diff --git a/src/requests/delete_chat_sticker_set.rs b/src/requests/delete_chat_sticker_set.rs index 2d1c849c..63a5260f 100644 --- a/src/requests/delete_chat_sticker_set.rs +++ b/src/requests/delete_chat_sticker_set.rs @@ -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 diff --git a/src/requests/get_chat_administrators.rs b/src/requests/get_chat_administrators.rs index f80c63c9..ba35a99c 100644 --- a/src/requests/get_chat_administrators.rs +++ b/src/requests/get_chat_administrators.rs @@ -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 a list of administrators in a chat. On success, /// returns an Array of ChatMember objects that contains information about all diff --git a/src/requests/get_chat_member.rs b/src/requests/get_chat_member.rs index ce3eae65..3a03fd12 100644 --- a/src/requests/get_chat_member.rs +++ b/src/requests/get_chat_member.rs @@ -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. diff --git a/src/requests/mod.rs b/src/requests/mod.rs index 5349630b..a98d12d9 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -1,11 +1,11 @@ //! 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::*; +use async_trait::async_trait; pub use delete_chat_photo::*; pub use delete_chat_sticker_set::*; pub use edit_message_live_location::*; diff --git a/src/requests/set_chat_sticker_set.rs b/src/requests/set_chat_sticker_set.rs index f27d82d5..a6166cf5 100644 --- a/src/requests/set_chat_sticker_set.rs +++ b/src/requests/set_chat_sticker_set.rs @@ -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 diff --git a/src/types/mod.rs b/src/types/mod.rs index 4205e755..075b1dfc 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -13,12 +13,36 @@ 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 inline_query::*; +pub use inline_query_result::*; +pub use inline_query_result_article::*; +pub use inline_query_result_audio::*; +pub use inline_query_result_cached_audio::*; +pub use inline_query_result_cached_document::*; +pub use inline_query_result_cached_gif::*; +pub use inline_query_result_cached_mpeg4_gif::*; +pub use inline_query_result_cached_photo::*; +pub use inline_query_result_cached_sticker::*; +pub use inline_query_result_cached_video::*; +pub use inline_query_result_cached_voice::*; +pub use inline_query_result_contact::*; +pub use inline_query_result_document::*; +pub use inline_query_result_game::*; +pub use inline_query_result_gif::*; +pub use inline_query_result_location::*; +pub use inline_query_result_mpeg4_gif::*; +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 input_file::*; pub use input_media::*; pub use input_message_content::*; @@ -32,6 +56,8 @@ 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::*; @@ -57,34 +83,6 @@ 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::*; -pub use inline_query_result_audio::*; -pub use inline_query_result_cached_audio::*; -pub use inline_query_result_cached_document::*; -pub use inline_query_result_cached_gif::*; -pub use inline_query_result_cached_mpeg4_gif::*; -pub use inline_query_result_cached_photo::*; -pub use inline_query_result_cached_sticker::*; -pub use inline_query_result_cached_video::*; -pub use inline_query_result_cached_voice::*; -pub use inline_query_result_contact::*; -pub use inline_query_result_document::*; -pub use inline_query_result_game::*; -pub use inline_query_result_gif::*; -pub use inline_query_result_location::*; -pub use inline_query_result_mpeg4_gif::*; -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 passport_data::*; -pub use passport_file::*; - mod animation; mod audio; mod callback_game; From c611fce15b65f77b1d2bcd24f85d991e626324c8 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 20 Oct 2019 23:21:47 +0600 Subject: [PATCH 07/31] Fix --- src/requests/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/requests/mod.rs b/src/requests/mod.rs index a98d12d9..e9bbc265 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -1,11 +1,8 @@ //! API requests. -use serde::de::DeserializeOwned; - pub use answer_callback_query::*; pub use answer_pre_checkout_query::*; pub use answer_shipping_query::*; -use async_trait::async_trait; pub use delete_chat_photo::*; pub use delete_chat_sticker_set::*; pub use edit_message_live_location::*; @@ -94,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 = Result; From 37ab5e049af06b571874ee49beb547307bceca2c Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Tue, 22 Oct 2019 17:02:43 +0600 Subject: [PATCH 08/31] Fmt --- src/dispatching/dispatchers/filter/mod.rs | 41 ++++++++++++----------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index 21038627..b3ed259f 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -5,7 +5,7 @@ use async_trait::async_trait; use crate::{ dispatching::{ dispatchers::filter::error_policy::ErrorPolicy, filters::Filter, - handler::Handler, updater::Updater, + handler::Handler, updater::Updater, Dispatcher, }, types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind}, }; @@ -197,22 +197,15 @@ 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( @@ -222,13 +215,22 @@ where .await; } UpdateKind::InlineQuery(query) => { - self.handle(query, &self.inline_query_handlers).await; + self.handle(query, &self.inline_query_handlers) + .await; } UpdateKind::ChosenInlineResult(result) => { - self.handle(result, &self.chosen_inline_result_handlers).await; + self.handle( + result, + &self.chosen_inline_result_handlers, + ) + .await; } UpdateKind::CallbackQuery(callback) => { - self.handle(callback, &self.callback_query_handlers).await; + self.handle( + callback, + &self.callback_query_handlers, + ) + .await; } } } @@ -238,9 +240,9 @@ where async fn handle(&self, update: T, handlers: &Handlers<'a, T, E>) where - T: std::fmt::Debug + T: std::fmt::Debug, { - let handler = handlers.iter().find_map(|e|{ + let handler = handlers.iter().find_map(|e| { let (filter, handler) = e; if filter.test(&update) { Some(handler) @@ -248,6 +250,7 @@ where None } }); + match handler { Some(handler) => { if let Err(err) = handler.handle(update).await { @@ -262,7 +265,7 @@ where } #[async_trait(? Send)] -impl<'a, U, E> crate::dispatching::Dispatcher<'a, U> for FilterDispatcher<'a, E> +impl<'a, U, E> Dispatcher<'a, U> for FilterDispatcher<'a, E> where E: std::fmt::Debug, U: Updater + 'a, From ec11b9ed3abdb49842dd6e86f11eebe9ce361dda Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 12:56:44 +0300 Subject: [PATCH 09/31] add MessageTextFilter --- .../dispatchers/filter/filters/mod.rs | 3 + .../dispatchers/filter/filters/text.rs | 82 +++++++++++++++++++ src/dispatching/dispatchers/filter/mod.rs | 1 + 3 files changed, 86 insertions(+) create mode 100644 src/dispatching/dispatchers/filter/filters/mod.rs create mode 100644 src/dispatching/dispatchers/filter/filters/text.rs diff --git a/src/dispatching/dispatchers/filter/filters/mod.rs b/src/dispatching/dispatchers/filter/filters/mod.rs new file mode 100644 index 00000000..45eaf476 --- /dev/null +++ b/src/dispatching/dispatchers/filter/filters/mod.rs @@ -0,0 +1,3 @@ +pub use text::*; + +mod text; \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/filters/text.rs b/src/dispatching/dispatchers/filter/filters/text.rs new file mode 100644 index 00000000..2bb76a0e --- /dev/null +++ b/src/dispatching/dispatchers/filter/filters/text.rs @@ -0,0 +1,82 @@ +use crate::dispatching::Filter; +use crate::types::Message; + +pub struct MessageTextFilter { + text: String, +} + +impl Filter for MessageTextFilter { + fn test(&self, value: &Message) -> bool { + match value.text() { + Some(text) => self.text == text, + None => false + } + } +} + +impl MessageTextFilter { + pub fn new(text: String) -> Self { + Self { + text + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn texts_are_equal() { + let filter = MessageTextFilter::new("text".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "text" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn texts_are_not_equal() { + let filter = MessageTextFilter::new("text".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "not equal text" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } +} \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index b3ed259f..816867fc 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -10,6 +10,7 @@ use crate::{ types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind}, }; +pub mod filters; pub mod error_policy; type Handlers<'a, T, E> = From 03b0e41fa0b2a926aa9b6d0548ed25721e39a5a6 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 12:59:58 +0300 Subject: [PATCH 10/31] added test caption --- src/dispatching/dispatchers/filter/filters/text.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dispatching/dispatchers/filter/filters/text.rs b/src/dispatching/dispatchers/filter/filters/text.rs index 2bb76a0e..c1d06c32 100644 --- a/src/dispatching/dispatchers/filter/filters/text.rs +++ b/src/dispatching/dispatchers/filter/filters/text.rs @@ -9,7 +9,12 @@ impl Filter for MessageTextFilter { fn test(&self, value: &Message) -> bool { match value.text() { Some(text) => self.text == text, - None => false + None => { + match value.caption() { + Some(caption) => self.text == caption, + None => false + } + } } } } From 720a34932f5e4b0be5139811280c6a73087189c1 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 18:36:37 +0300 Subject: [PATCH 11/31] divided TextFilter into MessageTextFilter and MessageCaptionFilter --- .../filter/filters/message_caption.rs | 98 +++++++++++++++++++ .../filters/{text.rs => message_text.rs} | 7 +- 2 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/dispatching/dispatchers/filter/filters/message_caption.rs rename src/dispatching/dispatchers/filter/filters/{text.rs => message_text.rs} (91%) diff --git a/src/dispatching/dispatchers/filter/filters/message_caption.rs b/src/dispatching/dispatchers/filter/filters/message_caption.rs new file mode 100644 index 00000000..d1c005ff --- /dev/null +++ b/src/dispatching/dispatchers/filter/filters/message_caption.rs @@ -0,0 +1,98 @@ +use crate::dispatching::Filter; +use crate::types::Message; + +pub struct MessageCaptionFilter { + text: String, +} + +impl Filter for MessageCaptionFilter { + fn test(&self, value: &Message) -> bool { + match value.caption() { + Some(caption) => self.text == caption, + None => false + } + } +} + +impl MessageCaptionFilter { + pub fn new(text: String) -> Self { + Self { + text + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn captions_are_equal() { + let filter = MessageCaptionFilter::new("caption".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "photo": [ + { + "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", + "file_size": 18188, + "width": 320, + "height": 239 + } + ], + "caption": "caption" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn captions_are_not_equal() { + let filter = MessageCaptionFilter::new("text".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "photo": [ + { + "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", + "file_size": 18188, + "width": 320, + "height": 239 + } + ], + "caption": "not equal caption" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } +} \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/filters/text.rs b/src/dispatching/dispatchers/filter/filters/message_text.rs similarity index 91% rename from src/dispatching/dispatchers/filter/filters/text.rs rename to src/dispatching/dispatchers/filter/filters/message_text.rs index c1d06c32..2bb76a0e 100644 --- a/src/dispatching/dispatchers/filter/filters/text.rs +++ b/src/dispatching/dispatchers/filter/filters/message_text.rs @@ -9,12 +9,7 @@ impl Filter for MessageTextFilter { fn test(&self, value: &Message) -> bool { match value.text() { Some(text) => self.text == text, - None => { - match value.caption() { - Some(caption) => self.text == caption, - None => false - } - } + None => false } } } From f67011eb4299b3aefa3b597294b630efe972bed0 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 18:36:53 +0300 Subject: [PATCH 12/31] added CommandFilter --- .../dispatchers/filter/filters/command.rs | 147 ++++++++++++++++++ .../dispatchers/filter/filters/mod.rs | 8 +- 2 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/dispatching/dispatchers/filter/filters/command.rs diff --git a/src/dispatching/dispatchers/filter/filters/command.rs b/src/dispatching/dispatchers/filter/filters/command.rs new file mode 100644 index 00000000..07a81384 --- /dev/null +++ b/src/dispatching/dispatchers/filter/filters/command.rs @@ -0,0 +1,147 @@ +use crate::dispatching::Filter; +use crate::types::Message; +use std::ops::Add; + +struct CommandFilter { + command: String, +} + +impl Filter for CommandFilter { + fn test(&self, value: &Message) -> bool { + match value.text() { + Some(text) => { + match text.split_whitespace().next() { + Some(command) => self.command == command, + None => false + } + } + None => false + } + } +} + +impl CommandFilter { + pub fn new(command: String) -> Self { + Self { + command: '/'.to_string() + command.as_str() + } + } + pub fn with_start_string(command: String, start_string: String) -> Self { + Self { + command: start_string.add(command.as_str()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn commands_are_equal() { + let filter = CommandFilter::new("command".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "/command" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn commands_are_not_equal() { + let filter = CommandFilter::new("command".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "/command_not_equal" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } + + #[test] + fn command_have_args() { + let filter = CommandFilter::new("command".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "/command arg1 arg2" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn message_have_only_whitespace() { + let filter = CommandFilter::new("command".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": " " + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } +} diff --git a/src/dispatching/dispatchers/filter/filters/mod.rs b/src/dispatching/dispatchers/filter/filters/mod.rs index 45eaf476..4c0f0ae8 100644 --- a/src/dispatching/dispatchers/filter/filters/mod.rs +++ b/src/dispatching/dispatchers/filter/filters/mod.rs @@ -1,3 +1,7 @@ -pub use text::*; +pub use command::*; +pub use message_text::*; +pub use message_caption::*; -mod text; \ No newline at end of file +mod command; +mod message_text; +mod message_caption; \ No newline at end of file From e2cd5a8440c0cec5bf437deb46453a385ebc9f54 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 18:46:04 +0300 Subject: [PATCH 13/31] added generics into functions --- .../dispatchers/filter/filters/command.rs | 16 +++++++++++----- .../filter/filters/message_caption.rs | 7 +++++-- .../dispatchers/filter/filters/message_text.rs | 11 +++++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/dispatching/dispatchers/filter/filters/command.rs b/src/dispatching/dispatchers/filter/filters/command.rs index 07a81384..fcb7fda4 100644 --- a/src/dispatching/dispatchers/filter/filters/command.rs +++ b/src/dispatching/dispatchers/filter/filters/command.rs @@ -2,7 +2,7 @@ use crate::dispatching::Filter; use crate::types::Message; use std::ops::Add; -struct CommandFilter { +pub struct CommandFilter { command: String, } @@ -21,14 +21,20 @@ impl Filter for CommandFilter { } impl CommandFilter { - pub fn new(command: String) -> Self { + pub fn new(command: T) -> Self + where + T: Into, + { Self { - command: '/'.to_string() + command.as_str() + command: '/'.to_string() + command.into().as_str() } } - pub fn with_start_string(command: String, start_string: String) -> Self { + pub fn with_start_string(command: T, start_string: T) -> Self + where + T: Into, + { Self { - command: start_string.add(command.as_str()) + command: start_string.into().add(command.into().as_str()) } } } diff --git a/src/dispatching/dispatchers/filter/filters/message_caption.rs b/src/dispatching/dispatchers/filter/filters/message_caption.rs index d1c005ff..f68d0837 100644 --- a/src/dispatching/dispatchers/filter/filters/message_caption.rs +++ b/src/dispatching/dispatchers/filter/filters/message_caption.rs @@ -15,9 +15,12 @@ impl Filter for MessageCaptionFilter { } impl MessageCaptionFilter { - pub fn new(text: String) -> Self { + pub fn new(text: T) -> Self + where + T: Into, + { Self { - text + text: text.into(), } } } diff --git a/src/dispatching/dispatchers/filter/filters/message_text.rs b/src/dispatching/dispatchers/filter/filters/message_text.rs index 2bb76a0e..765c149e 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text.rs +++ b/src/dispatching/dispatchers/filter/filters/message_text.rs @@ -15,9 +15,12 @@ impl Filter for MessageTextFilter { } impl MessageTextFilter { - pub fn new(text: String) -> Self { + pub fn new(text: T) -> Self + where + T: Into + { Self { - text + text: text.into(), } } } @@ -28,7 +31,7 @@ mod tests { #[test] fn texts_are_equal() { - let filter = MessageTextFilter::new("text".to_string()); + let filter = MessageTextFilter::new("text"); let json = r#"{ "message_id": 199785, "from": { @@ -55,7 +58,7 @@ mod tests { #[test] fn texts_are_not_equal() { - let filter = MessageTextFilter::new("text".to_string()); + let filter = MessageTextFilter::new("text"); let json = r#"{ "message_id": 199785, "from": { From 053a946a341d7c4f90b1ea6b7ac4e4f77d1a67b2 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 19:21:48 +0300 Subject: [PATCH 14/31] added docs --- .../dispatchers/filter/filters/message_caption.rs | 13 +++++++++++++ .../dispatchers/filter/filters/message_text.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/dispatching/dispatchers/filter/filters/message_caption.rs b/src/dispatching/dispatchers/filter/filters/message_caption.rs index f68d0837..ccb956f1 100644 --- a/src/dispatching/dispatchers/filter/filters/message_caption.rs +++ b/src/dispatching/dispatchers/filter/filters/message_caption.rs @@ -1,6 +1,19 @@ use crate::dispatching::Filter; use crate::types::Message; +/// Filter which compare caption of media with another text. +/// Returns true if the caption of media is equal to another text, otherwise false. +/// +/// NOTE: filter compares only caption of media, does not compare text of message! +/// +/// If you want to compare text of message use +/// [MessageTextFilter] +/// +/// If you want to compare text and caption use +/// [MessageTextCaptionFilter] +/// +/// [MessageTextFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextFilter +/// [MessageTextCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextCaptionFilter pub struct MessageCaptionFilter { text: String, } diff --git a/src/dispatching/dispatchers/filter/filters/message_text.rs b/src/dispatching/dispatchers/filter/filters/message_text.rs index 765c149e..01da11af 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text.rs +++ b/src/dispatching/dispatchers/filter/filters/message_text.rs @@ -1,6 +1,19 @@ use crate::dispatching::Filter; use crate::types::Message; +/// Filter which compare message text with another text. +/// Returns true if the message text is equal to another text, otherwise false. +/// +/// NOTE: filter compares only text message, does not compare caption of media! +/// +/// If you want to compare caption use +/// [MessageCaptionFilter] +/// +/// If you want to compare text and caption use +/// [MessageTextCaptionFilter] +/// +/// [MessageCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageCaptionFilter +/// [MessageTextCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextCaptionFilter pub struct MessageTextFilter { text: String, } From 9feaf6336202060c4afb01cb9b423269948f952c Mon Sep 17 00:00:00 2001 From: P0lunin Date: Wed, 23 Oct 2019 19:28:01 +0300 Subject: [PATCH 15/31] added MessageTextCaptionFilter --- .../filter/filters/message_text_caption.rs | 173 ++++++++++++++++++ .../dispatchers/filter/filters/mod.rs | 4 +- 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/dispatching/dispatchers/filter/filters/message_text_caption.rs diff --git a/src/dispatching/dispatchers/filter/filters/message_text_caption.rs b/src/dispatching/dispatchers/filter/filters/message_text_caption.rs new file mode 100644 index 00000000..b56aeb28 --- /dev/null +++ b/src/dispatching/dispatchers/filter/filters/message_text_caption.rs @@ -0,0 +1,173 @@ +use crate::dispatching::Filter; +use crate::types::Message; + +/// Filter which compare message text or caption of media with another text. +/// Returns true if the message text or caption of media is equal to another text, otherwise false. +/// +/// NOTE: filter compares text of message or if it is not exists, compares caption of the message! +/// +/// If you want to compare only caption use +/// [MessageCaptionFilter] +/// +/// If you want to compare only text use +/// [MessageTextFilter] +/// +/// [MessageCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageCaptionFilter +/// [MessageTextFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextFilter +pub struct MessageTextCaptionFilter { + text: String, +} + +impl Filter for MessageTextCaptionFilter { + fn test(&self, value: &Message) -> bool { + match value.text() { + Some(text) => self.text == text, + None => { + match value.caption() { + Some(caption) => self.text == caption, + None => false + } + } + } + } +} + +impl MessageTextCaptionFilter { + pub fn new(text: T) -> Self + where + T: Into + { + Self { + text: text.into(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn texts_are_equal() { + let filter = MessageTextCaptionFilter::new("text"); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "text" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn texts_are_not_equal() { + let filter = MessageTextCaptionFilter::new("text"); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "text": "not equal text" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } + + #[test] + fn captions_are_equal() { + let filter = MessageTextCaptionFilter::new("caption".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "photo": [ + { + "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", + "file_size": 18188, + "width": 320, + "height": 239 + } + ], + "caption": "caption" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert!(filter.test(&message)); + } + + #[test] + fn captions_are_not_equal() { + let filter = MessageTextCaptionFilter::new("text".to_string()); + let json = r#"{ + "message_id": 199785, + "from": { + "id": 250918540, + "is_bot": false, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "language_code": "en" + }, + "chat": { + "id": 250918540, + "first_name": "Андрей", + "last_name": "Власов", + "username": "aka_dude", + "type": "private" + }, + "date": 1568289890, + "photo": [ + { + "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", + "file_size": 18188, + "width": 320, + "height": 239 + } + ], + "caption": "not equal caption" + }"#; + let message = serde_json::from_str::(json).unwrap(); + assert_eq!(filter.test(&message), false); + } +} \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/filters/mod.rs b/src/dispatching/dispatchers/filter/filters/mod.rs index 4c0f0ae8..e54376eb 100644 --- a/src/dispatching/dispatchers/filter/filters/mod.rs +++ b/src/dispatching/dispatchers/filter/filters/mod.rs @@ -1,7 +1,9 @@ pub use command::*; pub use message_text::*; pub use message_caption::*; +pub use message_text_caption::*; mod command; mod message_text; -mod message_caption; \ No newline at end of file +mod message_caption; +mod message_text_caption; \ No newline at end of file From 0add325e3188a79b05ded10bdae849d57c1b9371 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Fri, 25 Oct 2019 18:09:56 +0300 Subject: [PATCH 16/31] optimized tests --- .../dispatchers/filter/filters/command.rs | 132 +++++-------- .../filter/filters/message_caption.rs | 101 ++++------ .../filter/filters/message_text.rs | 81 ++++---- .../filter/filters/message_text_caption.rs | 181 ++++++++---------- 4 files changed, 205 insertions(+), 290 deletions(-) diff --git a/src/dispatching/dispatchers/filter/filters/command.rs b/src/dispatching/dispatchers/filter/filters/command.rs index fcb7fda4..0588330c 100644 --- a/src/dispatching/dispatchers/filter/filters/command.rs +++ b/src/dispatching/dispatchers/filter/filters/command.rs @@ -1,6 +1,5 @@ use crate::dispatching::Filter; use crate::types::Message; -use std::ops::Add; pub struct CommandFilter { command: String, @@ -26,15 +25,15 @@ impl CommandFilter { T: Into, { Self { - command: '/'.to_string() + command.into().as_str() + command: '/'.to_string() + &command.into() } } - pub fn with_start_string(command: T, start_string: T) -> Self + pub fn with_prefix(command: T, prefix: T) -> Self where T: Into, { Self { - command: start_string.into().add(command.into().as_str()) + command: prefix.into() + &command.into() } } } @@ -42,112 +41,69 @@ impl CommandFilter { #[cfg(test)] mod tests { use super::*; + use crate::types::{Chat, ChatKind, MessageKind, Sender, User, ForwardKind, MediaKind}; #[test] fn commands_are_equal() { let filter = CommandFilter::new("command".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "/command" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("/command".to_string()); assert!(filter.test(&message)); } #[test] fn commands_are_not_equal() { let filter = CommandFilter::new("command".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "/command_not_equal" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("/not_equal_command".to_string()); assert_eq!(filter.test(&message), false); } #[test] fn command_have_args() { let filter = CommandFilter::new("command".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "/command arg1 arg2" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("/command arg1 arg2".to_string()); assert!(filter.test(&message)); } #[test] fn message_have_only_whitespace() { let filter = CommandFilter::new("command".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": " " - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text(" ".to_string()); assert_eq!(filter.test(&message), false); } + + fn create_message_with_text(text: String) -> Message { + Message { + id: 0, + date: 0, + chat: Chat { + id: 0, + kind: ChatKind::Private { + type_: (), + username: None, + first_name: None, + last_name: None + }, + photo: None + }, + kind: MessageKind::Common { + from: Sender::User(User { + id: 0, + is_bot: false, + first_name: "".to_string(), + last_name: None, + username: None, + language_code: None + }), + forward_kind: ForwardKind::Origin { + reply_to_message: None + }, + edit_date: None, + media_kind: MediaKind::Text { + text, + entities: vec![] + }, + reply_markup: None + } + } + } } diff --git a/src/dispatching/dispatchers/filter/filters/message_caption.rs b/src/dispatching/dispatchers/filter/filters/message_caption.rs index ccb956f1..aed705c8 100644 --- a/src/dispatching/dispatchers/filter/filters/message_caption.rs +++ b/src/dispatching/dispatchers/filter/filters/message_caption.rs @@ -41,74 +41,57 @@ impl MessageCaptionFilter { #[cfg(test)] mod tests { use super::*; + use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; #[test] fn captions_are_equal() { let filter = MessageCaptionFilter::new("caption".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "photo": [ - { - "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", - "file_size": 18188, - "width": 320, - "height": 239 - } - ], - "caption": "caption" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_caption("caption".to_string()); assert!(filter.test(&message)); } #[test] fn captions_are_not_equal() { - let filter = MessageCaptionFilter::new("text".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "photo": [ - { - "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", - "file_size": 18188, - "width": 320, - "height": 239 - } - ], - "caption": "not equal caption" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let filter = MessageCaptionFilter::new("caption".to_string()); + let message = create_message_with_caption("not equal caption".to_string()); assert_eq!(filter.test(&message), false); } + + fn create_message_with_caption(caption: String) -> Message { + Message { + id: 0, + date: 0, + chat: Chat { + id: 0, + kind: ChatKind::Private { + type_: (), + username: None, + first_name: None, + last_name: None + }, + photo: None + }, + kind: MessageKind::Common { + from: Sender::User(User { + id: 0, + is_bot: false, + first_name: "".to_string(), + last_name: None, + username: None, + language_code: None + }), + forward_kind: ForwardKind::Origin { + reply_to_message: None + }, + edit_date: None, + media_kind: MediaKind::Photo { + photo: vec![], + caption: Some(caption), + caption_entities: vec![], + media_group_id: None + }, + reply_markup: None + } + } + } } \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/filters/message_text.rs b/src/dispatching/dispatchers/filter/filters/message_text.rs index 01da11af..3af158ea 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text.rs +++ b/src/dispatching/dispatchers/filter/filters/message_text.rs @@ -41,58 +41,55 @@ impl MessageTextFilter { #[cfg(test)] mod tests { use super::*; + use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; #[test] fn texts_are_equal() { let filter = MessageTextFilter::new("text"); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "text" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("text".to_string()); assert!(filter.test(&message)); } #[test] fn texts_are_not_equal() { let filter = MessageTextFilter::new("text"); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "not equal text" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("not equal text".to_string()); assert_eq!(filter.test(&message), false); } + + fn create_message_with_text(text: String) -> Message { + Message { + id: 0, + date: 0, + chat: Chat { + id: 0, + kind: ChatKind::Private { + type_: (), + username: None, + first_name: None, + last_name: None + }, + photo: None + }, + kind: MessageKind::Common { + from: Sender::User(User { + id: 0, + is_bot: false, + first_name: "".to_string(), + last_name: None, + username: None, + language_code: None + }), + forward_kind: ForwardKind::Origin { + reply_to_message: None + }, + edit_date: None, + media_kind: MediaKind::Text { + text, + entities: vec![] + }, + reply_markup: None + } + } + } } \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/filters/message_text_caption.rs b/src/dispatching/dispatchers/filter/filters/message_text_caption.rs index b56aeb28..193d13e1 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text_caption.rs +++ b/src/dispatching/dispatchers/filter/filters/message_text_caption.rs @@ -46,128 +46,107 @@ impl MessageTextCaptionFilter { #[cfg(test)] mod tests { use super::*; + use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; #[test] fn texts_are_equal() { let filter = MessageTextCaptionFilter::new("text"); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "text" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("text".to_string()); assert!(filter.test(&message)); } #[test] fn texts_are_not_equal() { let filter = MessageTextCaptionFilter::new("text"); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "text": "not equal text" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_text("not equal text".to_string()); assert_eq!(filter.test(&message), false); } + fn create_message_with_text(text: String) -> Message { + Message { + id: 0, + date: 0, + chat: Chat { + id: 0, + kind: ChatKind::Private { + type_: (), + username: None, + first_name: None, + last_name: None + }, + photo: None + }, + kind: MessageKind::Common { + from: Sender::User(User { + id: 0, + is_bot: false, + first_name: "".to_string(), + last_name: None, + username: None, + language_code: None + }), + forward_kind: ForwardKind::Origin { + reply_to_message: None + }, + edit_date: None, + media_kind: MediaKind::Text { + text, + entities: vec![] + }, + reply_markup: None + } + } + } + #[test] fn captions_are_equal() { let filter = MessageTextCaptionFilter::new("caption".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "photo": [ - { - "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", - "file_size": 18188, - "width": 320, - "height": 239 - } - ], - "caption": "caption" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let message = create_message_with_caption("caption".to_string()); assert!(filter.test(&message)); } #[test] fn captions_are_not_equal() { - let filter = MessageTextCaptionFilter::new("text".to_string()); - let json = r#"{ - "message_id": 199785, - "from": { - "id": 250918540, - "is_bot": false, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "language_code": "en" - }, - "chat": { - "id": 250918540, - "first_name": "Андрей", - "last_name": "Власов", - "username": "aka_dude", - "type": "private" - }, - "date": 1568289890, - "photo": [ - { - "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ", - "file_size": 18188, - "width": 320, - "height": 239 - } - ], - "caption": "not equal caption" - }"#; - let message = serde_json::from_str::(json).unwrap(); + let filter = MessageTextCaptionFilter::new("caption".to_string()); + let message = create_message_with_caption("not equal caption".to_string()); assert_eq!(filter.test(&message), false); } + + fn create_message_with_caption(caption: String) -> Message { + Message { + id: 0, + date: 0, + chat: Chat { + id: 0, + kind: ChatKind::Private { + type_: (), + username: None, + first_name: None, + last_name: None + }, + photo: None + }, + kind: MessageKind::Common { + from: Sender::User(User { + id: 0, + is_bot: false, + first_name: "".to_string(), + last_name: None, + username: None, + language_code: None + }), + forward_kind: ForwardKind::Origin { + reply_to_message: None + }, + edit_date: None, + media_kind: MediaKind::Photo { + photo: vec![], + caption: Some(caption), + caption_entities: vec![], + media_group_id: None + }, + reply_markup: None + } + } + } } \ No newline at end of file From 262031cd812ee5048eec9ce2c274b4393f351be6 Mon Sep 17 00:00:00 2001 From: P0lunin Date: Fri, 25 Oct 2019 18:16:10 +0300 Subject: [PATCH 17/31] moved filters from ..\dispatching\dispatchers\filter\ to ..\dispatching\ --- src/dispatching/dispatchers/filter/mod.rs | 1 - .../filter => }/filters/command.rs | 0 .../{filters.rs => filters/main.rs} | 32 +++++++++---------- .../filter => }/filters/message_caption.rs | 4 +-- .../filter => }/filters/message_text.rs | 4 +-- .../filters/message_text_caption.rs | 4 +-- .../{dispatchers/filter => }/filters/mod.rs | 4 +++ 7 files changed, 26 insertions(+), 23 deletions(-) rename src/dispatching/{dispatchers/filter => }/filters/command.rs (100%) rename src/dispatching/{filters.rs => filters/main.rs} (97%) rename src/dispatching/{dispatchers/filter => }/filters/message_caption.rs (92%) rename src/dispatching/{dispatchers/filter => }/filters/message_text.rs (92%) rename src/dispatching/{dispatchers/filter => }/filters/message_text_caption.rs (95%) rename src/dispatching/{dispatchers/filter => }/filters/mod.rs (86%) diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index 816867fc..b3ed259f 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -10,7 +10,6 @@ use crate::{ types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind}, }; -pub mod filters; pub mod error_policy; type Handlers<'a, T, E> = diff --git a/src/dispatching/dispatchers/filter/filters/command.rs b/src/dispatching/filters/command.rs similarity index 100% rename from src/dispatching/dispatchers/filter/filters/command.rs rename to src/dispatching/filters/command.rs diff --git a/src/dispatching/filters.rs b/src/dispatching/filters/main.rs similarity index 97% rename from src/dispatching/filters.rs rename to src/dispatching/filters/main.rs index 8c513405..6b3f3c3d 100644 --- a/src/dispatching/filters.rs +++ b/src/dispatching/filters/main.rs @@ -60,9 +60,9 @@ impl And { } impl Filter for And -where - A: Filter, - B: Filter, + where + A: Filter, + B: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) && self.1.test(value) @@ -111,9 +111,9 @@ impl Or { } impl Filter for Or -where - A: Filter, - B: Filter, + where + A: Filter, + B: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) || self.1.test(value) @@ -157,8 +157,8 @@ impl Not { } impl Filter for Not -where - A: Filter, + where + A: Filter, { fn test(&self, value: &T) -> bool { !self.0.test(value) @@ -283,8 +283,8 @@ pub fn f(a: A) -> F { } impl Filter for F -where - A: Filter, + where + A: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) @@ -324,8 +324,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::Not::new fn not(self) -> Not - where - Self: Sized, + where + Self: Sized, { Not::new(self) } @@ -346,8 +346,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::And::new fn and(self, other: B) -> And - where - Self: Sized, + where + Self: Sized, { And::new(self, other) } @@ -368,8 +368,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::Or::new fn or(self, other: B) -> Or - where - Self: Sized, + where + Self: Sized, { Or::new(self, other) } diff --git a/src/dispatching/dispatchers/filter/filters/message_caption.rs b/src/dispatching/filters/message_caption.rs similarity index 92% rename from src/dispatching/dispatchers/filter/filters/message_caption.rs rename to src/dispatching/filters/message_caption.rs index aed705c8..a940d49f 100644 --- a/src/dispatching/dispatchers/filter/filters/message_caption.rs +++ b/src/dispatching/filters/message_caption.rs @@ -12,8 +12,8 @@ use crate::types::Message; /// If you want to compare text and caption use /// [MessageTextCaptionFilter] /// -/// [MessageTextFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextFilter -/// [MessageTextCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextCaptionFilter +/// [MessageTextFilter]: telebofr::dispatching::filters::MessageTextFilter +/// [MessageTextCaptionFilter]: telebofr::dispatching::filters::MessageTextCaptionFilter pub struct MessageCaptionFilter { text: String, } diff --git a/src/dispatching/dispatchers/filter/filters/message_text.rs b/src/dispatching/filters/message_text.rs similarity index 92% rename from src/dispatching/dispatchers/filter/filters/message_text.rs rename to src/dispatching/filters/message_text.rs index 3af158ea..e5079823 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text.rs +++ b/src/dispatching/filters/message_text.rs @@ -12,8 +12,8 @@ use crate::types::Message; /// If you want to compare text and caption use /// [MessageTextCaptionFilter] /// -/// [MessageCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageCaptionFilter -/// [MessageTextCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextCaptionFilter +/// [MessageCaptionFilter]: telebofr::dispatching::filters::MessageCaptionFilter +/// [MessageTextCaptionFilter]: telebofr::dispatching::filters::MessageTextCaptionFilter pub struct MessageTextFilter { text: String, } diff --git a/src/dispatching/dispatchers/filter/filters/message_text_caption.rs b/src/dispatching/filters/message_text_caption.rs similarity index 95% rename from src/dispatching/dispatchers/filter/filters/message_text_caption.rs rename to src/dispatching/filters/message_text_caption.rs index 193d13e1..bc144c27 100644 --- a/src/dispatching/dispatchers/filter/filters/message_text_caption.rs +++ b/src/dispatching/filters/message_text_caption.rs @@ -12,8 +12,8 @@ use crate::types::Message; /// If you want to compare only text use /// [MessageTextFilter] /// -/// [MessageCaptionFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageCaptionFilter -/// [MessageTextFilter]: telebofr::dispatching::dispatchers::filter::filters::MessageTextFilter +/// [MessageCaptionFilter]: telebofr::dispatching::filters::MessageCaptionFilter +/// [MessageTextFilter]: telebofr::filter::filters::MessageTextFilter pub struct MessageTextCaptionFilter { text: String, } diff --git a/src/dispatching/dispatchers/filter/filters/mod.rs b/src/dispatching/filters/mod.rs similarity index 86% rename from src/dispatching/dispatchers/filter/filters/mod.rs rename to src/dispatching/filters/mod.rs index e54376eb..6d4b47ef 100644 --- a/src/dispatching/dispatchers/filter/filters/mod.rs +++ b/src/dispatching/filters/mod.rs @@ -1,8 +1,12 @@ +pub use main::*; + pub use command::*; pub use message_text::*; pub use message_caption::*; pub use message_text_caption::*; +mod main; + mod command; mod message_text; mod message_caption; From 04dd861f5161cadb18179b6272fecaa72bb96cd9 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Tue, 29 Oct 2019 01:28:38 +0600 Subject: [PATCH 18/31] Fmt --- src/bot/download.rs | 6 +- src/dispatching/filters/command.rs | 43 +++++++------ src/dispatching/filters/main.rs | 32 +++++----- src/dispatching/filters/message_caption.rs | 41 ++++++------ src/dispatching/filters/message_text.rs | 34 +++++----- .../filters/message_text_caption.rs | 64 +++++++++---------- src/dispatching/filters/mod.rs | 6 +- 7 files changed, 115 insertions(+), 111 deletions(-) diff --git a/src/bot/download.rs b/src/bot/download.rs index b768f43d..abb2da78 100644 --- a/src/bot/download.rs +++ b/src/bot/download.rs @@ -8,7 +8,7 @@ use crate::network::download_file_stream; use crate::{bot::Bot, network::download_file, DownloadError}; impl Bot { - /// Download file from telegram into `destination`. + /// Download a file from Telegram into `destination`. /// `path` can be obtained from [`get_file`] method. /// /// For downloading as Stream of Chunks see [`download_file_stream`]. @@ -43,9 +43,9 @@ impl Bot { download_file(&self.client, &self.token, path, destination).await } - /// Download file from telegram. + /// Download a file from Telegram. /// - /// `path` can be obtained from [`get_file`] method. + /// `path` can be obtained from the [`get_file`] method. /// /// For downloading into [`AsyncWrite`] (e.g. [`tokio::fs::File`]) /// see [`download_file`]. diff --git a/src/dispatching/filters/command.rs b/src/dispatching/filters/command.rs index 0588330c..b807050a 100644 --- a/src/dispatching/filters/command.rs +++ b/src/dispatching/filters/command.rs @@ -1,5 +1,4 @@ -use crate::dispatching::Filter; -use crate::types::Message; +use crate::{dispatching::Filter, types::Message}; pub struct CommandFilter { command: String, @@ -8,13 +7,11 @@ pub struct CommandFilter { impl Filter for CommandFilter { fn test(&self, value: &Message) -> bool { match value.text() { - Some(text) => { - match text.split_whitespace().next() { - Some(command) => self.command == command, - None => false - } - } - None => false + Some(text) => match text.split_whitespace().next() { + Some(command) => self.command == command, + None => false, + }, + None => false, } } } @@ -25,7 +22,7 @@ impl CommandFilter { T: Into, { Self { - command: '/'.to_string() + &command.into() + command: '/'.to_string() + &command.into(), } } pub fn with_prefix(command: T, prefix: T) -> Self @@ -33,7 +30,7 @@ impl CommandFilter { T: Into, { Self { - command: prefix.into() + &command.into() + command: prefix.into() + &command.into(), } } } @@ -41,7 +38,9 @@ impl CommandFilter { #[cfg(test)] mod tests { use super::*; - use crate::types::{Chat, ChatKind, MessageKind, Sender, User, ForwardKind, MediaKind}; + use crate::types::{ + Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User, + }; #[test] fn commands_are_equal() { @@ -53,14 +52,16 @@ mod tests { #[test] fn commands_are_not_equal() { let filter = CommandFilter::new("command".to_string()); - let message = create_message_with_text("/not_equal_command".to_string()); + let message = + create_message_with_text("/not_equal_command".to_string()); assert_eq!(filter.test(&message), false); } #[test] fn command_have_args() { let filter = CommandFilter::new("command".to_string()); - let message = create_message_with_text("/command arg1 arg2".to_string()); + let message = + create_message_with_text("/command arg1 arg2".to_string()); assert!(filter.test(&message)); } @@ -81,9 +82,9 @@ mod tests { type_: (), username: None, first_name: None, - last_name: None + last_name: None, }, - photo: None + photo: None, }, kind: MessageKind::Common { from: Sender::User(User { @@ -92,18 +93,18 @@ mod tests { first_name: "".to_string(), last_name: None, username: None, - language_code: None + language_code: None, }), forward_kind: ForwardKind::Origin { - reply_to_message: None + reply_to_message: None, }, edit_date: None, media_kind: MediaKind::Text { text, - entities: vec![] + entities: vec![], }, - reply_markup: None - } + reply_markup: None, + }, } } } diff --git a/src/dispatching/filters/main.rs b/src/dispatching/filters/main.rs index 6b3f3c3d..8c513405 100644 --- a/src/dispatching/filters/main.rs +++ b/src/dispatching/filters/main.rs @@ -60,9 +60,9 @@ impl And { } impl Filter for And - where - A: Filter, - B: Filter, +where + A: Filter, + B: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) && self.1.test(value) @@ -111,9 +111,9 @@ impl Or { } impl Filter for Or - where - A: Filter, - B: Filter, +where + A: Filter, + B: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) || self.1.test(value) @@ -157,8 +157,8 @@ impl Not { } impl Filter for Not - where - A: Filter, +where + A: Filter, { fn test(&self, value: &T) -> bool { !self.0.test(value) @@ -283,8 +283,8 @@ pub fn f(a: A) -> F { } impl Filter for F - where - A: Filter, +where + A: Filter, { fn test(&self, value: &T) -> bool { self.0.test(value) @@ -324,8 +324,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::Not::new fn not(self) -> Not - where - Self: Sized, + where + Self: Sized, { Not::new(self) } @@ -346,8 +346,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::And::new fn and(self, other: B) -> And - where - Self: Sized, + where + Self: Sized, { And::new(self, other) } @@ -368,8 +368,8 @@ pub trait FilterExt { /// /// [`Not::new`]: crate::dispatching::filter::Or::new fn or(self, other: B) -> Or - where - Self: Sized, + where + Self: Sized, { Or::new(self, other) } diff --git a/src/dispatching/filters/message_caption.rs b/src/dispatching/filters/message_caption.rs index a940d49f..0539390e 100644 --- a/src/dispatching/filters/message_caption.rs +++ b/src/dispatching/filters/message_caption.rs @@ -1,10 +1,11 @@ -use crate::dispatching::Filter; -use crate::types::Message; +use crate::{dispatching::Filter, types::Message}; /// Filter which compare caption of media with another text. -/// Returns true if the caption of media is equal to another text, otherwise false. +/// Returns true if the caption of media is equal to another text, otherwise +/// false. /// -/// NOTE: filter compares only caption of media, does not compare text of message! +/// NOTE: filter compares only caption of media, does not compare text of +/// message! /// /// If you want to compare text of message use /// [MessageTextFilter] @@ -13,7 +14,8 @@ use crate::types::Message; /// [MessageTextCaptionFilter] /// /// [MessageTextFilter]: telebofr::dispatching::filters::MessageTextFilter -/// [MessageTextCaptionFilter]: telebofr::dispatching::filters::MessageTextCaptionFilter +/// [MessageTextCaptionFilter]: +/// telebofr::dispatching::filters::MessageTextCaptionFilter pub struct MessageCaptionFilter { text: String, } @@ -22,7 +24,7 @@ impl Filter for MessageCaptionFilter { fn test(&self, value: &Message) -> bool { match value.caption() { Some(caption) => self.text == caption, - None => false + None => false, } } } @@ -32,16 +34,16 @@ impl MessageCaptionFilter { where T: Into, { - Self { - text: text.into(), - } + Self { text: text.into() } } } #[cfg(test)] mod tests { use super::*; - use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; + use crate::types::{ + Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User, + }; #[test] fn captions_are_equal() { @@ -53,7 +55,8 @@ mod tests { #[test] fn captions_are_not_equal() { let filter = MessageCaptionFilter::new("caption".to_string()); - let message = create_message_with_caption("not equal caption".to_string()); + let message = + create_message_with_caption("not equal caption".to_string()); assert_eq!(filter.test(&message), false); } @@ -67,9 +70,9 @@ mod tests { type_: (), username: None, first_name: None, - last_name: None + last_name: None, }, - photo: None + photo: None, }, kind: MessageKind::Common { from: Sender::User(User { @@ -78,20 +81,20 @@ mod tests { first_name: "".to_string(), last_name: None, username: None, - language_code: None + language_code: None, }), forward_kind: ForwardKind::Origin { - reply_to_message: None + reply_to_message: None, }, edit_date: None, media_kind: MediaKind::Photo { photo: vec![], caption: Some(caption), caption_entities: vec![], - media_group_id: None + media_group_id: None, }, - reply_markup: None - } + reply_markup: None, + }, } } -} \ No newline at end of file +} diff --git a/src/dispatching/filters/message_text.rs b/src/dispatching/filters/message_text.rs index e5079823..28db8206 100644 --- a/src/dispatching/filters/message_text.rs +++ b/src/dispatching/filters/message_text.rs @@ -1,5 +1,4 @@ -use crate::dispatching::Filter; -use crate::types::Message; +use crate::{dispatching::Filter, types::Message}; /// Filter which compare message text with another text. /// Returns true if the message text is equal to another text, otherwise false. @@ -13,7 +12,8 @@ use crate::types::Message; /// [MessageTextCaptionFilter] /// /// [MessageCaptionFilter]: telebofr::dispatching::filters::MessageCaptionFilter -/// [MessageTextCaptionFilter]: telebofr::dispatching::filters::MessageTextCaptionFilter +/// [MessageTextCaptionFilter]: +/// telebofr::dispatching::filters::MessageTextCaptionFilter pub struct MessageTextFilter { text: String, } @@ -22,7 +22,7 @@ impl Filter for MessageTextFilter { fn test(&self, value: &Message) -> bool { match value.text() { Some(text) => self.text == text, - None => false + None => false, } } } @@ -30,18 +30,18 @@ impl Filter for MessageTextFilter { impl MessageTextFilter { pub fn new(text: T) -> Self where - T: Into + T: Into, { - Self { - text: text.into(), - } + Self { text: text.into() } } } #[cfg(test)] mod tests { use super::*; - use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; + use crate::types::{ + Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User, + }; #[test] fn texts_are_equal() { @@ -67,9 +67,9 @@ mod tests { type_: (), username: None, first_name: None, - last_name: None + last_name: None, }, - photo: None + photo: None, }, kind: MessageKind::Common { from: Sender::User(User { @@ -78,18 +78,18 @@ mod tests { first_name: "".to_string(), last_name: None, username: None, - language_code: None + language_code: None, }), forward_kind: ForwardKind::Origin { - reply_to_message: None + reply_to_message: None, }, edit_date: None, media_kind: MediaKind::Text { text, - entities: vec![] + entities: vec![], }, - reply_markup: None - } + reply_markup: None, + }, } } -} \ No newline at end of file +} diff --git a/src/dispatching/filters/message_text_caption.rs b/src/dispatching/filters/message_text_caption.rs index bc144c27..5ee0df1f 100644 --- a/src/dispatching/filters/message_text_caption.rs +++ b/src/dispatching/filters/message_text_caption.rs @@ -1,10 +1,11 @@ -use crate::dispatching::Filter; -use crate::types::Message; +use crate::{dispatching::Filter, types::Message}; /// Filter which compare message text or caption of media with another text. -/// Returns true if the message text or caption of media is equal to another text, otherwise false. +/// Returns true if the message text or caption of media is equal to another +/// text, otherwise false. /// -/// NOTE: filter compares text of message or if it is not exists, compares caption of the message! +/// NOTE: filter compares text of message or if it is not exists, compares +/// caption of the message! /// /// If you want to compare only caption use /// [MessageCaptionFilter] @@ -22,31 +23,29 @@ impl Filter for MessageTextCaptionFilter { fn test(&self, value: &Message) -> bool { match value.text() { Some(text) => self.text == text, - None => { - match value.caption() { - Some(caption) => self.text == caption, - None => false - } - } + None => match value.caption() { + Some(caption) => self.text == caption, + None => false, + }, } } } impl MessageTextCaptionFilter { pub fn new(text: T) -> Self - where - T: Into + where + T: Into, { - Self { - text: text.into(), - } + Self { text: text.into() } } } #[cfg(test)] mod tests { use super::*; - use crate::types::{Chat, Sender, ChatKind, MessageKind, ForwardKind, User, MediaKind}; + use crate::types::{ + Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User, + }; #[test] fn texts_are_equal() { @@ -72,9 +71,9 @@ mod tests { type_: (), username: None, first_name: None, - last_name: None + last_name: None, }, - photo: None + photo: None, }, kind: MessageKind::Common { from: Sender::User(User { @@ -83,18 +82,18 @@ mod tests { first_name: "".to_string(), last_name: None, username: None, - language_code: None + language_code: None, }), forward_kind: ForwardKind::Origin { - reply_to_message: None + reply_to_message: None, }, edit_date: None, media_kind: MediaKind::Text { text, - entities: vec![] + entities: vec![], }, - reply_markup: None - } + reply_markup: None, + }, } } @@ -108,7 +107,8 @@ mod tests { #[test] fn captions_are_not_equal() { let filter = MessageTextCaptionFilter::new("caption".to_string()); - let message = create_message_with_caption("not equal caption".to_string()); + let message = + create_message_with_caption("not equal caption".to_string()); assert_eq!(filter.test(&message), false); } @@ -122,9 +122,9 @@ mod tests { type_: (), username: None, first_name: None, - last_name: None + last_name: None, }, - photo: None + photo: None, }, kind: MessageKind::Common { from: Sender::User(User { @@ -133,20 +133,20 @@ mod tests { first_name: "".to_string(), last_name: None, username: None, - language_code: None + language_code: None, }), forward_kind: ForwardKind::Origin { - reply_to_message: None + reply_to_message: None, }, edit_date: None, media_kind: MediaKind::Photo { photo: vec![], caption: Some(caption), caption_entities: vec![], - media_group_id: None + media_group_id: None, }, - reply_markup: None - } + reply_markup: None, + }, } } -} \ No newline at end of file +} diff --git a/src/dispatching/filters/mod.rs b/src/dispatching/filters/mod.rs index 6d4b47ef..b3f9237f 100644 --- a/src/dispatching/filters/mod.rs +++ b/src/dispatching/filters/mod.rs @@ -1,13 +1,13 @@ pub use main::*; pub use command::*; -pub use message_text::*; pub use message_caption::*; +pub use message_text::*; pub use message_text_caption::*; mod main; mod command; -mod message_text; mod message_caption; -mod message_text_caption; \ No newline at end of file +mod message_text; +mod message_text_caption; From a2eda602c0419302dd80dbbdaa76c818c94d8f49 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 31 Oct 2019 15:42:18 +0600 Subject: [PATCH 19/31] A erroneous implementation of trait ErrorPolicy --- .../dispatchers/filter/error_policy.rs | 42 ++++++++----------- src/dispatching/dispatchers/filter/mod.rs | 22 ++++++---- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index 8e922c63..0f4af1d0 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -1,32 +1,26 @@ -use std::{fmt::Debug, future::Future, pin::Pin}; +use std::future::Future; -// TODO: shouldn't it be trait? -pub enum ErrorPolicy<'a, E> { - Ignore, - Log, - Custom(Box Pin + 'a>>>), +use async_trait::async_trait; + +#[async_trait] +pub trait ErrorPolicy { + type Error; + + async fn handle_error(&mut self, error: Self::Error); } -impl<'a, E> ErrorPolicy<'a, E> +pub struct FnErrorPolicy(pub F); + +#[async_trait] +impl ErrorPolicy for FnErrorPolicy where - E: Debug, + F: FnMut(E) -> Fut + Send, + Fut: Future, + E: Send, { - pub async fn handle_error(&self, error: E) { - match self { - Self::Ignore => {} - Self::Log => { - // TODO: better message - log::error!("Error in handler: {:?}", error) - } - Self::Custom(func) => func(error).await, - } - } + type Error = E; - pub fn custom(f: F) -> Self - where - F: Fn(E) -> Fut + 'static, - Fut: Future + 'a, - { - Self::Custom(Box::new(move |e| Box::pin(f(e)))) + async fn handle_error(&mut self, error: E) { + self.0(error); } } diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index b3ed259f..fce18a5d 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -69,7 +69,7 @@ type Handlers<'a, T, E> = /// [Custom error policy]: /// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]: /// crate::dispatching::updater -pub struct FilterDispatcher<'a, E> { +pub struct FilterDispatcher<'a, E, Ep> { message_handlers: Handlers<'a, Message, E>, edited_message_handlers: Handlers<'a, Message, E>, channel_post_handlers: Handlers<'a, Message, E>, @@ -77,14 +77,15 @@ pub struct FilterDispatcher<'a, E> { inline_query_handlers: Handlers<'a, (), E>, chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>, callback_query_handlers: Handlers<'a, CallbackQuery, E>, - error_policy: ErrorPolicy<'a, E>, + error_policy: Ep, } -impl<'a, E> FilterDispatcher<'a, E> +impl<'a, E, Ep> FilterDispatcher<'a, E, Ep> where + Ep: ErrorPolicy, E: std::fmt::Debug, // TODO: Is this really necessary? { - pub fn new(error_policy: ErrorPolicy<'a, E>) -> Self { + pub fn new(error_policy: Ep) -> Self { FilterDispatcher { message_handlers: Vec::new(), edited_message_handlers: Vec::new(), @@ -183,7 +184,6 @@ where updates .for_each(|res| { async { - let res = res; let Update { kind, id } = match res { Ok(upd) => upd, _ => return, // TODO: proper error handling @@ -238,7 +238,7 @@ where .await; } - async fn handle(&self, update: T, handlers: &Handlers<'a, T, E>) + async fn handle(&mut self, update: T, handlers: &Handlers<'a, T, E>) where T: std::fmt::Debug, { @@ -265,10 +265,11 @@ where } #[async_trait(? Send)] -impl<'a, U, E> Dispatcher<'a, U> for FilterDispatcher<'a, E> +impl<'a, U, E, Ep> Dispatcher<'a, U> for FilterDispatcher<'a, E, Ep> where E: std::fmt::Debug, U: Updater + 'a, + Ep: ErrorPolicy, { async fn dispatch(&'a mut self, updater: U) { FilterDispatcher::dispatch(self, updater).await @@ -287,7 +288,7 @@ mod tests { use crate::{ dispatching::{ dispatchers::filter::{ - error_policy::ErrorPolicy, FilterDispatcher, + error_policy::FnErrorPolicy, FilterDispatcher, }, updater::StreamUpdater, }, @@ -302,7 +303,10 @@ mod tests { let counter = &AtomicI32::new(0); let counter2 = &AtomicI32::new(0); - let mut dp = FilterDispatcher::::new(ErrorPolicy::Ignore) + let mut dp = + FilterDispatcher::::new(FnErrorPolicy(|_| { + async { () } + })) .message_handler(true, |_mes: Message| { async move { counter.fetch_add(1, Ordering::SeqCst); From 65e003120d267b7dbdde0e6efb4260050d542aed Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 31 Oct 2019 15:50:36 +0600 Subject: [PATCH 20/31] Add comments (error_policy.rs) --- src/dispatching/dispatchers/filter/error_policy.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index 0f4af1d0..d80e2389 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -2,6 +2,7 @@ use std::future::Future; use async_trait::async_trait; +/// Implementors of this trait are treated as error-handlers. #[async_trait] pub trait ErrorPolicy { type Error; @@ -9,6 +10,8 @@ pub trait ErrorPolicy { async fn handle_error(&mut self, error: Self::Error); } +/// A convenient structure with an error-handling closure. Implements +/// `ErrorPolicy`. pub struct FnErrorPolicy(pub F); #[async_trait] From 1d9c42c309097a857a39afca2ff2fb43c310859a Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 1 Nov 2019 21:51:09 +0600 Subject: [PATCH 21/31] Fix --- src/dispatching/dispatchers/filter/error_policy.rs | 10 +++------- src/dispatching/dispatchers/filter/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index d80e2389..d3760c41 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -4,10 +4,8 @@ use async_trait::async_trait; /// Implementors of this trait are treated as error-handlers. #[async_trait] -pub trait ErrorPolicy { - type Error; - - async fn handle_error(&mut self, error: Self::Error); +pub trait ErrorPolicy { + async fn handle_error(&mut self, error: E); } /// A convenient structure with an error-handling closure. Implements @@ -15,14 +13,12 @@ pub trait ErrorPolicy { pub struct FnErrorPolicy(pub F); #[async_trait] -impl ErrorPolicy for FnErrorPolicy +impl ErrorPolicy for FnErrorPolicy where F: FnMut(E) -> Fut + Send, Fut: Future, E: Send, { - type Error = E; - async fn handle_error(&mut self, error: E) { self.0(error); } diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index fce18a5d..c4203747 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -82,7 +82,7 @@ pub struct FilterDispatcher<'a, E, Ep> { impl<'a, E, Ep> FilterDispatcher<'a, E, Ep> where - Ep: ErrorPolicy, + Ep: ErrorPolicy, E: std::fmt::Debug, // TODO: Is this really necessary? { pub fn new(error_policy: Ep) -> Self { @@ -269,7 +269,7 @@ impl<'a, U, E, Ep> Dispatcher<'a, U> for FilterDispatcher<'a, E, Ep> where E: std::fmt::Debug, U: Updater + 'a, - Ep: ErrorPolicy, + Ep: ErrorPolicy, { async fn dispatch(&'a mut self, updater: U) { FilterDispatcher::dispatch(self, updater).await From a537830472f37dbcc8320a895d03f13c051d6a4d Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 1 Nov 2019 22:09:27 +0600 Subject: [PATCH 22/31] An another try to implement ErrorPolicy for FnMut --- src/dispatching/dispatchers/filter/error_policy.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index d3760c41..db52e05a 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -8,18 +8,14 @@ pub trait ErrorPolicy { async fn handle_error(&mut self, error: E); } -/// A convenient structure with an error-handling closure. Implements -/// `ErrorPolicy`. -pub struct FnErrorPolicy(pub F); - #[async_trait] -impl ErrorPolicy for FnErrorPolicy +impl ErrorPolicy for F where F: FnMut(E) -> Fut + Send, - Fut: Future, + Fut: Future + Send, E: Send, { async fn handle_error(&mut self, error: E) { - self.0(error); + self(error).await; } } From 3f2d049c22e81916aeede7ba779d30d015f5933f Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 2 Nov 2019 15:55:54 +0300 Subject: [PATCH 23/31] Fix `ErrorPolicy` by implementing trait on all `Fn() -> Fut` by-hands (and some related small fixes) --- .../dispatchers/filter/error_policy.rs | 23 +++++++++++------ src/dispatching/dispatchers/filter/mod.rs | 25 ++++++++----------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index db52e05a..b602bcf0 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -1,21 +1,28 @@ use std::future::Future; use async_trait::async_trait; +use std::pin::Pin; /// Implementors of this trait are treated as error-handlers. #[async_trait] pub trait ErrorPolicy { - async fn handle_error(&mut self, error: E); + async fn handle_error(&self, error: E) + where + E: 'async_trait; } -#[async_trait] impl ErrorPolicy for F -where - F: FnMut(E) -> Fut + Send, - Fut: Future + Send, - E: Send, + where + F: Fn(E) -> Fut + Sync, + Fut: Future + Send, + E: Send, { - async fn handle_error(&mut self, error: E) { - self(error).await; + fn handle_error<'s, 'async_trait>(&'s self, error: E) -> Pin + Send + 'async_trait>> + where + 's: 'async_trait, + Self: 'async_trait, + E: 'async_trait + { + Box::pin(async move { self(error).await }) } } diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index c4203747..5d1b0a89 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -32,11 +32,12 @@ type Handlers<'a, T, E> = /// /// Simplest example: /// ```no_run -/// # use telebofr::Bot; -/// use telebofr::types::Message; -/// async fn run() { +/// # async fn run() { /// use std::convert::Infallible; +/// /// use telebofr::{ +/// Bot, +/// types::Message, /// dispatching::{ /// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher}, /// updater::polling, @@ -51,7 +52,7 @@ type Handlers<'a, T, E> = /// /// // create dispatching which handlers can't fail /// // with error policy that just ignores all errors (that can't ever happen) -/// let mut dp = FilterDispatcher::::new(ErrorPolicy::Ignore) +/// let mut dp = FilterDispatcher::::new(|_| async { () }) /// // Add 'handler' that will handle all messages sent to the bot /// .message_handler(true, |mes: Message| { /// async move { println!("New message: {:?}", mes) } @@ -66,9 +67,8 @@ type Handlers<'a, T, E> = /// ``` /// /// [`std::fmt::Debug`]: std::fmt::Debug -/// [Custom error policy]: -/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]: -/// crate::dispatching::updater +/// [Custom error policy]: crate::dispatching::filter::error_policy::ErrorPolicy::Custom +/// [updater]: crate::dispatching::updater pub struct FilterDispatcher<'a, E, Ep> { message_handlers: Handlers<'a, Message, E>, edited_message_handlers: Handlers<'a, Message, E>, @@ -238,7 +238,7 @@ where .await; } - async fn handle(&mut self, update: T, handlers: &Handlers<'a, T, E>) + async fn handle(&self, update: T, handlers: &Handlers<'a, T, E>) where T: std::fmt::Debug, { @@ -287,9 +287,7 @@ mod tests { use crate::{ dispatching::{ - dispatchers::filter::{ - error_policy::FnErrorPolicy, FilterDispatcher, - }, + dispatchers::filter::FilterDispatcher, updater::StreamUpdater, }, types::{ @@ -303,10 +301,7 @@ mod tests { let counter = &AtomicI32::new(0); let counter2 = &AtomicI32::new(0); - let mut dp = - FilterDispatcher::::new(FnErrorPolicy(|_| { - async { () } - })) + let mut dp = FilterDispatcher::::new(|_| async { () } ) .message_handler(true, |_mes: Message| { async move { counter.fetch_add(1, Ordering::SeqCst); From 4423a992c0bf823b5eb7e33fa5bb59a6668b51d2 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 2 Nov 2019 16:50:32 +0300 Subject: [PATCH 24/31] Fix indent for `where` --- src/dispatching/dispatchers/filter/error_policy.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index b602bcf0..91bd322b 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -12,10 +12,10 @@ pub trait ErrorPolicy { } impl ErrorPolicy for F - where - F: Fn(E) -> Fut + Sync, - Fut: Future + Send, - E: Send, +where + F: Fn(E) -> Fut + Sync, + Fut: Future + Send, + E: Send, { fn handle_error<'s, 'async_trait>(&'s self, error: E) -> Pin + Send + 'async_trait>> where From 5c73af4a6fd7fc3c2a06e2d954fc1a543e3dc8fb Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 2 Nov 2019 17:15:13 +0300 Subject: [PATCH 25/31] Add `Ignore` and `IgnoreSafe` error policies. --- Cargo.toml | 3 +- .../dispatchers/filter/error_policy.rs | 114 +++++++++++++++++- src/lib.rs | 2 + 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6b662740..522c1a8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,5 @@ thiserror = "1.0.2" [features] default = [] -unstable-stream = [] # add streams to public API \ No newline at end of file +unstable-stream = [] # add streams to public API +never-type = [] # add never type (`!`) to punlic API \ No newline at end of file diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index 91bd322b..f69ef4e8 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -1,7 +1,10 @@ -use std::future::Future; +use std::{ + pin::Pin, + future::Future, + convert::Infallible, +}; use async_trait::async_trait; -use std::pin::Pin; /// Implementors of this trait are treated as error-handlers. #[async_trait] @@ -11,6 +14,113 @@ pub trait ErrorPolicy { E: 'async_trait; } +/// Error policy that silently ignores all errors +/// +/// ## Example +/// ``` +/// # #[tokio::main] +/// # async fn main() { +/// use telebofr::dispatching::dispatchers::filter::error_policy::{ +/// ErrorPolicy, +/// Ignore, +/// }; +/// +/// Ignore.handle_error(()).await; +/// Ignore.handle_error(404).await; +/// Ignore.handle_error(String::from("error")).await; +/// # } +/// ``` +pub struct Ignore; + +#[async_trait] +impl ErrorPolicy for Ignore +where + E: Send, +{ + async fn handle_error(&self, _: E) + where + E: 'async_trait + {} +} + +/// Error policy that silently ignores all errors that can never happen (e.g.: [`!`] or [`Infallible`]) +/// +/// ## Examples +/// ``` +/// # #[tokio::main] +/// # async fn main() { +/// use std::convert::{TryInto, Infallible}; +/// +/// use telebofr::dispatching::dispatchers::filter::error_policy::{ +/// ErrorPolicy, +/// IgnoreSafe, +/// }; +/// +/// let result: Result = "str".try_into(); +/// match result { +/// Ok(string) => println!("{}", string), +/// Err(inf) => IgnoreSafe.handle_error(inf).await, +/// } +/// +/// IgnoreSafe.handle_error(return).await; // return type of `return` is `!` (aka never) +/// # } +/// ``` +/// +/// ```compile_fail +/// use telebofr::dispatching::dispatchers::filter::error_policy::{ +/// ErrorPolicy, +/// IgnoreSafe, +/// }; +/// +/// IgnoreSafe.handle_error(0); +/// ``` +/// +/// ## Note +/// Never type is not stabilized yet (see [`#35121`]) so all API that uses [`!`] +/// (including `impl ErrorPolicy for IgnoreSafe`) we hide under the +/// `never-type` cargo feature. +/// +/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html +/// [`Infallible`]: std::convert::Infallible +/// [`#35121`]: https://github.com/rust-lang/rust/issues/35121 +pub struct IgnoreSafe; + +#[cfg(feature = "never-type")] +#[async_trait] +impl ErrorPolicy for IgnoreSafe { + async fn handle_error(&self, never: !) + where + !: 'async_trait + { + never + } +} + +#[async_trait] +impl ErrorPolicy for IgnoreSafe { + async fn handle_error(&self, inf: Infallible) + where + Infallible: 'async_trait + { + match inf {} + } +} + +/// Implementation of `ErrorPolicy` for `async fn`s +/// +/// ## Example +/// ``` +/// # #[tokio::main] +/// # async fn main() { +/// use telebofr::dispatching::dispatchers::filter::error_policy::ErrorPolicy; +/// +/// let closure = |e: i32| async move { +/// eprintln!("Error code{}", e) +/// }; +/// +/// closure.handle_error(404).await; +/// # } +/// ``` impl ErrorPolicy for F where F: Fn(E) -> Fut + Sync, diff --git a/src/lib.rs b/src/lib.rs index 838a211a..339931e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "never-type", feature(never_type))] + #[macro_use] extern crate derive_more; #[macro_use] From ab9f2b99f19db2419b2feba53aaa16a4d7c69883 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 2 Nov 2019 17:16:54 +0300 Subject: [PATCH 26/31] Add newline at the end of the `Cargo.toml` --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 522c1a8e..b74a1f87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,4 +22,4 @@ thiserror = "1.0.2" default = [] unstable-stream = [] # add streams to public API -never-type = [] # add never type (`!`) to punlic API \ No newline at end of file +never-type = [] # add never type (`!`) to punlic API From 89db95ef3f19cd28d152361bfe7caf5770fdc19f Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 3 Nov 2019 19:16:38 +0600 Subject: [PATCH 27/31] Simplify 'type Handlers = ...' (dispatchers/filter/mod.rs) --- .../dispatchers/filter/error_policy.rs | 35 +++--- src/dispatching/dispatchers/filter/mod.rs | 112 ++++++++++-------- 2 files changed, 80 insertions(+), 67 deletions(-) diff --git a/src/dispatching/dispatchers/filter/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs index f69ef4e8..a54509b4 100644 --- a/src/dispatching/dispatchers/filter/error_policy.rs +++ b/src/dispatching/dispatchers/filter/error_policy.rs @@ -1,8 +1,4 @@ -use std::{ - pin::Pin, - future::Future, - convert::Infallible, -}; +use std::{convert::Infallible, future::Future, pin::Pin}; use async_trait::async_trait; @@ -21,8 +17,7 @@ pub trait ErrorPolicy { /// # #[tokio::main] /// # async fn main() { /// use telebofr::dispatching::dispatchers::filter::error_policy::{ -/// ErrorPolicy, -/// Ignore, +/// ErrorPolicy, Ignore, /// }; /// /// Ignore.handle_error(()).await; @@ -39,11 +34,13 @@ where { async fn handle_error(&self, _: E) where - E: 'async_trait - {} + E: 'async_trait, + { + } } -/// Error policy that silently ignores all errors that can never happen (e.g.: [`!`] or [`Infallible`]) +/// Error policy that silently ignores all errors that can never happen (e.g.: +/// [`!`] or [`Infallible`]) /// /// ## Examples /// ``` @@ -68,8 +65,7 @@ where /// /// ```compile_fail /// use telebofr::dispatching::dispatchers::filter::error_policy::{ -/// ErrorPolicy, -/// IgnoreSafe, +/// ErrorPolicy, IgnoreSafe, /// }; /// /// IgnoreSafe.handle_error(0); @@ -90,7 +86,7 @@ pub struct IgnoreSafe; impl ErrorPolicy for IgnoreSafe { async fn handle_error(&self, never: !) where - !: 'async_trait + !: 'async_trait, { never } @@ -100,7 +96,7 @@ impl ErrorPolicy for IgnoreSafe { impl ErrorPolicy for IgnoreSafe { async fn handle_error(&self, inf: Infallible) where - Infallible: 'async_trait + Infallible: 'async_trait, { match inf {} } @@ -114,9 +110,7 @@ impl ErrorPolicy for IgnoreSafe { /// # async fn main() { /// use telebofr::dispatching::dispatchers::filter::error_policy::ErrorPolicy; /// -/// let closure = |e: i32| async move { -/// eprintln!("Error code{}", e) -/// }; +/// let closure = |e: i32| async move { eprintln!("Error code{}", e) }; /// /// closure.handle_error(404).await; /// # } @@ -127,11 +121,14 @@ where Fut: Future + Send, E: Send, { - fn handle_error<'s, 'async_trait>(&'s self, error: E) -> Pin + Send + 'async_trait>> + fn handle_error<'s, 'async_trait>( + &'s self, + error: E, + ) -> Pin + Send + 'async_trait>> where 's: 'async_trait, Self: 'async_trait, - E: 'async_trait + E: 'async_trait, { Box::pin(async move { self(error).await }) } diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index 5d1b0a89..f36ea740 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -12,8 +12,12 @@ use crate::{ pub mod error_policy; -type Handlers<'a, T, E> = - Vec<(Box + 'a>, Box + 'a>)>; +struct FilterAndHandler<'a, T, E> { + filter: Box + 'a>, + handler: Box + 'a>, +} + +type FiltersAndHandlers<'a, T, E> = Vec>; /// Dispatcher that dispatches updates from telegram. /// @@ -36,12 +40,14 @@ type Handlers<'a, T, E> = /// use std::convert::Infallible; /// /// use telebofr::{ -/// Bot, -/// types::Message, /// dispatching::{ -/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher}, +/// dispatchers::filter::{ +/// error_policy::ErrorPolicy, FilterDispatcher, +/// }, /// updater::polling, /// }, +/// types::Message, +/// Bot, /// }; /// /// async fn handle_edited_message(mes: Message) { @@ -67,16 +73,18 @@ type Handlers<'a, T, E> = /// ``` /// /// [`std::fmt::Debug`]: std::fmt::Debug -/// [Custom error policy]: crate::dispatching::filter::error_policy::ErrorPolicy::Custom -/// [updater]: crate::dispatching::updater +/// [Custom error policy]: +/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]: +/// crate::dispatching::updater pub struct FilterDispatcher<'a, E, Ep> { - message_handlers: Handlers<'a, Message, E>, - edited_message_handlers: Handlers<'a, Message, E>, - channel_post_handlers: Handlers<'a, Message, E>, - edited_channel_post_handlers: Handlers<'a, Message, E>, - inline_query_handlers: Handlers<'a, (), E>, - chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>, - callback_query_handlers: Handlers<'a, CallbackQuery, E>, + message_handlers: FiltersAndHandlers<'a, Message, E>, + edited_message_handlers: FiltersAndHandlers<'a, Message, E>, + channel_post_handlers: FiltersAndHandlers<'a, Message, E>, + edited_channel_post_handlers: FiltersAndHandlers<'a, Message, E>, + inline_query_handlers: FiltersAndHandlers<'a, (), E>, + chosen_inline_result_handlers: + FiltersAndHandlers<'a, ChosenInlineResult, E>, + callback_query_handlers: FiltersAndHandlers<'a, CallbackQuery, E>, error_policy: Ep, } @@ -103,8 +111,10 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.message_handlers - .push((Box::new(filter), Box::new(handler))); + self.message_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -113,8 +123,10 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.edited_message_handlers - .push((Box::new(filter), Box::new(handler))); + self.edited_message_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -123,8 +135,10 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.channel_post_handlers - .push((Box::new(filter), Box::new(handler))); + self.channel_post_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -137,8 +151,10 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.edited_channel_post_handlers - .push((Box::new(filter), Box::new(handler))); + self.edited_channel_post_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -147,8 +163,10 @@ where F: Filter<()> + 'a, H: Handler<'a, (), E> + 'a, { - self.inline_query_handlers - .push((Box::new(filter), Box::new(handler))); + self.inline_query_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -161,8 +179,10 @@ where F: Filter + 'a, H: Handler<'a, ChosenInlineResult, E> + 'a, { - self.chosen_inline_result_handlers - .push((Box::new(filter), Box::new(handler))); + self.chosen_inline_result_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -171,8 +191,10 @@ where F: Filter + 'a, H: Handler<'a, CallbackQuery, E> + 'a, { - self.callback_query_handlers - .push((Box::new(filter), Box::new(handler))); + self.callback_query_handlers.push(FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + }); self } @@ -238,29 +260,24 @@ where .await; } - async fn handle(&self, update: T, handlers: &Handlers<'a, T, E>) - where + async fn handle( + &self, + update: T, + handlers: &FiltersAndHandlers<'a, T, E>, + ) where T: std::fmt::Debug, { - let handler = handlers.iter().find_map(|e| { - let (filter, handler) = e; - if filter.test(&update) { - Some(handler) - } else { - None - } - }); - - match handler { - Some(handler) => { - if let Err(err) = handler.handle(update).await { + for x in handlers { + if x.filter.test(&update) { + if let Err(err) = x.handler.handle(update).await { self.error_policy.handle_error(err).await } - } - None => { - log::warn!("unhandled update {:?}", update); + + return; } } + + log::warn!("unhandled update {:?}", update); } } @@ -287,8 +304,7 @@ mod tests { use crate::{ dispatching::{ - dispatchers::filter::FilterDispatcher, - updater::StreamUpdater, + dispatchers::filter::FilterDispatcher, updater::StreamUpdater, }, types::{ Chat, ChatKind, ForwardKind, MediaKind, Message, MessageKind, @@ -301,7 +317,7 @@ mod tests { let counter = &AtomicI32::new(0); let counter2 = &AtomicI32::new(0); - let mut dp = FilterDispatcher::::new(|_| async { () } ) + let mut dp = FilterDispatcher::::new(|_| async { () }) .message_handler(true, |_mes: Message| { async move { counter.fetch_add(1, Ordering::SeqCst); From 60391de28af755da4e5a00639429080be72a1197 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 3 Nov 2019 19:33:24 +0600 Subject: [PATCH 28/31] Add FilterAndHandler::new --- src/dispatching/dispatchers/filter/mod.rs | 51 ++++++++++------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index f36ea740..2fe7bd79 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -17,6 +17,15 @@ struct FilterAndHandler<'a, T, E> { handler: Box + 'a>, } +impl<'a, T, E> FilterAndHandler<'a, T, E> { + fn new( + filter: Box + 'a>, + handler: Box + 'a>, + ) -> Self { + FilterAndHandler { filter, handler } + } +} + type FiltersAndHandlers<'a, T, E> = Vec>; /// Dispatcher that dispatches updates from telegram. @@ -111,10 +120,8 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.message_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.message_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -123,10 +130,8 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.edited_message_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.edited_message_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -135,10 +140,8 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.channel_post_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.channel_post_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -151,10 +154,8 @@ where F: Filter + 'a, H: Handler<'a, Message, E> + 'a, { - self.edited_channel_post_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.edited_channel_post_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -163,10 +164,8 @@ where F: Filter<()> + 'a, H: Handler<'a, (), E> + 'a, { - self.inline_query_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.inline_query_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -179,10 +178,8 @@ where F: Filter + 'a, H: Handler<'a, ChosenInlineResult, E> + 'a, { - self.chosen_inline_result_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.chosen_inline_result_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } @@ -191,10 +188,8 @@ where F: Filter + 'a, H: Handler<'a, CallbackQuery, E> + 'a, { - self.callback_query_handlers.push(FilterAndHandler { - filter: Box::new(filter), - handler: Box::new(handler), - }); + self.callback_query_handlers + .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); self } From f8851eabffcb9d8ac493e06fa9eec6386a288e07 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Mon, 4 Nov 2019 01:03:04 +0600 Subject: [PATCH 29/31] Rework HandlerAndFilter::new --- src/dispatching/dispatchers/filter/mod.rs | 28 +++-- src/requests/form_builder.rs | 139 ---------------------- 2 files changed, 16 insertions(+), 151 deletions(-) delete mode 100644 src/requests/form_builder.rs diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs index 2fe7bd79..436aa921 100644 --- a/src/dispatching/dispatchers/filter/mod.rs +++ b/src/dispatching/dispatchers/filter/mod.rs @@ -18,11 +18,15 @@ struct FilterAndHandler<'a, T, E> { } impl<'a, T, E> FilterAndHandler<'a, T, E> { - fn new( - filter: Box + 'a>, - handler: Box + 'a>, - ) -> Self { - FilterAndHandler { filter, handler } + fn new(filter: F, handler: H) -> Self + where + F: Filter + 'a, + H: Handler<'a, T, E> + 'a, + { + FilterAndHandler { + filter: Box::new(filter), + handler: Box::new(handler), + } } } @@ -121,7 +125,7 @@ where H: Handler<'a, Message, E> + 'a, { self.message_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -131,7 +135,7 @@ where H: Handler<'a, Message, E> + 'a, { self.edited_message_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -141,7 +145,7 @@ where H: Handler<'a, Message, E> + 'a, { self.channel_post_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -155,7 +159,7 @@ where H: Handler<'a, Message, E> + 'a, { self.edited_channel_post_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -165,7 +169,7 @@ where H: Handler<'a, (), E> + 'a, { self.inline_query_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -179,7 +183,7 @@ where H: Handler<'a, ChosenInlineResult, E> + 'a, { self.chosen_inline_result_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } @@ -189,7 +193,7 @@ where H: Handler<'a, CallbackQuery, E> + 'a, { self.callback_query_handlers - .push(FilterAndHandler::new(Box::new(filter), Box::new(handler))); + .push(FilterAndHandler::new(filter, handler)); self } diff --git a/src/requests/form_builder.rs b/src/requests/form_builder.rs deleted file mode 100644 index bc355eab..00000000 --- a/src/requests/form_builder.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::{ - path::PathBuf, - borrow::Cow, -}; - -use reqwest::multipart::Form; - -use crate::{ - requests::utils::file_to_part, - types::{ChatId, InputMedia, ParseMode, InputFile}, -}; - -/// This is a convenient struct that builds `reqwest::multipart::Form` -/// from scratch. -pub(crate) struct FormBuilder { - form: Form, -} - -impl FormBuilder { - pub fn new() -> Self { - Self { form: Form::new() } - } - - /// Add the supplied key-value pair to this `FormBuilder`. - pub fn add<'a, T, N>(self, name: N, value: T) -> Self - where - N: Into>, - T: IntoFormValue, - { - let name = name.into().into_owned(); - match value.into_form_value() { - Some(FormValue::Str(string)) => Self { - form: self.form.text(name, string), - }, - Some(FormValue::File(path)) => self.add_file(name, path), - None => self, - } - } - - // used in SendMediaGroup - pub fn add_file<'a, N>(self, name: N, path_to_file: PathBuf) -> Self - where - N: Into> - { - Self { - form: self - .form - .part(name.into().into_owned(), file_to_part(path_to_file)), - } - } - - pub fn build(self) -> Form { - self.form - } -} - -pub(crate) enum FormValue { - File(PathBuf), - Str(String), -} - -pub(crate) trait IntoFormValue { - fn into_form_value(self) -> Option; -} - -macro_rules! impl_for_struct { - ($($name:ty),*) => { - $( - impl IntoFormValue for $name { - fn into_form_value(self) -> Option { - let json = serde_json::to_string(&self) - .expect("serde_json::to_string failed"); - Some(FormValue::Str(json)) - } - } - )* - }; -} - -impl_for_struct!(bool, i32, i64); - -impl IntoFormValue for Option -where - T: IntoFormValue, -{ - fn into_form_value(self) -> Option { - self.and_then(IntoFormValue::into_form_value) - } -} - -impl IntoFormValue for &[InputMedia] { - fn into_form_value(self) -> Option { - let json = - serde_json::to_string(self).expect("serde_json::to_string failed"); - Some(FormValue::Str(json)) - } -} - -impl IntoFormValue for &str { - fn into_form_value(self) -> Option { - Some(FormValue::Str(self.to_owned())) - } -} - -impl IntoFormValue for ParseMode { - fn into_form_value(self) -> Option { - let string = match self { - ParseMode::HTML => String::from("HTML"), - ParseMode::Markdown => String::from("Markdown"), - }; - Some(FormValue::Str(string)) - } -} - -impl IntoFormValue for ChatId { - fn into_form_value(self) -> Option { - let string = match self { - ChatId::Id(id) => id.to_string(), - ChatId::ChannelUsername(username) => username, - }; - Some(FormValue::Str(string)) - } -} - -impl IntoFormValue for String { - fn into_form_value(self) -> Option { - Some(FormValue::Str(self)) - } -} - -impl IntoFormValue for InputFile { - fn into_form_value(self) -> Option { - match self { - InputFile::File(path) => Some(FormValue::File(path)), - InputFile::Url(url) => Some(FormValue::Str(url)), - InputFile::FileId(file_id) => Some(FormValue::Str(file_id)), - } - } -} From 478cde4c3fac3453dce9ee1481b6d57bd800f01c Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Mon, 4 Nov 2019 01:03:56 +0600 Subject: [PATCH 30/31] Oops --- src/requests/form_builder.rs | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/requests/form_builder.rs diff --git a/src/requests/form_builder.rs b/src/requests/form_builder.rs new file mode 100644 index 00000000..f19bc864 --- /dev/null +++ b/src/requests/form_builder.rs @@ -0,0 +1,136 @@ +use std::{borrow::Cow, path::PathBuf}; + +use reqwest::multipart::Form; + +use crate::{ + requests::utils::file_to_part, + types::{ChatId, InputFile, InputMedia, ParseMode}, +}; + +/// This is a convenient struct that builds `reqwest::multipart::Form` +/// from scratch. +pub(crate) struct FormBuilder { + form: Form, +} + +impl FormBuilder { + pub fn new() -> Self { + Self { form: Form::new() } + } + + /// Add the supplied key-value pair to this `FormBuilder`. + pub fn add<'a, T, N>(self, name: N, value: T) -> Self + where + N: Into>, + T: IntoFormValue, + { + let name = name.into().into_owned(); + match value.into_form_value() { + Some(FormValue::Str(string)) => Self { + form: self.form.text(name, string), + }, + Some(FormValue::File(path)) => self.add_file(name, path), + None => self, + } + } + + // used in SendMediaGroup + pub fn add_file<'a, N>(self, name: N, path_to_file: PathBuf) -> Self + where + N: Into>, + { + Self { + form: self + .form + .part(name.into().into_owned(), file_to_part(path_to_file)), + } + } + + pub fn build(self) -> Form { + self.form + } +} + +pub(crate) enum FormValue { + File(PathBuf), + Str(String), +} + +pub(crate) trait IntoFormValue { + fn into_form_value(self) -> Option; +} + +macro_rules! impl_for_struct { + ($($name:ty),*) => { + $( + impl IntoFormValue for $name { + fn into_form_value(self) -> Option { + let json = serde_json::to_string(&self) + .expect("serde_json::to_string failed"); + Some(FormValue::Str(json)) + } + } + )* + }; +} + +impl_for_struct!(bool, i32, i64); + +impl IntoFormValue for Option +where + T: IntoFormValue, +{ + fn into_form_value(self) -> Option { + self.and_then(IntoFormValue::into_form_value) + } +} + +impl IntoFormValue for &[InputMedia] { + fn into_form_value(self) -> Option { + let json = + serde_json::to_string(self).expect("serde_json::to_string failed"); + Some(FormValue::Str(json)) + } +} + +impl IntoFormValue for &str { + fn into_form_value(self) -> Option { + Some(FormValue::Str(self.to_owned())) + } +} + +impl IntoFormValue for ParseMode { + fn into_form_value(self) -> Option { + let string = match self { + ParseMode::HTML => String::from("HTML"), + ParseMode::Markdown => String::from("Markdown"), + }; + Some(FormValue::Str(string)) + } +} + +impl IntoFormValue for ChatId { + fn into_form_value(self) -> Option { + let string = match self { + ChatId::Id(id) => id.to_string(), + ChatId::ChannelUsername(username) => username, + }; + Some(FormValue::Str(string)) + } +} + +impl IntoFormValue for String { + fn into_form_value(self) -> Option { + Some(FormValue::Str(self)) + } +} + +impl IntoFormValue for InputFile { + fn into_form_value(self) -> Option { + match self { + InputFile::File(path) => Some(FormValue::File(path)), + InputFile::Url(url) => Some(FormValue::Str(url)), + InputFile::FileId(file_id) => Some(FormValue::Str(file_id)), + } + } +} From c0bd9b64c8ed8172358d006ee6d4b7338c45b3f2 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Wed, 13 Nov 2019 20:45:18 +0600 Subject: [PATCH 31/31] Remove hw.doc --- hw.doc | Bin 33280 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 hw.doc diff --git a/hw.doc b/hw.doc deleted file mode 100644 index 0bdb82bf7864fcf9f8101fb143c11cc9a5ea15fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33280 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 TlUhDHeKfxf{iCaaL?iwmfn32*