use twilight_model::{
application::command::CommandOptionChoice,
channel::message::{AllowedMentions, Component, Embed, MessageFlags},
http::{attachment::Attachment, interaction::InteractionResponseData},
poll::Poll,
};
#[derive(Clone, Debug)]
#[must_use = "builders have no effect if unused"]
pub struct InteractionResponseDataBuilder(InteractionResponseData);
impl InteractionResponseDataBuilder {
pub const fn new() -> Self {
Self(InteractionResponseData {
allowed_mentions: None,
attachments: None,
choices: None,
components: None,
content: None,
custom_id: None,
embeds: None,
flags: None,
title: None,
tts: None,
poll: None,
})
}
#[allow(clippy::missing_const_for_fn)]
#[must_use = "builders have no effect if unused"]
pub fn build(self) -> InteractionResponseData {
self.0
}
#[allow(clippy::missing_const_for_fn)]
pub fn allowed_mentions(mut self, allowed_mentions: AllowedMentions) -> Self {
self.0.allowed_mentions = Some(allowed_mentions);
self
}
pub fn attachments(mut self, attachments: impl IntoIterator<Item = Attachment>) -> Self {
self.0.attachments = Some(attachments.into_iter().collect());
self
}
pub fn choices(mut self, choices: impl IntoIterator<Item = CommandOptionChoice>) -> Self {
self.0.choices = Some(choices.into_iter().collect());
self
}
pub fn components(mut self, components: impl IntoIterator<Item = Component>) -> Self {
self.0.components = Some(components.into_iter().collect());
self
}
pub fn content(mut self, content: impl Into<String>) -> Self {
self.0.content = Some(content.into());
self
}
pub fn custom_id(mut self, custom_id: impl Into<String>) -> Self {
self.0.custom_id = Some(custom_id.into());
self
}
pub fn embeds(mut self, embeds: impl IntoIterator<Item = Embed>) -> Self {
self.0.embeds = Some(embeds.into_iter().collect());
self
}
pub const fn flags(mut self, flags: MessageFlags) -> Self {
self.0.flags = Some(flags);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.0.title = Some(title.into());
self
}
pub const fn tts(mut self, value: bool) -> Self {
self.0.tts = Some(value);
self
}
pub fn poll(mut self, poll: Poll) -> Self {
self.0.poll = Some(poll);
self
}
}
impl Default for InteractionResponseDataBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use static_assertions::assert_impl_all;
use std::fmt::Debug;
use twilight_model::{
channel::message::{
MentionType,
component::{Button, ButtonStyle},
},
poll::{PollLayoutType, PollMedia},
util::Timestamp,
};
assert_impl_all!(
InteractionResponseDataBuilder: Clone,
Debug,
Default,
Send,
Sync
);
#[test]
fn callback_data_builder() {
let allowed_mentions = AllowedMentions {
parse: Vec::from([MentionType::Everyone]),
..Default::default()
};
let component = Component::Button(Button {
style: ButtonStyle::Primary,
emoji: None,
label: Some("test label".into()),
custom_id: Some("test custom id".into()),
url: None,
disabled: false,
sku_id: None,
id: None,
});
let embed = 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(Timestamp::from_secs(1_580_608_922).unwrap()),
title: Some("a title".to_owned()),
url: Some("https://example.com".to_owned()),
video: None,
};
let poll = Poll {
answers: vec![],
allow_multiselect: false,
expiry: None,
layout_type: PollLayoutType::Default,
question: PollMedia {
emoji: None,
text: Some("lorem ipsum".to_owned()),
},
results: None,
};
let value = InteractionResponseDataBuilder::new()
.allowed_mentions(allowed_mentions.clone())
.components([component.clone()])
.content("a content")
.embeds([embed.clone()])
.flags(MessageFlags::empty())
.tts(false)
.poll(poll.clone())
.build();
let expected = InteractionResponseData {
allowed_mentions: Some(allowed_mentions),
attachments: None,
choices: None,
components: Some(vec![component]),
content: Some("a content".to_owned()),
custom_id: None,
embeds: Some(vec![embed]),
flags: Some(MessageFlags::empty()),
title: None,
tts: Some(false),
poll: Some(poll),
};
assert_eq!(value, expected);
}
}