1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
mod author;
mod field;
mod footer;
mod image;
mod provider;
mod thumbnail;
mod video;

pub use self::{
    author::EmbedAuthor, field::EmbedField, footer::EmbedFooter, image::EmbedImage,
    provider::EmbedProvider, thumbnail::EmbedThumbnail, video::EmbedVideo,
};

use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct Embed {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub author: Option<EmbedAuthor>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub color: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub fields: Vec<EmbedField>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub footer: Option<EmbedFooter>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub image: Option<EmbedImage>,
    #[serde(rename = "type")]
    pub kind: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub provider: Option<EmbedProvider>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub thumbnail: Option<EmbedThumbnail>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timestamp: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub video: Option<EmbedVideo>,
}

#[cfg(test)]
mod tests {
    use super::{
        Embed, EmbedAuthor, EmbedField, EmbedFooter, EmbedImage, EmbedProvider, EmbedThumbnail,
        EmbedVideo,
    };
    use serde_test::Token;

    #[test]
    fn test_embed() {
        let value = Embed {
            author: None,
            color: Some(123),
            description: Some("a description".to_owned()),
            fields: Vec::new(),
            footer: None,
            image: None,
            kind: "rich".to_owned(),
            provider: None,
            thumbnail: None,
            timestamp: Some("a timestamp".to_owned()),
            title: Some("a title".to_owned()),
            url: Some("https://example.com".to_owned()),
            video: None,
        };

        serde_test::assert_tokens(
            &value,
            &[
                Token::Struct {
                    name: "Embed",
                    len: 6,
                },
                Token::Str("color"),
                Token::Some,
                Token::U32(123),
                Token::Str("description"),
                Token::Some,
                Token::Str("a description"),
                Token::Str("type"),
                Token::Str("rich"),
                Token::Str("timestamp"),
                Token::Some,
                Token::Str("a timestamp"),
                Token::Str("title"),
                Token::Some,
                Token::Str("a title"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com"),
                Token::StructEnd,
            ],
        );
    }

    #[allow(clippy::too_many_lines)]
    #[test]
    fn test_embed_complete() {
        let value = Embed {
            author: Some(EmbedAuthor {
                icon_url: Some("https://example.com/1.png".to_owned()),
                name: Some("test".to_owned()),
                proxy_icon_url: Some("https://example.com".to_owned()),
                url: Some("https://example.com".to_owned()),
            }),
            color: Some(123),
            description: Some("a description".to_owned()),
            fields: vec![EmbedField {
                inline: true,
                name: "name".to_owned(),
                value: "value".to_owned(),
            }],
            footer: Some(EmbedFooter {
                icon_url: Some("https://example.com/1.png".to_owned()),
                proxy_icon_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
                text: "a footer".to_owned(),
            }),
            image: Some(EmbedImage {
                height: Some(1440),
                proxy_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
                url: Some("https://example.com/1.png".to_owned()),
                width: Some(2560),
            }),
            kind: "rich".to_owned(),
            provider: Some(EmbedProvider {
                name: Some("Example".to_owned()),
                url: Some("https://example.com".to_owned()),
            }),
            thumbnail: Some(EmbedThumbnail {
                height: Some(1440),
                proxy_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
                url: Some("https://example.com/1.png".to_owned()),
                width: Some(2560),
            }),
            timestamp: Some("a timestamp".to_owned()),
            title: Some("a title".to_owned()),
            url: Some("https://example.com".to_owned()),
            video: Some(EmbedVideo {
                height: Some(1440),
                proxy_url: Some("https://proxy.cdn.example.com/1-hash.mp4".to_owned()),
                url: Some("https://cdn.example.com/1-hash.mp4".to_owned()),
                width: Some(2560),
            }),
        };

        serde_test::assert_tokens(
            &value,
            &[
                Token::Struct {
                    name: "Embed",
                    len: 13,
                },
                Token::Str("author"),
                Token::Some,
                Token::Struct {
                    name: "EmbedAuthor",
                    len: 4,
                },
                Token::Str("icon_url"),
                Token::Some,
                Token::Str("https://example.com/1.png"),
                Token::Str("name"),
                Token::Some,
                Token::Str("test"),
                Token::Str("proxy_icon_url"),
                Token::Some,
                Token::Str("https://example.com"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com"),
                Token::StructEnd,
                Token::Str("color"),
                Token::Some,
                Token::U32(123),
                Token::Str("description"),
                Token::Some,
                Token::Str("a description"),
                Token::Str("fields"),
                Token::Seq { len: Some(1) },
                Token::Struct {
                    name: "EmbedField",
                    len: 3,
                },
                Token::Str("inline"),
                Token::Bool(true),
                Token::Str("name"),
                Token::Str("name"),
                Token::Str("value"),
                Token::Str("value"),
                Token::StructEnd,
                Token::SeqEnd,
                Token::Str("footer"),
                Token::Some,
                Token::Struct {
                    name: "EmbedFooter",
                    len: 3,
                },
                Token::Str("icon_url"),
                Token::Some,
                Token::Str("https://example.com/1.png"),
                Token::Str("proxy_icon_url"),
                Token::Some,
                Token::Str("https://cdn.example.com/1-hash.png"),
                Token::Str("text"),
                Token::Str("a footer"),
                Token::StructEnd,
                Token::Str("image"),
                Token::Some,
                Token::Struct {
                    name: "EmbedImage",
                    len: 4,
                },
                Token::Str("height"),
                Token::Some,
                Token::U64(1440),
                Token::Str("proxy_url"),
                Token::Some,
                Token::Str("https://cdn.example.com/1-hash.png"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com/1.png"),
                Token::Str("width"),
                Token::Some,
                Token::U64(2560),
                Token::StructEnd,
                Token::Str("type"),
                Token::Str("rich"),
                Token::Str("provider"),
                Token::Some,
                Token::Struct {
                    name: "EmbedProvider",
                    len: 2,
                },
                Token::Str("name"),
                Token::Some,
                Token::Str("Example"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com"),
                Token::StructEnd,
                Token::Str("thumbnail"),
                Token::Some,
                Token::Struct {
                    name: "EmbedThumbnail",
                    len: 4,
                },
                Token::Str("height"),
                Token::Some,
                Token::U64(1440),
                Token::Str("proxy_url"),
                Token::Some,
                Token::Str("https://cdn.example.com/1-hash.png"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com/1.png"),
                Token::Str("width"),
                Token::Some,
                Token::U64(2560),
                Token::StructEnd,
                Token::Str("timestamp"),
                Token::Some,
                Token::Str("a timestamp"),
                Token::Str("title"),
                Token::Some,
                Token::Str("a title"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://example.com"),
                Token::Str("video"),
                Token::Some,
                Token::Struct {
                    name: "EmbedVideo",
                    len: 4,
                },
                Token::Str("height"),
                Token::Some,
                Token::U64(1440),
                Token::Str("proxy_url"),
                Token::Some,
                Token::Str("https://proxy.cdn.example.com/1-hash.mp4"),
                Token::Str("url"),
                Token::Some,
                Token::Str("https://cdn.example.com/1-hash.mp4"),
                Token::Str("width"),
                Token::Some,
                Token::U64(2560),
                Token::StructEnd,
                Token::StructEnd,
            ],
        );
    }
}