Skip to main content

twilight_model/channel/
attachment.rs

1use super::AttachmentFlags;
2use crate::{
3    id::{Id, marker::AttachmentMarker},
4    util::is_false,
5};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
9pub struct Attachment {
10    /// Attachment's [media type].
11    ///
12    /// [media type]: https://en.wikipedia.org/wiki/Media_type
13    pub content_type: Option<String>,
14    /// Whether this attachment is ephemeral.
15    ///
16    /// Ephemeral attachments will automatically be removed after a set period
17    /// of time. Ephemeral attachments on messages are guaranteed to be
18    /// available as long as the message itself exists.
19    #[serde(default, skip_serializing_if = "is_false")]
20    pub ephemeral: bool,
21    /// Duration of the audio file (currently for voice messages).
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub duration_secs: Option<f64>,
24    pub filename: String,
25    // Flags for this attachment.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub flags: Option<AttachmentFlags>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub description: Option<String>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub height: Option<u64>,
32    pub id: Id<AttachmentMarker>,
33    /// A [thumbhash](https://evanw.github.io/thumbhash) placeholder of the
34    /// image or video.
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub placeholder: Option<String>,
37    /// Version of the placeholder.
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub placeholder_version: Option<u64>,
40    pub proxy_url: String,
41    pub size: u64,
42    /// The title of the file.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub title: Option<String>,
45    pub url: String,
46    /// Base64 encoded bytearray representing a sampled waveform (currently for voice messages).
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub waveform: Option<String>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub width: Option<u64>,
51}
52
53#[cfg(test)]
54mod tests {
55    use super::Attachment;
56    use crate::{channel::AttachmentFlags, id::Id};
57    use serde::{Deserialize, Serialize};
58    use serde_test::Token;
59    use static_assertions::{assert_fields, assert_impl_all};
60    use std::fmt::Debug;
61
62    assert_fields!(
63        Attachment: content_type,
64        ephemeral,
65        filename,
66        height,
67        id,
68        proxy_url,
69        size,
70        url,
71        width
72    );
73
74    assert_impl_all!(
75        Attachment: Clone,
76        Debug,
77        Deserialize<'static>,
78        PartialEq,
79        Serialize
80    );
81
82    #[test]
83    fn attachment() {
84        let value = Attachment {
85            content_type: Some("image/png".to_owned()),
86            ephemeral: false,
87            filename: "a.png".to_owned(),
88            flags: Some(AttachmentFlags::IS_SPOILER),
89            description: Some("a image".to_owned()),
90            duration_secs: Some(3.2),
91            height: Some(184),
92            id: Id::new(700_000_000_000_000_000),
93            // Thumbhash of the twilight project logo.
94            placeholder: Some("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg".to_owned()),
95            placeholder_version: Some(1),
96            proxy_url: "https://cdn.example.com/1.png".to_owned(),
97            size: 13_593,
98            title: Some("a title".to_owned()),
99            url: "https://example.com/1.png".to_owned(),
100            waveform: Some(String::from("waveform")),
101            width: Some(184),
102        };
103
104        serde_test::assert_tokens(
105            &value,
106            &[
107                Token::Struct {
108                    name: "Attachment",
109                    len: 15,
110                },
111                Token::Str("content_type"),
112                Token::Some,
113                Token::Str("image/png"),
114                Token::Str("duration_secs"),
115                Token::Some,
116                Token::F64(3.2),
117                Token::Str("filename"),
118                Token::Str("a.png"),
119                Token::Str("flags"),
120                Token::Some,
121                Token::U64(8),
122                Token::Str("description"),
123                Token::Some,
124                Token::Str("a image"),
125                Token::Str("height"),
126                Token::Some,
127                Token::U64(184),
128                Token::Str("id"),
129                Token::NewtypeStruct { name: "Id" },
130                Token::Str("700000000000000000"),
131                Token::Str("placeholder"),
132                Token::Some,
133                Token::Str("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg"),
134                Token::Str("placeholder_version"),
135                Token::Some,
136                Token::U64(1),
137                Token::Str("proxy_url"),
138                Token::Str("https://cdn.example.com/1.png"),
139                Token::Str("size"),
140                Token::U64(13_593),
141                Token::Str("title"),
142                Token::Some,
143                Token::Str("a title"),
144                Token::Str("url"),
145                Token::Str("https://example.com/1.png"),
146                Token::Str("waveform"),
147                Token::Some,
148                Token::Str("waveform"),
149                Token::Str("width"),
150                Token::Some,
151                Token::U64(184),
152                Token::StructEnd,
153            ],
154        );
155    }
156}