noob/
builder.rs

1use Error;
2
3use serde_json;
4
5/// Object used to construct outgoing messages
6pub struct MessageBuilder<'a> {
7    content: &'a str,
8    embed: Option<&'a EmbedBuilder<'a>>,
9}
10
11impl<'a> MessageBuilder<'a> {
12    /// Create a new MessageBuilder
13    pub fn new(content: &'a str) -> Self {
14        Self {
15            content,
16            embed: None,
17        }
18    }
19
20    /// Set an embed for this message
21    pub fn set_embed(&mut self, embed: &'a EmbedBuilder<'a>) {
22        self.embed = Some(embed);
23    }
24
25    /// Set an embed for this message
26    pub fn with_embed(mut self, embed: &'a EmbedBuilder<'a>) -> Self {
27        self.set_embed(embed);
28        self
29    }
30
31    #[doc(hidden)]
32    pub fn to_request_body(&self, channel: &str) -> Result<String, Error> {
33        #[derive(Serialize, Debug)]
34        struct MessageCreateBody<'a> {
35            content: &'a str,
36            channel: &'a str,
37            embed: Option<&'a EmbedBuilder<'a>>,
38        }
39        serde_json::to_string(&MessageCreateBody {
40            content: self.content,
41            channel,
42            embed: self.embed,
43        }).map_err(|e| {
44            Error::Other(format!(
45                "Failed to serialize message creation body: {:?}",
46                e
47            ))
48        })
49    }
50}
51
52#[derive(Default, Serialize, Debug)]
53/// Builder for a message embed
54pub struct EmbedBuilder<'a> {
55    title: Option<&'a str>,
56    description: Option<&'a str>,
57    url: Option<&'a str>,
58    timestamp: Option<&'a str>,
59    color: Option<u32>,
60    footer: Option<&'a EmbedFooter<'a>>,
61    image: Option<&'a str>,
62    thumbnail: Option<&'a str>,
63    author: Option<&'a EmbedAuthor<'a>>,
64    fields: Vec<&'a EmbedField<'a>>,
65}
66
67#[allow(missing_docs)]
68impl<'a> EmbedBuilder<'a> {
69    pub fn new() -> Self {
70        Default::default()
71    }
72
73    pub fn set_title(&mut self, title: &'a str) {
74        self.title = Some(title);
75    }
76
77    pub fn with_title(mut self, title: &'a str) -> Self {
78        self.set_title(title);
79        self
80    }
81
82    pub fn set_author(&mut self, author: &'a EmbedAuthor<'a>) {
83        self.author = Some(author);
84    }
85
86    pub fn with_author(mut self, author: &'a EmbedAuthor<'a>) -> Self {
87        self.set_author(author);
88        self
89    }
90
91    pub fn set_color(&mut self, color: u32) {
92        self.color = Some(color);
93    }
94
95    pub fn with_color(mut self, color: u32) -> Self {
96        self.set_color(color);
97        self
98    }
99
100    pub fn add_field(&mut self, field: &'a EmbedField<'a>) {
101        self.fields.push(field);
102    }
103
104    pub fn with_field(mut self, field: &'a EmbedField<'a>) -> Self {
105        self.add_field(field);
106        self
107    }
108
109    pub fn set_footer(&mut self, footer: &'a EmbedFooter<'a>) {
110        self.footer = Some(footer);
111    }
112
113    pub fn with_footer(mut self, footer: &'a EmbedFooter<'a>) -> Self {
114        self.set_footer(footer);
115        self
116    }
117
118    pub fn set_description(&mut self, description: &'a str) {
119        self.description = Some(description);
120    }
121
122    pub fn with_description(mut self, description: &'a str) -> Self {
123        self.set_description(description);
124        self
125    }
126
127    pub fn set_timestamp(&mut self, timestamp: &'a str) {
128        self.timestamp = Some(timestamp);
129    }
130
131    pub fn with_timestamp(mut self, timestamp: &'a str) -> Self {
132        self.set_timestamp(timestamp);
133        self
134    }
135}
136
137#[derive(Default, Serialize, Debug)]
138/// Representation of an embed author
139pub struct EmbedAuthor<'a> {
140    /// Name of author
141    pub name: Option<&'a str>,
142    /// URL of author
143    pub url: Option<&'a str>,
144    /// URL of author icon
145    pub icon_url: Option<&'a str>,
146}
147
148impl<'a> EmbedAuthor<'a> {
149    /// Create an empty embed author
150    pub fn new() -> Self {
151        Default::default()
152    }
153}
154
155#[derive(Serialize, Debug)]
156/// Representation of an embed footer
157pub struct EmbedFooter<'a> {
158    text: &'a str,
159    icon_url: Option<&'a str>,
160}
161
162impl<'a> EmbedFooter<'a> {
163    /// Create a text-only footer
164    pub fn new(text: &'a str) -> Self {
165        EmbedFooter {
166            text,
167            icon_url: None,
168        }
169    }
170    /// Create a footer with an icon
171    pub fn new_with_icon(text: &'a str, icon_url: &'a str) -> Self {
172        EmbedFooter {
173            text,
174            icon_url: Some(icon_url),
175        }
176    }
177}
178
179#[derive(Serialize, Debug)]
180/// Representation of an [embed field](https://discordapp.com/developers/docs/resources/channel#embed-object-embed-field-structure)
181pub struct EmbedField<'a> {
182    name: &'a str,
183    value: &'a str,
184    inline: bool,
185}
186
187impl<'a> EmbedField<'a> {
188    /// Create a new embed field
189    pub fn new(name: &'a str, value: &'a str) -> Self {
190        EmbedField::new_internal(name, value, false)
191    }
192    /// Create a new inline embed field
193    pub fn new_inline(name: &'a str, value: &'a str) -> Self {
194        EmbedField::new_internal(name, value, true)
195    }
196    fn new_internal(name: &'a str, value: &'a str, inline: bool) -> Self {
197        EmbedField {
198            name,
199            value,
200            inline,
201        }
202    }
203}