From 8b4ac2260be04f7cd4ef53ef046e0fc39f3ca011 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 18 Jul 2022 18:55:05 +0400 Subject: [PATCH] Add `StickerKind` --- CHANGELOG.md | 3 ++ src/types/sticker.rs | 114 +++++++++++++++++++++++++++++++++++---- src/types/sticker_set.rs | 33 ++++++++---- 3 files changed, 131 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 271b4386..e8dc5913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `InlineKeyboardButton::{pay, login, web_app, callback_game, pay}` constructors ([#231][pr231]) - Support for Telegram Bot API [version 6.1](https://core.telegram.org/bots/api#june-20-2022) ([#233][pr233]) +- `StickerKind` that is now used instead of `is_animated` and `is_video` fields of `Sticker` and `StickerSet` ([#238][pr238]) + +[pr238]: https://github.com/teloxide/teloxide-core/pull/238 ### Fixed diff --git a/src/types/sticker.rs b/src/types/sticker.rs index 4066350b..2862699d 100644 --- a/src/types/sticker.rs +++ b/src/types/sticker.rs @@ -1,3 +1,5 @@ +use std::{convert::TryFrom, ops::Deref}; + use serde::{Deserialize, Serialize}; use crate::types::{File, MaskPosition, PhotoSize}; @@ -22,15 +24,9 @@ pub struct Sticker { /// Sticker height. pub height: u16, - /// `true`, if the sticker is [animated]. - /// - /// [animated]: https://telegram.org/blog/animated-stickers - pub is_animated: bool, - - /// `true`, if the sticker is a [video sticker]. - /// - /// [video sticker]: https://telegram.org/blog/video-stickers-better-reactions - pub is_video: bool, + /// Kind of this sticker - webp, animated or video. + #[serde(flatten)] + pub kind: StickerKind, /// Sticker thumbnail in the .webp or .jpg format. pub thumb: Option, @@ -50,3 +46,103 @@ pub struct Sticker { /// File size in bytes. pub file_size: Option, } + +/// Kind of a sticker - webp, animated or video. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(try_from = "StickerKindRaw", into = "StickerKindRaw")] +pub enum StickerKind { + /// "Normal", raster sticker. + Webp, + /// [Animated] sticker. + /// + /// [Animated]: https://telegram.org/blog/animated-stickers + Animated, + /// [Video] sticker. + /// + /// [Video]: https://telegram.org/blog/video-stickers-better-reactions + Video, +} + +/// This allows calling [`StickerKind`]'s methods directly on [`Sticker`]. +/// +/// ```no_run +/// use teloxide_core::types::Sticker; +/// +/// let sticker: Sticker = todo!(); +/// +/// let _ = sticker.is_video(); +/// let _ = sticker.kind.is_video(); +/// ``` +impl Deref for Sticker { + type Target = StickerKind; + + fn deref(&self) -> &Self::Target { + &self.kind + } +} + +impl StickerKind { + /// Returns `true` is this is a "normal" raster sticker. + pub fn is_webp(&self) -> bool { + matches!(self, Self::Webp) + } + + /// Returns `true` is this is an [animated] sticker. + /// + /// [animated]: https://telegram.org/blog/animated-stickers + pub fn is_animated(&self) -> bool { + matches!(self, Self::Animated) + } + + /// Returns `true` is this is a [video] sticker. + /// + /// [video]: https://telegram.org/blog/video-stickers-better-reactions + pub fn is_video(&self) -> bool { + matches!(self, Self::Video) + } +} + +#[derive(Serialize, Deserialize)] +struct StickerKindRaw { + is_animated: bool, + is_video: bool, +} + +impl TryFrom for StickerKind { + type Error = &'static str; + + fn try_from( + StickerKindRaw { + is_animated, + is_video, + }: StickerKindRaw, + ) -> Result { + let ret = match (is_animated, is_video) { + (false, false) => Self::Webp, + (true, false) => Self::Animated, + (false, true) => Self::Video, + (true, true) => return Err("`is_animated` and `is_video` present at the same time"), + }; + + Ok(ret) + } +} + +impl From for StickerKindRaw { + fn from(kind: StickerKind) -> Self { + match kind { + StickerKind::Webp => Self { + is_animated: false, + is_video: false, + }, + StickerKind::Animated => Self { + is_animated: true, + is_video: false, + }, + StickerKind::Video => Self { + is_animated: false, + is_video: true, + }, + } + } +} diff --git a/src/types/sticker_set.rs b/src/types/sticker_set.rs index 3150518e..e666c1c8 100644 --- a/src/types/sticker_set.rs +++ b/src/types/sticker_set.rs @@ -1,6 +1,8 @@ +use std::ops::Deref; + use serde::{Deserialize, Serialize}; -use crate::types::{PhotoSize, Sticker}; +use crate::types::{PhotoSize, Sticker, StickerKind}; /// This object represents a sticker set. /// @@ -13,15 +15,8 @@ pub struct StickerSet { /// Sticker set title. pub title: String, - /// `true`, if the sticker set contains [animated stickers]. - /// - /// [animates stickers]: https://telegram.org/blog/animated-stickers - pub is_animated: bool, - - /// `true`, if the sticker is a [video sticker]. - /// - /// [video sticker]: https://telegram.org/blog/video-stickers-better-reactions - pub is_video: bool, + /// Sticker kind shared by all stickers in this set. + pub kind: StickerKind, /// `true`, if the sticker set contains masks. pub contains_masks: bool, @@ -32,3 +27,21 @@ pub struct StickerSet { /// Sticker set thumbnail in the .WEBP or .TGS format. pub thumb: Option, } + +/// This allows calling [`StickerKind`]'s methods directly on [`StickerSet`]. +/// +/// ```no_run +/// use teloxide_core::types::StickerSet; +/// +/// let sticker: StickerSet = todo!(); +/// +/// let _ = sticker.is_video(); +/// let _ = sticker.kind.is_video(); +/// ``` +impl Deref for StickerSet { + type Target = StickerKind; + + fn deref(&self) -> &Self::Target { + &self.kind + } +}