tbot/types/input_file/
animation.rs

1use super::{InputFile, Thumb};
2use crate::types::{
3    file,
4    parameters::{ParseMode, Text},
5};
6use serde::ser::SerializeMap;
7
8/// Represents an animation to be sent.
9#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
10#[must_use]
11pub struct Animation<'a> {
12    pub(crate) media: InputFile<'a>,
13    pub(crate) thumb: Option<Thumb<'a>>,
14    pub(crate) caption: Option<&'a str>,
15    pub(crate) parse_mode: Option<ParseMode>,
16    pub(crate) width: Option<u32>,
17    pub(crate) height: Option<u32>,
18    pub(crate) duration: Option<u32>,
19}
20
21impl<'a> Animation<'a> {
22    const fn new(media: InputFile<'a>) -> Self {
23        Self {
24            media,
25            thumb: None,
26            caption: None,
27            parse_mode: None,
28            width: None,
29            height: None,
30            duration: None,
31        }
32    }
33
34    /// Constructs an `Animation` from bytes.
35    pub fn with_bytes(bytes: &'a [u8]) -> Self {
36        Self::new(InputFile::File {
37            filename: "animation.mp4",
38            bytes,
39        })
40    }
41
42    #[doc(hidden)]
43    #[deprecated(
44        since = "0.6.6",
45        note = "this method is renamed to `with_bytes`"
46    )]
47    pub fn bytes(bytes: &'a [u8]) -> Self {
48        Self::with_bytes(bytes)
49    }
50
51    /// Constructs an `Animation` from a file ID.
52    /// # Panics
53    ///
54    /// Panicks if the ID starts with `attach://`.
55    pub fn with_id(id: file::id::Ref<'a>) -> Self {
56        assert!(
57            !id.0.starts_with("attach://"),
58            "\n[tbot] Animations's ID cannot start with `attach://`\n",
59        );
60
61        Self::new(InputFile::Id(id.0))
62    }
63
64    #[doc(hidden)]
65    #[deprecated(
66        since = "0.6.6",
67        note = "use `with_id` which takes a `file::id::Ref<'a>`"
68    )]
69    pub fn id(id: &'a str) -> Self {
70        Self::with_id(file::id::Ref(id))
71    }
72
73    /// Constructs an `Animation` from an URL.
74    ///
75    /// # Panics
76    ///
77    /// Panicks if the URL starts with `attach://`.
78    pub fn with_url(url: &'a str) -> Self {
79        assert!(
80            !url.starts_with("attach://"),
81            "\n[tbot] Animation's URL cannot start with `attach://`\n",
82        );
83
84        Self::new(InputFile::Url(url))
85    }
86
87    #[doc(hidden)]
88    #[deprecated(
89        since = "0.6.6",
90        note = "this method is renamed to `with_url`"
91    )]
92    pub fn url(url: &'a str) -> Self {
93        Self::with_url(url)
94    }
95
96    /// Configures `thumb`.
97    pub fn thumb(mut self, thumb: Thumb<'a>) -> Self {
98        self.thumb = Some(thumb);
99        self
100    }
101
102    /// Configures `caption`.
103    pub fn caption(mut self, caption: impl Into<Text<'a>>) -> Self {
104        let caption = caption.into();
105
106        self.caption = Some(caption.text);
107        self.parse_mode = caption.parse_mode;
108        self
109    }
110
111    /// Configures `duration`.
112    pub fn duration(mut self, duration: u32) -> Self {
113        self.duration = Some(duration);
114        self
115    }
116
117    /// Configures `width`.
118    pub fn width(mut self, width: u32) -> Self {
119        self.width = Some(width);
120        self
121    }
122
123    /// Configures `height`.
124    pub fn height(mut self, height: u32) -> Self {
125        self.height = Some(height);
126        self
127    }
128}
129
130impl<'a> serde::Serialize for Animation<'a> {
131    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
132        let mut map = s.serialize_map(None)?;
133
134        map.serialize_entry("type", "animation")?;
135        map.serialize_entry("media", &self.media.with_name("animation"))?;
136
137        if let Some(thumb) = &self.thumb {
138            map.serialize_entry("thumb", &thumb)?;
139        }
140        if let Some(caption) = self.caption {
141            map.serialize_entry("caption", caption)?;
142        }
143        if let Some(parse_mode) = self.parse_mode {
144            map.serialize_entry("parse_mode", &parse_mode)?;
145        }
146        if let Some(width) = self.width {
147            map.serialize_entry("width", &width)?;
148        }
149        if let Some(height) = self.height {
150            map.serialize_entry("height", &height)?;
151        }
152        if let Some(duration) = self.duration {
153            map.serialize_entry("duration", &duration)?;
154        }
155
156        map.end()
157    }
158}