titanium_model/builder/
message.rs

1use crate::{Component, CreateMessage, Embed, TitanString};
2
3/// Builder for creating a Message.
4#[derive(Debug, Clone, Default)]
5#[must_use]
6pub struct MessageBuilder<'a> {
7    message: CreateMessage<'a>,
8}
9
10impl<'a> MessageBuilder<'a> {
11    /// Create a new `MessageBuilder`.
12    #[inline]
13    pub fn new() -> Self {
14        Self::default()
15    }
16
17    /// Create a message with just text content.
18    #[inline]
19    pub fn text(content: impl Into<TitanString<'a>>) -> Self {
20        Self::new().content(content)
21    }
22
23    /// Set the content of the message.
24    #[inline]
25    pub fn content(mut self, content: impl Into<TitanString<'a>>) -> Self {
26        self.message.content = Some(content.into());
27        self
28    }
29
30    /// Enable/disable TTS.
31    pub fn tts(mut self, tts: bool) -> Self {
32        self.message.tts = Some(tts);
33        self
34    }
35
36    /// Reply to a message (sets `message_reference`).
37    pub fn reply(mut self, message_id: impl Into<crate::Snowflake>) -> Self {
38        self.message.message_reference = Some(crate::MessageReference {
39            message_id: Some(message_id.into()),
40            channel_id: None,
41            guild_id: None,
42            fail_if_not_exists: Some(true),
43        });
44        self
45    }
46
47    /// Add an embed to the message.
48    pub fn embed(mut self, embed: impl Into<Embed<'a>>) -> Self {
49        if let Some(embeds) = &mut self.message.embeds {
50            embeds.push(embed.into());
51        } else {
52            self.message.embeds = Some(vec![embed.into()]);
53        }
54        self
55    }
56
57    /// Add multiple embeds.
58    pub fn embeds(mut self, embeds: Vec<Embed<'a>>) -> Self {
59        if let Some(existing) = &mut self.message.embeds {
60            existing.extend(embeds);
61        } else {
62            self.message.embeds = Some(embeds);
63        }
64        self
65    }
66
67    /// Add a component (`ActionRow`, etc.) to the message.
68    pub fn component(mut self, component: impl Into<Component<'a>>) -> Self {
69        if let Some(components) = &mut self.message.components {
70            components.push(component.into());
71        } else {
72            self.message.components = Some(vec![component.into()]);
73        }
74        self
75    }
76
77    /// Add a file to upload.
78    pub fn add_file(
79        mut self,
80        filename: impl Into<TitanString<'a>>,
81        data: impl Into<Vec<u8>>,
82    ) -> Self {
83        self.message
84            .files
85            .push(crate::create_message::FileUpload::new(
86                filename.into().into_owned(),
87                data,
88            ));
89        self
90    }
91
92    /// Build the `CreateMessage` payload.
93    #[must_use]
94    pub fn build(self) -> CreateMessage<'a> {
95        self.message
96    }
97}
98
99/// `MessageBuilder` automatically converts to `CreateMessage`
100impl<'a> From<MessageBuilder<'a>> for CreateMessage<'a> {
101    #[inline]
102    fn from(builder: MessageBuilder<'a>) -> Self {
103        builder.build()
104    }
105}
106
107/// String automatically converts to `CreateMessage`
108impl From<String> for CreateMessage<'static> {
109    fn from(content: String) -> Self {
110        MessageBuilder::text(content).build()
111    }
112}
113
114/// &str automatically converts to `CreateMessage`
115impl<'a> From<&'a str> for CreateMessage<'a> {
116    fn from(content: &'a str) -> Self {
117        MessageBuilder::text(content).build()
118    }
119}