From 53b9ab31c428de95b5ee7dde9b4908c0786c7a4f Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 13:59:31 +0300 Subject: [PATCH 1/7] Fix clippy's `warning: returning the result of a let binding from a block` --- src/requests/utils.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/requests/utils.rs b/src/requests/utils.rs index 9add97f0..6ff6b3a5 100644 --- a/src/requests/utils.rs +++ b/src/requests/utils.rs @@ -30,12 +30,11 @@ pub fn file_to_part(path_to_file: &PathBuf) -> Part { ) }) .flatten_stream(); - let part = Part::stream(Body::wrap_stream(file)).file_name( + Part::stream(Body::wrap_stream(file)).file_name( path_to_file .file_name() .unwrap() .to_string_lossy() .into_owned(), - ); - part + ) } From cbd98f6e03efe841afdf4c3abed6920ccc71609f Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 14:03:56 +0300 Subject: [PATCH 2/7] Fix clippy `warning: methods called `from_*` usually take no self; consider choosing a less ambiguous name` (actually just allow that on the `from_chat_id` method cause it is setter for co-named field) --- src/requests/forward_message.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/requests/forward_message.rs b/src/requests/forward_message.rs index 69f81453..79498e24 100644 --- a/src/requests/forward_message.rs +++ b/src/requests/forward_message.rs @@ -70,6 +70,7 @@ impl<'a> ForwardMessage<'a> { self } + #[allow(clippy::wrong_self_convention)] pub fn from_chat_id>(mut self, val: T) -> Self { self.from_chat_id = val.into(); self From d68ec00deb20f3bfaebe80c0c7791e3d3f3625dc Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 14:17:23 +0300 Subject: [PATCH 3/7] Elide lifetimes where possible. Fix clippy "warning: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)" --- src/requests/kick_chat_member.rs | 2 +- src/requests/pin_chat_message.rs | 2 +- src/requests/restrict_chat_member.rs | 2 +- src/requests/send_animation.rs | 2 +- src/requests/send_video.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/requests/kick_chat_member.rs b/src/requests/kick_chat_member.rs index deb6c65e..975b6b71 100644 --- a/src/requests/kick_chat_member.rs +++ b/src/requests/kick_chat_member.rs @@ -28,7 +28,7 @@ pub struct KickChatMember<'a> { } #[async_trait] -impl<'a> Request for KickChatMember<'a> { +impl Request for KickChatMember<'_> { type ReturnValue = True; async fn send_boxed(self) -> ResponseResult { diff --git a/src/requests/pin_chat_message.rs b/src/requests/pin_chat_message.rs index 5ab517ff..0e3764c3 100644 --- a/src/requests/pin_chat_message.rs +++ b/src/requests/pin_chat_message.rs @@ -45,7 +45,7 @@ impl<'a> PinChatMessage<'a> { } #[async_trait] -impl<'a> Request for PinChatMessage<'a> { +impl Request for PinChatMessage<'_> { type ReturnValue = True; async fn send_boxed(self) -> ResponseResult { self.send().await diff --git a/src/requests/restrict_chat_member.rs b/src/requests/restrict_chat_member.rs index 67e24c5a..06139c37 100644 --- a/src/requests/restrict_chat_member.rs +++ b/src/requests/restrict_chat_member.rs @@ -29,7 +29,7 @@ pub struct RestrictChatMember<'a> { } #[async_trait] -impl<'a> Request for RestrictChatMember<'a> { +impl Request for RestrictChatMember<'_> { type ReturnValue = True; async fn send_boxed(self) -> ResponseResult { diff --git a/src/requests/send_animation.rs b/src/requests/send_animation.rs index 3020d9fe..b5741de0 100644 --- a/src/requests/send_animation.rs +++ b/src/requests/send_animation.rs @@ -65,7 +65,7 @@ pub struct SendAnimation<'a> { } #[async_trait] -impl<'a> Request for SendAnimation<'a> { +impl Request for SendAnimation<'_> { type ReturnValue = Message; async fn send_boxed(self) -> ResponseResult { diff --git a/src/requests/send_video.rs b/src/requests/send_video.rs index a234cbee..7e5d03da 100644 --- a/src/requests/send_video.rs +++ b/src/requests/send_video.rs @@ -66,7 +66,7 @@ pub struct SendVideo<'a> { } #[async_trait] -impl<'a> Request for SendVideo<'a> { +impl Request for SendVideo<'_> { type ReturnValue = Message; async fn send_boxed(self) -> ResponseResult { From 77b24eaa3fe23649a81c9312918d504860cbdf00 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 14:39:53 +0300 Subject: [PATCH 4/7] Remove `fn main` from doctest (and also remove `edition2018` cause I think it isn't useful) Fix clippy "warning: needless `fn main` in doctest" --- src/types/inline_keyboard_button.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/types/inline_keyboard_button.rs b/src/types/inline_keyboard_button.rs index 5d5b2ee7..27ef8896 100644 --- a/src/types/inline_keyboard_button.rs +++ b/src/types/inline_keyboard_button.rs @@ -44,15 +44,13 @@ pub enum InlineKeyboardButtonKind { /// Build buttons /// /// Example: -/// ```edition2018 +/// ``` /// use async_telegram_bot::types::InlineKeyboardButton; /// -/// fn main() { -/// let url_button = InlineKeyboardButton::url( -/// "Text".to_string(), -/// "http://url.com".to_string(), -/// ); -/// } +/// let url_button = InlineKeyboardButton::url( +/// "Text".to_string(), +/// "http://url.com".to_string(), +/// ); /// ``` impl InlineKeyboardButton { pub fn url(text: String, url: String) -> InlineKeyboardButton { From 101630a3a12aa3b0758c2b43f5a19b51c5c86e4c Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 14:44:21 +0300 Subject: [PATCH 5/7] Fix clippy "warning: you should consider deriving a `Default` implementation for `types::inline_keyboard_markup::InlineKeyboardMarkup`" --- src/types/inline_keyboard_markup.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/types/inline_keyboard_markup.rs b/src/types/inline_keyboard_markup.rs index 89eb625e..67bd2aa8 100644 --- a/src/types/inline_keyboard_markup.rs +++ b/src/types/inline_keyboard_markup.rs @@ -5,7 +5,7 @@ use crate::types::InlineKeyboardButton; /// /// *Note*: This will only work in Telegram versions released after /// 9 April, 2016. Older clients will display unsupported message. -#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone)] +#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Default)] pub struct InlineKeyboardMarkup { /// Array of button rows, each represented by an Array of /// [`InlineKeyboardButton`] objects @@ -28,9 +28,7 @@ pub struct InlineKeyboardMarkup { /// ``` impl InlineKeyboardMarkup { pub fn new() -> Self { - Self { - inline_keyboard: vec![], - } + <_>::default() } pub fn append_row(mut self, buttons: Vec) -> Self { From c4664025944b62eeff8864a593247518e4d48187 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sun, 13 Oct 2019 14:59:22 +0300 Subject: [PATCH 6/7] Allow matching on `bool` for in `src/types/unit_true.rs` --- src/types/unit_true.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/unit_true.rs b/src/types/unit_true.rs index e2c9444b..0efe1b33 100644 --- a/src/types/unit_true.rs +++ b/src/types/unit_true.rs @@ -8,6 +8,7 @@ impl std::convert::TryFrom for True { type Error = (); fn try_from(value: bool) -> Result { + #[allow(clippy::match_bool)] match value { true => Ok(True), false => Err(()), @@ -37,6 +38,7 @@ impl<'de> Visitor<'de> for TrueVisitor { where E: de::Error, { + #[allow(clippy::match_bool)] match value { true => Ok(True), false => Err(E::custom("expected `true`, found `false`")), From b75a25cbd81101e95cfb94f65d65e8f5bf5e943a Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 14 Oct 2019 00:19:18 +0300 Subject: [PATCH 7/7] Add getters for all `Message` fields --- src/types/message.rs | 396 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 374 insertions(+), 22 deletions(-) diff --git a/src/types/message.rs b/src/types/message.rs index baa5adeb..c658dd42 100644 --- a/src/types/message.rs +++ b/src/types/message.rs @@ -1,8 +1,4 @@ -use crate::types::{ - Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup, - Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker, - SuccessfulPayment, User, Venue, Video, VideoNote, Voice, -}; +use crate::types::{Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup, Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker, SuccessfulPayment, User, Venue, Video, VideoNote, Voice, True}; #[derive(Debug, Deserialize, PartialEq, Clone)] pub struct Message { @@ -14,19 +10,6 @@ pub struct Message { pub kind: MessageKind, } -impl Message { - pub fn text(&self) -> Option<&str> { - if let MessageKind::Common { - media_kind: MediaKind::Text { ref text, .. }, - .. - } = self.kind - { - Some(text) - } else { - None - } - } -} #[derive(Debug, Deserialize, PartialEq, Clone)] #[serde(untagged)] @@ -54,16 +37,16 @@ pub enum MessageKind { new_chat_photo: Vec, }, DeleteChatPhoto { - delete_chat_photo: bool, + delete_chat_photo: True, }, GroupChatCreated { - group_chat_created: bool, + group_chat_created: True, }, SupergroupChatCreated { - supergroup_chat_created: bool, + supergroup_chat_created: True, }, ChannelChatCreated { - channel_chat_created: bool, + channel_chat_created: True, }, Migrate { migrate_to_chat_id: i64, @@ -201,6 +184,375 @@ pub enum MediaKind { }, } +mod getters { + use std::ops::Deref; + + use crate::types::{ + self, Message, Sender, User, ForwardedFrom, Chat, MessageEntity, + PhotoSize, True, + message::{ + MessageKind::{ + Common, NewChatMembers, LeftChatMember, NewChatTitle, + NewChatPhoto, DeleteChatPhoto, GroupChatCreated, + ChannelChatCreated, Migrate, Invoice, SuccessfulPayment, + ConnectedWebsite, PassportData + }, + MediaKind::{ + Text, Video, Photo, Animation, Audio, Document, Voice, Game, + Sticker, VideoNote, Contact, Location, Poll, Venue + }, + ForwardKind::{NonChannelForward, ChannelForward, Origin} + }, + }; + use crate::types::message::MessageKind::{SupergroupChatCreated, Pinned}; + + /// Getters for [Message] fields from [telegram docs]. + /// + /// [Message]: crate::types::Message + /// [telegram docs]: https://core.telegram.org/bots/api#message + impl Message { + /// NOTE: this is getter for both `from` and `author_signature` + pub fn from(&self) -> Option<&Sender> { + match &self.kind { + Common { from, .. } => Some(from), + _ => None, + } + } + + /// NOTE: this is getter for both `forward_from` and + /// `forward_sender_name` + pub fn forward_from(&self) -> Option<&ForwardedFrom> { + match &self.kind { + Common { forward_kind: NonChannelForward { from, .. }, .. } => + Some(from), + _ => None, + } + } + + pub fn forward_from_chat(&self) -> Option<&Chat> { + match &self.kind { + Common { forward_kind: ChannelForward { chat, .. }, .. } => + Some(chat), + _ => None, + } + } + + pub fn forward_from_message_id(&self) -> Option<&i32> { + match &self.kind { + Common { forward_kind: ChannelForward { message_id, .. }, .. } => + Some(message_id), + _ => None, + } + } + + pub fn forward_signature(&self) -> Option<&str> { + match &self.kind { + Common { forward_kind: ChannelForward { signature, .. }, .. } => + signature.as_ref().map(Deref::deref), + _ => None, + } + } + + pub fn forward_date(&self) -> Option<&i32> { + match &self.kind { + Common { forward_kind: ChannelForward { date, .. }, .. } | + Common { forward_kind: NonChannelForward { date, .. }, .. } => + Some(date), + _ => None, + } + } + + pub fn reply_to_message(&self) -> Option<&Message> { + match &self.kind { + Common { forward_kind: Origin { reply_to_message, .. }, .. } => + reply_to_message.as_ref().map(Deref::deref), + _ => None, + } + } + + pub fn edit_date(&self) -> Option<&i32> { + match &self.kind { + Common { edit_date, .. } => edit_date.as_ref(), + _ => None, + } + } + + pub fn media_group_id(&self) -> Option<&str> { + match &self.kind { + Common { media_kind: Video { media_group_id, .. }, .. } | + Common { media_kind: Photo { media_group_id, .. }, .. } => + media_group_id.as_ref().map(Deref::deref), + _ => None, + } + } + + pub fn text(&self) -> Option<&str> { + match &self.kind { + Common { media_kind: Text { text, .. }, .. } => Some(text), + _ => None, + } + } + + pub fn entities(&self) -> Option<&[MessageEntity]> { + match &self.kind { + Common { media_kind: Text { entities, .. }, .. } => + Some(entities), + _ => None, + } + } + + pub fn caption_entities(&self) -> Option<&[MessageEntity]> { + match &self.kind { + Common { media_kind: Animation { caption_entities, .. }, .. } | + Common { media_kind: Audio { caption_entities, .. }, .. } | + Common { media_kind: Document { caption_entities, .. }, .. } | + Common { media_kind: Photo { caption_entities, .. }, .. } | + Common { media_kind: Video { caption_entities, .. }, .. } | + Common { media_kind: Voice { caption_entities, .. }, .. } => + Some(caption_entities), + _ => None, + } + } + + pub fn audio(&self) -> Option<&types::Audio> { + match &self.kind { + Common { media_kind: Audio { audio, .. }, .. } => Some(audio), + _ => None, + } + } + + pub fn document(&self) -> Option<&types::Document> { + match &self.kind { + Common { media_kind: Document { document, .. }, .. } => + Some(document), + _ => None, + } + } + + pub fn animation(&self) -> Option<&types::Animation> { + match &self.kind { + Common { media_kind: Animation { animation, .. }, .. } => + Some(animation), + _ => None, + } + } + + pub fn game(&self) -> Option<&types::Game> { + match &self.kind { + Common { media_kind: Game { game, .. }, .. } => Some(game), + _ => None, + } + } + + pub fn photo(&self) -> Option<&[PhotoSize]> { + match &self.kind { + Common { media_kind: Photo { photo, .. }, .. } => Some(photo), + _ => None, + } + } + + pub fn sticker(&self) -> Option<&types::Sticker> { + match &self.kind { + Common { media_kind: Sticker { sticker, .. }, .. } => + Some(sticker), + _ => None, + } + } + + pub fn video(&self) -> Option<&types::Video> { + match &self.kind { + Common { media_kind: Video { video, .. }, .. } => Some(video), + _ => None, + } + } + + pub fn voice(&self) -> Option<&types::Voice> { + match &self.kind { + Common { media_kind: Voice { voice, .. }, .. } => Some(voice), + _ => None, + } + } + + pub fn video_note(&self) -> Option<&types::VideoNote> { + match &self.kind { + Common { media_kind: VideoNote { video_note, .. }, .. } => + Some(video_note), + _ => None, + } + } + + pub fn caption(&self) -> Option<&str> { + match &self.kind { + Common { media_kind, .. } => match media_kind { + Animation { caption, ..} | + Audio { caption, ..} | + Document { caption, ..} | + Photo { caption, ..} | + Video { caption, ..} | + Voice { caption, ..} => caption.as_ref().map(Deref::deref), + _ => None, + }, + _ => None, + } + } + + pub fn contact(&self) -> Option<&types::Contact> { + match &self.kind { + Common { media_kind: Contact { contact }, .. } => Some(contact), + _ => None, + } + } + + pub fn location(&self) -> Option<&types::Location> { + match &self.kind { + Common { media_kind: Location { location, .. }, .. } => + Some(location), + _ => None, + } + } + + pub fn venue(&self) -> Option<&types::Venue> { + match &self.kind { + Common { media_kind: Venue { venue, .. }, .. } => Some(venue), + _ => None, + } + } + + pub fn poll(&self) -> Option<&types::Poll> { + match &self.kind { + Common { media_kind: Poll { poll, .. }, .. } => Some(poll), + _ => None, + } + } + + pub fn new_chat_members(&self) -> Option<&[User]> { + match &self.kind { + NewChatMembers { new_chat_members } => Some(new_chat_members), + _ => None, + } + } + + pub fn left_chat_member(&self) -> Option<&User> { + match &self.kind { + LeftChatMember { left_chat_member } => Some(left_chat_member), + _ => None, + } + } + + pub fn new_chat_title(&self) -> Option<&str> { + match &self.kind { + NewChatTitle { new_chat_title } => Some(new_chat_title), + _ => None, + } + } + + pub fn new_chat_photo(&self) -> Option<&[PhotoSize]> { + match &self.kind { + NewChatPhoto { new_chat_photo } => Some(new_chat_photo), + _ => None, + } + } + + // TODO: OK, `Option` is weird, can we do something with it? + // mb smt like `is_delete_chat_photo(&self) -> bool`? + pub fn delete_chat_photo(&self) -> Option { + match &self.kind { + DeleteChatPhoto { delete_chat_photo } => + Some(*delete_chat_photo), + _ => None, + } + } + + pub fn group_chat_created(&self) -> Option { + match &self.kind { + GroupChatCreated { group_chat_created } => + Some(*group_chat_created), + _ => None, + } + } + + pub fn super_group_chat_created(&self) -> Option { + match &self.kind { + SupergroupChatCreated { supergroup_chat_created } => + Some(*supergroup_chat_created), + _ => None, + } + } + + pub fn channel_chat_created(&self) -> Option { + match &self.kind { + ChannelChatCreated { channel_chat_created } => + Some(*channel_chat_created), + _ => None, + } + } + + pub fn migrate_to_chat_id(&self) -> Option<&i64> { + match &self.kind { + Migrate { migrate_to_chat_id, .. } => Some(migrate_to_chat_id), + _ => None, + } + } + + pub fn migrate_from_chat_id(&self) -> Option<&i64> { + match &self.kind { + Migrate { migrate_from_chat_id, .. } => + Some(migrate_from_chat_id), + _ => None, + } + } + + pub fn pinned_message(&self) -> Option<&Message> { + match &self.kind { + Pinned { pinned } => Some(pinned), + _ => None, + } + } + + pub fn invoice(&self) -> Option<&types::Invoice> { + match &self.kind { + Invoice { invoice } => Some(invoice), + _ => None, + } + } + + + pub fn successful_payment(&self) -> Option<&types::SuccessfulPayment> { + match &self.kind { + SuccessfulPayment { successful_payment } => + Some(successful_payment), + _ => None, + } + } + + + pub fn connected_website(&self) -> Option<&str> { + match &self.kind { + ConnectedWebsite { connected_website } => + Some(connected_website), + _ => None, + } + } + + + pub fn passport_data(&self) -> Option<&types::PassportData> { + match &self.kind { + PassportData { passport_data } => Some(passport_data), + _ => None, + } + } + + + pub fn reply_markup(&self) -> Option<&types::InlineKeyboardMarkup> { + match &self.kind { + Common { reply_markup, .. } => reply_markup.as_ref(), + _ => None, + } + } + } +} + + #[cfg(test)] mod tests { use serde_json::from_str;