Skip to content

Commit 04e3912

Browse files
committed
Change Embed::fields to use FixedArray (#2674)
`Embed::fields` previously had to stay as a `Vec` due to `CreateEmbed` wrapping around it, but by implementing `Serialize` manually we can overwrite the `Embed::fields` with a normal `Vec`, for a small performance hit on serialization while saving some space for all stored `Embed`s.
1 parent 45b3638 commit 04e3912

File tree

2 files changed

+55
-36
lines changed

2 files changed

+55
-36
lines changed

src/builder/create_embed.rs

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,22 @@ use crate::model::prelude::*;
2121
/// A builder to create an embed in a message
2222
///
2323
/// [Discord docs](https://discord.com/developers/docs/resources/channel#embed-object)
24-
#[derive(Clone, Debug, Serialize, PartialEq)]
24+
#[derive(Clone, Debug, PartialEq)]
2525
#[must_use]
26-
pub struct CreateEmbed(Embed);
26+
pub struct CreateEmbed {
27+
inner: Embed,
28+
fields: Vec<EmbedField>,
29+
}
30+
31+
impl serde::Serialize for CreateEmbed {
32+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
33+
let owned_self = self.clone();
34+
35+
let mut embed = owned_self.inner;
36+
embed.fields = owned_self.fields.into();
37+
embed.serialize(serializer)
38+
}
39+
}
2740

2841
impl CreateEmbed {
2942
/// Equivalent to [`Self::default`].
@@ -35,7 +48,7 @@ impl CreateEmbed {
3548
///
3649
/// Refer to the documentation for [`CreateEmbedAuthor`] for more information.
3750
pub fn author(mut self, author: CreateEmbedAuthor) -> Self {
38-
self.0.author = Some(author.0);
51+
self.inner.author = Some(author.0);
3952
self
4053
}
4154

@@ -50,7 +63,7 @@ impl CreateEmbed {
5063
/// Set the colour of the left-hand side of the embed.
5164
#[inline]
5265
pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
53-
self.0.colour = Some(colour.into());
66+
self.inner.colour = Some(colour.into());
5467
self
5568
}
5669

@@ -59,7 +72,7 @@ impl CreateEmbed {
5972
/// **Note**: This can't be longer than 4096 characters.
6073
#[inline]
6174
pub fn description(mut self, description: impl Into<String>) -> Self {
62-
self.0.description = Some(description.into().into());
75+
self.inner.description = Some(description.into().into());
6376
self
6477
}
6578

@@ -74,7 +87,7 @@ impl CreateEmbed {
7487
value: impl Into<String>,
7588
inline: bool,
7689
) -> Self {
77-
self.0.fields.push(EmbedField::new(name, value, inline));
90+
self.fields.push(EmbedField::new(name, value, inline));
7891
self
7992
}
8093

@@ -88,22 +101,22 @@ impl CreateEmbed {
88101
{
89102
let fields =
90103
fields.into_iter().map(|(name, value, inline)| EmbedField::new(name, value, inline));
91-
self.0.fields.extend(fields);
104+
self.fields.extend(fields);
92105
self
93106
}
94107

95108
/// Set the footer of the embed.
96109
///
97110
/// Refer to the documentation for [`CreateEmbedFooter`] for more information.
98111
pub fn footer(mut self, footer: CreateEmbedFooter) -> Self {
99-
self.0.footer = Some(footer.0);
112+
self.inner.footer = Some(footer.0);
100113
self
101114
}
102115

103116
/// Set the image associated with the embed. This only supports HTTP(S).
104117
#[inline]
105118
pub fn image(mut self, url: impl Into<String>) -> Self {
106-
self.0.image = Some(EmbedImage {
119+
self.inner.image = Some(EmbedImage {
107120
url: url.into().into(),
108121
proxy_url: None,
109122
height: None,
@@ -115,7 +128,7 @@ impl CreateEmbed {
115128
/// Set the thumbnail of the embed. This only supports HTTP(S).
116129
#[inline]
117130
pub fn thumbnail(mut self, url: impl Into<String>) -> Self {
118-
self.0.thumbnail = Some(EmbedThumbnail {
131+
self.inner.thumbnail = Some(EmbedThumbnail {
119132
url: url.into().into(),
120133
proxy_url: None,
121134
height: None,
@@ -140,21 +153,21 @@ impl CreateEmbed {
140153
/// ```
141154
#[inline]
142155
pub fn timestamp<T: Into<Timestamp>>(mut self, timestamp: T) -> Self {
143-
self.0.timestamp = Some(timestamp.into());
156+
self.inner.timestamp = Some(timestamp.into());
144157
self
145158
}
146159

147160
/// Set the title of the embed.
148161
#[inline]
149162
pub fn title(mut self, title: impl Into<String>) -> Self {
150-
self.0.title = Some(title.into().into());
163+
self.inner.title = Some(title.into().into());
151164
self
152165
}
153166

154167
/// Set the URL to direct to when clicking on the title.
155168
#[inline]
156169
pub fn url(mut self, url: impl Into<String>) -> Self {
157-
self.0.url = Some(url.into().into());
170+
self.inner.url = Some(url.into().into());
158171
self
159172
}
160173

@@ -174,24 +187,24 @@ impl CreateEmbed {
174187
#[cfg(feature = "http")]
175188
pub(super) fn check_length(&self) -> Result<()> {
176189
let mut length = 0;
177-
if let Some(ref author) = self.0.author {
190+
if let Some(ref author) = self.inner.author {
178191
length += author.name.chars().count();
179192
}
180193

181-
if let Some(ref description) = self.0.description {
194+
if let Some(ref description) = self.inner.description {
182195
length += description.chars().count();
183196
}
184197

185-
for field in &self.0.fields {
198+
for field in &self.fields {
186199
length += field.name.chars().count();
187200
length += field.value.chars().count();
188201
}
189202

190-
if let Some(ref footer) = self.0.footer {
203+
if let Some(ref footer) = self.inner.footer {
191204
length += footer.text.chars().count();
192205
}
193206

194-
if let Some(ref title) = self.0.title {
207+
if let Some(ref title) = self.inner.title {
195208
length += title.chars().count();
196209
}
197210

@@ -203,27 +216,33 @@ impl CreateEmbed {
203216
impl Default for CreateEmbed {
204217
/// Creates a builder with default values, setting the `type` to `rich`.
205218
fn default() -> Self {
206-
Self(Embed {
219+
Self {
207220
fields: Vec::new(),
208-
description: None,
209-
thumbnail: None,
210-
timestamp: None,
211-
kind: Some("rich".to_string().into()),
212-
author: None,
213-
colour: None,
214-
footer: None,
215-
image: None,
216-
title: None,
217-
url: None,
218-
video: None,
219-
provider: None,
220-
})
221+
inner: Embed {
222+
fields: FixedArray::new(),
223+
description: None,
224+
thumbnail: None,
225+
timestamp: None,
226+
kind: Some("rich".to_string().into()),
227+
author: None,
228+
colour: None,
229+
footer: None,
230+
image: None,
231+
title: None,
232+
url: None,
233+
video: None,
234+
provider: None,
235+
},
236+
}
221237
}
222238
}
223239

224240
impl From<Embed> for CreateEmbed {
225-
fn from(embed: Embed) -> Self {
226-
Self(embed)
241+
fn from(mut embed: Embed) -> Self {
242+
Self {
243+
fields: std::mem::take(&mut embed.fields).into_vec(),
244+
inner: embed,
245+
}
227246
}
228247
}
229248

src/model/channel/embed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ pub struct Embed {
6666
///
6767
/// The maximum number of fields is 25.
6868
#[serde(default)]
69-
#[serde(skip_serializing_if = "Vec::is_empty")]
70-
pub fields: Vec<EmbedField>,
69+
#[serde(skip_serializing_if = "FixedArray::is_empty")]
70+
pub fields: FixedArray<EmbedField, u8>,
7171
}
7272

7373
/// An author object in an embed.

0 commit comments

Comments
 (0)