discord_webhook_rs/
embed.rs1use super::Author;
2use super::Error;
3use super::Field;
4use super::Footer;
5
6use serde_json::{Value, json};
7
8pub struct Embed {
9 author: Option<Author>,
10 title: Option<String>,
11 url: Option<String>,
12 description: Option<String>,
13 color: Option<u32>,
14 fields: Vec<Field>,
15 thumbnail: Option<String>,
16 image: Option<String>,
17 footer: Option<Footer>,
18}
19
20impl Embed {
21 pub fn new() -> Self {
22 Embed {
23 author: None,
24 title: None,
25 url: None,
26 description: None,
27 color: None,
28 fields: Vec::new(),
29 thumbnail: None,
30 image: None,
31 footer: None,
32 }
33 }
34
35 pub fn author(mut self, author: Author) -> Self {
36 self.author = Some(author);
37 self
38 }
39
40 pub fn title(mut self, title: impl Into<String>) -> Self {
41 self.title = Some(title.into());
42 self
43 }
44
45 pub fn url(mut self, url: impl Into<String>) -> Self {
46 self.url = Some(url.into());
47 self
48 }
49
50 pub fn description(mut self, description: impl Into<String>) -> Self {
51 self.description = Some(description.into());
52 self
53 }
54
55 pub fn color(mut self, color: u32) -> Self {
56 self.color = Some(color);
57 self
58 }
59
60 pub fn add_field(mut self, field: Field) -> Self {
61 self.fields.push(field);
62 self
63 }
64
65 pub fn thumbnail(mut self, thumbnail: impl Into<String>) -> Self {
66 self.thumbnail = Some(thumbnail.into());
67 self
68 }
69
70 pub fn image(mut self, image: impl Into<String>) -> Self {
71 self.image = Some(image.into());
72 self
73 }
74
75 pub fn footer(mut self, footer: Footer) -> Self {
76 self.footer = Some(footer);
77 self
78 }
79
80 fn verify(&self) -> Result<(), Error> {
81 if let Some(title) = &self.title {
82 if title.len() > 256 {
83 return Err(Error::MaxContent);
84 }
85 }
86
87 if let Some(description) = &self.description {
88 if description.len() > 4096 {
89 return Err(Error::MaxContent);
90 }
91 }
92
93 if let Some(color) = self.color {
94 if color > (1 << 8 * 3) - 1 {
96 return Err(Error::InvalidColor);
97 }
98 }
99
100 if self.fields.len() > 25 {
101 return Err(Error::MaxField);
102 }
103
104 Ok(())
105 }
106
107 pub fn build(&self) -> Result<Value, Error> {
108 self.verify()?;
109
110 let mut obj = serde_json::Map::new();
111
112 if let Some(author) = &self.author {
113 obj.insert("author".into(), author.build()?);
114 }
115
116 if let Some(footer) = &self.footer {
117 obj.insert("footer".into(), footer.build()?);
118 }
119
120 if let Some(title) = &self.title {
121 obj.insert("title".into(), Value::String(title.clone()));
122 }
123
124 if let Some(url) = &self.url {
125 obj.insert("url".into(), Value::String(url.clone()));
126 }
127
128 if let Some(description) = &self.description {
129 obj.insert("description".into(), Value::String(description.clone()));
130 }
131
132 if let Some(color) = &self.color {
133 obj.insert("color".into(), json!(color));
134 }
135
136 if let Some(thumbnail) = &self.thumbnail {
137 obj.insert("thumbnail".into(), json!({"url": thumbnail}));
138 }
139
140 if let Some(image) = &self.image {
141 obj.insert("image".into(), json!({"url": image}));
142 }
143
144 obj.insert("fields".into(), Value::Array(Vec::new()));
145 if let Value::Array(ref mut fields) = obj["fields"] {
146 for field in &self.fields {
147 fields.push(field.build()?);
148 }
149 };
150
151 if obj.contains_key("author")
153 || obj.contains_key("footer")
154 || obj.contains_key("title")
155 || obj.contains_key("description")
156 || obj.contains_key("thumbnail")
157 || obj.contains_key("image")
158 || self.fields.len() > 0
159 {
160 Ok(Value::Object(obj))
161 } else {
162 Err(Error::InvalidEmbed)
163 }
164 }
165}