use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmbedAuthor {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmbedFooter {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmbedImage {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmbedField {
pub name: String,
pub value: String,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub inline: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub inputs: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_options: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Embed {
#[serde(skip_serializing_if = "Option::is_none")]
pub color: 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 author: Option<EmbedAuthor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub thumbnail: Option<EmbedImage>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub fields: Vec<EmbedField>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image: Option<EmbedImage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub footer: Option<EmbedFooter>,
}
impl Embed {
pub fn new() -> Self {
Self::default()
}
pub fn color(mut self, hex: impl Into<String>) -> Self {
self.color = Some(hex.into());
self
}
pub fn title(mut self, t: impl Into<String>) -> Self {
self.title = Some(t.into());
self
}
pub fn url(mut self, u: impl Into<String>) -> Self {
self.url = Some(u.into());
self
}
pub fn description(mut self, d: impl Into<String>) -> Self {
self.description = Some(d.into());
self
}
pub fn timestamp(mut self, ts: impl Into<String>) -> Self {
self.timestamp = Some(ts.into());
self
}
pub fn image(mut self, url: impl Into<String>) -> Self {
self.image = Some(EmbedImage {
url: url.into(),
..Default::default()
});
self
}
pub fn image_sized(mut self, url: impl Into<String>, w: u32, h: u32) -> Self {
self.image = Some(EmbedImage {
url: url.into(),
width: Some(w),
height: Some(h),
});
self
}
pub fn thumbnail(mut self, url: impl Into<String>) -> Self {
self.thumbnail = Some(EmbedImage {
url: url.into(),
..Default::default()
});
self
}
pub fn footer(mut self, text: impl Into<String>, icon_url: Option<&str>) -> Self {
self.footer = Some(EmbedFooter {
text: text.into(),
icon_url: icon_url.map(|s| s.to_owned()),
});
self
}
pub fn author(
mut self,
name: impl Into<String>,
icon_url: Option<&str>,
url: Option<&str>,
) -> Self {
self.author = Some(EmbedAuthor {
name: name.into(),
icon_url: icon_url.map(|s| s.to_owned()),
url: url.map(|s| s.to_owned()),
});
self
}
pub fn field(
mut self,
name: impl Into<String>,
value: impl Into<String>,
inline: bool,
) -> Self {
self.fields.push(EmbedField {
name: name.into(),
value: value.into(),
inline,
..Default::default()
});
self
}
pub fn build(self) -> Value {
serde_json::to_value(self).unwrap_or(Value::Null)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn embed_basic_fields() {
let v = Embed::new()
.title("Test")
.description("Desc")
.color("#ff0000")
.build();
assert_eq!(v["title"], "Test");
assert_eq!(v["description"], "Desc");
assert_eq!(v["color"], "#ff0000");
}
#[test]
fn embed_with_field() {
let v = Embed::new().field("Key", "Value", true).build();
let fields = v["fields"].as_array().unwrap();
assert_eq!(fields.len(), 1);
assert_eq!(fields[0]["name"], "Key");
assert!(fields[0]["inline"].as_bool().unwrap());
}
}