1use crate::{
4 Component, CreateMessage, Embed, EmbedAuthor, EmbedField, EmbedFooter, EmbedMedia, TitanString,
5};
6
7#[derive(Debug, Clone, Default)]
9pub struct EmbedBuilder<'a> {
10 embed: Embed<'a>,
11}
12
13impl<'a> EmbedBuilder<'a> {
14 #[inline]
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 #[inline]
22 pub fn title(mut self, title: impl Into<TitanString<'a>>) -> Self {
23 self.embed.title = Some(title.into());
24 self
25 }
26
27 pub fn description(mut self, description: impl Into<TitanString<'a>>) -> Self {
29 self.embed.description = Some(description.into());
30 self
31 }
32
33 pub fn url(mut self, url: impl Into<TitanString<'a>>) -> Self {
35 self.embed.url = Some(url.into());
36 self
37 }
38
39 pub fn timestamp(mut self, timestamp: impl Into<TitanString<'a>>) -> Self {
41 self.embed.timestamp = Some(timestamp.into());
42 self
43 }
44
45 pub fn color(mut self, color: u32) -> Self {
47 self.embed.color = Some(color);
48 self
49 }
50
51 pub fn color_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
53 self.embed.color = Some(((r as u32) << 16) | ((g as u32) << 8) | (b as u32));
54 self
55 }
56
57 pub fn footer(
59 mut self,
60 text: impl Into<TitanString<'a>>,
61 icon_url: Option<impl Into<TitanString<'a>>>,
62 ) -> Self {
63 self.embed.footer = Some(EmbedFooter {
64 text: text.into(),
65 icon_url: icon_url.map(Into::into),
66 proxy_icon_url: None,
67 });
68 self
69 }
70
71 pub fn image(mut self, url: impl Into<TitanString<'a>>) -> Self {
73 self.embed.image = Some(EmbedMedia {
74 url: Some(url.into()),
75 proxy_url: None,
76 height: None,
77 width: None,
78 });
79 self
80 }
81
82 pub fn thumbnail(mut self, url: impl Into<TitanString<'a>>) -> Self {
84 self.embed.thumbnail = Some(EmbedMedia {
85 url: Some(url.into()),
86 proxy_url: None,
87 height: None,
88 width: None,
89 });
90 self
91 }
92
93 pub fn author(
95 mut self,
96 name: impl Into<TitanString<'a>>,
97 url: Option<impl Into<TitanString<'a>>>,
98 icon_url: Option<impl Into<TitanString<'a>>>,
99 ) -> Self {
100 self.embed.author = Some(EmbedAuthor {
101 name: name.into(),
102 url: url.map(Into::into),
103 icon_url: icon_url.map(Into::into),
104 proxy_icon_url: None,
105 });
106 self
107 }
108
109 pub fn field(
111 mut self,
112 name: impl Into<TitanString<'a>>,
113 value: impl Into<TitanString<'a>>,
114 inline: bool,
115 ) -> Self {
116 self.embed.fields.push(EmbedField {
117 name: name.into(),
118 value: value.into(),
119 inline,
120 });
121 self
122 }
123
124 pub fn field_inline(
126 self,
127 name: impl Into<TitanString<'a>>,
128 value: impl Into<TitanString<'a>>,
129 ) -> Self {
130 self.field(name, value, true)
131 }
132
133 pub fn field_block(
135 self,
136 name: impl Into<TitanString<'a>>,
137 value: impl Into<TitanString<'a>>,
138 ) -> Self {
139 self.field(name, value, false)
140 }
141
142 pub fn build(self) -> Embed<'a> {
144 self.embed
145 }
146}
147
148#[derive(Debug, Clone, Default)]
150pub struct MessageBuilder<'a> {
151 message: CreateMessage<'a>,
152}
153
154impl<'a> MessageBuilder<'a> {
155 #[inline]
157 pub fn new() -> Self {
158 Self::default()
159 }
160
161 #[inline]
163 pub fn content(mut self, content: impl Into<TitanString<'a>>) -> Self {
164 self.message.content = Some(content.into());
165 self
166 }
167
168 pub fn tts(mut self, tts: bool) -> Self {
170 self.message.tts = Some(tts);
171 self
172 }
173
174 pub fn reply(mut self, message_id: impl Into<crate::Snowflake>) -> Self {
176 self.message.message_reference = Some(crate::MessageReference {
177 message_id: Some(message_id.into()),
178 channel_id: None,
179 guild_id: None,
180 fail_if_not_exists: Some(true),
181 });
182 self
183 }
184
185 pub fn embed(mut self, embed: impl Into<Embed<'a>>) -> Self {
187 if let Some(embeds) = &mut self.message.embeds {
188 embeds.push(embed.into());
189 } else {
190 self.message.embeds = Some(vec![embed.into()]);
191 }
192 self
193 }
194
195 pub fn embeds(mut self, embeds: Vec<Embed<'a>>) -> Self {
197 if let Some(existing) = &mut self.message.embeds {
198 existing.extend(embeds);
199 } else {
200 self.message.embeds = Some(embeds);
201 }
202 self
203 }
204
205 pub fn component(mut self, component: impl Into<Component<'a>>) -> Self {
207 if let Some(components) = &mut self.message.components {
208 components.push(component.into());
209 } else {
210 self.message.components = Some(vec![component.into()]);
211 }
212 self
213 }
214
215 pub fn add_file(
217 mut self,
218 filename: impl Into<TitanString<'a>>,
219 data: impl Into<Vec<u8>>,
220 ) -> Self {
221 self.message.files.push(crate::file::FileUpload::new(
222 filename.into().into_owned(),
223 data,
224 ));
225 self
226 }
227
228 pub fn build(self) -> CreateMessage<'a> {
230 self.message
231 }
232}
233
234#[derive(Debug, Clone, serde::Serialize, Default)]
240pub struct ModifyGuild<'a> {
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub name: Option<TitanString<'a>>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub region: Option<TitanString<'a>>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub verification_level: Option<u8>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub default_message_notifications: Option<u8>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub explicit_content_filter: Option<u8>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub afk_channel_id: Option<crate::Snowflake>,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub afk_timeout: Option<u32>,
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub icon: Option<TitanString<'a>>,
257 #[serde(skip_serializing_if = "Option::is_none")]
258 pub owner_id: Option<crate::Snowflake>,
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub splash: Option<TitanString<'a>>,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub discovery_splash: Option<TitanString<'a>>,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub banner: Option<TitanString<'a>>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub system_channel_id: Option<crate::Snowflake>,
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub system_channel_flags: Option<u64>,
269 #[serde(skip_serializing_if = "Option::is_none")]
270 pub rules_channel_id: Option<crate::Snowflake>,
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub public_updates_channel_id: Option<crate::Snowflake>,
273 #[serde(skip_serializing_if = "Option::is_none")]
274 pub preferred_locale: Option<TitanString<'a>>,
275 #[serde(skip_serializing_if = "Option::is_none")]
276 pub features: Option<Vec<TitanString<'a>>>,
277 #[serde(skip_serializing_if = "Option::is_none")]
278 pub description: Option<TitanString<'a>>,
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub premium_progress_bar_enabled: Option<bool>,
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub safety_alerts_channel_id: Option<crate::Snowflake>,
283}
284
285#[derive(Debug, Clone, Default)]
287pub struct ModifyGuildBuilder<'a> {
288 params: ModifyGuild<'a>,
289}
290
291impl<'a> ModifyGuildBuilder<'a> {
292 pub fn new() -> Self {
294 Self::default()
295 }
296
297 pub fn name(mut self, name: impl Into<TitanString<'a>>) -> Self {
299 self.params.name = Some(name.into());
300 self
301 }
302
303 pub fn region(mut self, region: impl Into<TitanString<'a>>) -> Self {
305 self.params.region = Some(region.into());
306 self
307 }
308
309 pub fn verification_level(mut self, level: u8) -> Self {
311 self.params.verification_level = Some(level);
312 self
313 }
314
315 pub fn default_message_notifications(mut self, level: u8) -> Self {
317 self.params.default_message_notifications = Some(level);
318 self
319 }
320
321 pub fn explicit_content_filter(mut self, level: u8) -> Self {
323 self.params.explicit_content_filter = Some(level);
324 self
325 }
326
327 pub fn afk_channel_id(mut self, id: impl Into<crate::Snowflake>) -> Self {
329 self.params.afk_channel_id = Some(id.into());
330 self
331 }
332
333 pub fn afk_timeout(mut self, timeout: u32) -> Self {
335 self.params.afk_timeout = Some(timeout);
336 self
337 }
338
339 pub fn icon(mut self, icon: impl Into<TitanString<'a>>) -> Self {
341 self.params.icon = Some(icon.into());
342 self
343 }
344
345 pub fn system_channel_id(mut self, id: impl Into<crate::Snowflake>) -> Self {
347 self.params.system_channel_id = Some(id.into());
348 self
349 }
350
351 pub fn build(self) -> ModifyGuild<'a> {
353 self.params
354 }
355}
356
357#[derive(Debug, Clone, serde::Serialize, Default)]
363pub struct ModifyMember<'a> {
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub nick: Option<TitanString<'a>>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub roles: Option<Vec<crate::Snowflake>>,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub mute: Option<bool>,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub deaf: Option<bool>,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 pub channel_id: Option<crate::Snowflake>, #[serde(skip_serializing_if = "Option::is_none")]
375 pub communication_disabled_until: Option<TitanString<'a>>, #[serde(skip_serializing_if = "Option::is_none")]
377 pub flags: Option<u64>,
378}
379
380#[derive(Debug, Clone, Default)]
382pub struct ModifyMemberBuilder<'a> {
383 params: ModifyMember<'a>,
384}
385
386impl<'a> ModifyMemberBuilder<'a> {
387 pub fn new() -> Self {
389 Self::default()
390 }
391
392 pub fn nick(mut self, nick: impl Into<TitanString<'a>>) -> Self {
394 self.params.nick = Some(nick.into());
395 self
396 }
397
398 pub fn roles(mut self, roles: Vec<crate::Snowflake>) -> Self {
400 self.params.roles = Some(roles);
401 self
402 }
403
404 pub fn mute(mut self, mute: bool) -> Self {
406 self.params.mute = Some(mute);
407 self
408 }
409
410 pub fn deaf(mut self, deaf: bool) -> Self {
412 self.params.deaf = Some(deaf);
413 self
414 }
415
416 pub fn move_to_channel(mut self, channel_id: impl Into<crate::Snowflake>) -> Self {
418 self.params.channel_id = Some(channel_id.into());
419 self
420 }
421
422 pub fn timeout_until(mut self, timestamp: impl Into<TitanString<'a>>) -> Self {
424 self.params.communication_disabled_until = Some(timestamp.into());
425 self
426 }
427
428 pub fn build(self) -> ModifyMember<'a> {
430 self.params
431 }
432}
433
434#[derive(Debug, Clone, serde::Serialize, Default)]
440pub struct StartThread<'a> {
441 pub name: TitanString<'a>,
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub auto_archive_duration: Option<u32>,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub type_: Option<u8>, #[serde(skip_serializing_if = "Option::is_none")]
447 pub invitable: Option<bool>,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub rate_limit_per_user: Option<u32>,
450}
451
452#[derive(Debug, Clone)]
454pub struct StartThreadBuilder<'a> {
455 params: StartThread<'a>,
456}
457
458impl<'a> StartThreadBuilder<'a> {
459 pub fn new(name: impl Into<TitanString<'a>>) -> Self {
461 Self {
462 params: StartThread {
463 name: name.into(),
464 ..Default::default()
465 },
466 }
467 }
468
469 pub fn auto_archive_duration(mut self, duration: u32) -> Self {
471 self.params.auto_archive_duration = Some(duration);
472 self
473 }
474
475 pub fn kind(mut self, kind: u8) -> Self {
477 self.params.type_ = Some(kind);
478 self
479 }
480
481 pub fn invitable(mut self, invitable: bool) -> Self {
483 self.params.invitable = Some(invitable);
484 self
485 }
486
487 pub fn rate_limit_per_user(mut self, limit: u32) -> Self {
489 self.params.rate_limit_per_user = Some(limit);
490 self
491 }
492
493 pub fn build(self) -> StartThread<'a> {
495 self.params
496 }
497}
498
499#[derive(Debug, Clone)]
505pub struct ButtonBuilder<'a> {
506 component: crate::Component<'a>,
507}
508
509impl<'a> ButtonBuilder<'a> {
510 #[inline]
512 pub fn new() -> Self {
513 Self {
514 component: crate::Component::Button(crate::component::Button {
515 style: crate::component::ButtonStyle::Primary, label: None,
517 emoji: None,
518 custom_id: None,
519 url: None,
520 disabled: false,
521 component_type: crate::component::ComponentType::Button,
522 }),
523 }
524 }
525
526 pub fn style(mut self, style: crate::component::ButtonStyle) -> Self {
528 if let crate::Component::Button(b) = &mut self.component {
529 b.style = style;
530 }
531 self
532 }
533
534 pub fn label(mut self, label: impl Into<TitanString<'a>>) -> Self {
536 if let crate::Component::Button(b) = &mut self.component {
537 b.label = Some(label.into());
538 }
539 self
540 }
541
542 pub fn emoji(mut self, emoji: impl Into<crate::reaction::ReactionEmoji<'a>>) -> Self {
544 if let crate::Component::Button(b) = &mut self.component {
545 b.emoji = Some(emoji.into());
546 }
547 self
548 }
549
550 pub fn custom_id(mut self, id: impl Into<TitanString<'a>>) -> Self {
552 if let crate::Component::Button(b) = &mut self.component {
553 b.custom_id = Some(id.into());
554 }
555 self
556 }
557
558 pub fn url(mut self, url: impl Into<TitanString<'a>>) -> Self {
560 if let crate::Component::Button(b) = &mut self.component {
561 b.url = Some(url.into());
562 }
563 self
564 }
565
566 pub fn disabled(mut self, disabled: bool) -> Self {
568 if let crate::Component::Button(b) = &mut self.component {
569 b.disabled = disabled;
570 }
571 self
572 }
573
574 pub fn build(self) -> crate::Component<'a> {
576 self.component
577 }
578}
579
580#[derive(Debug, Clone)]
582pub struct SelectMenuBuilder<'a> {
583 component: crate::Component<'a>,
584}
585
586impl<'a> SelectMenuBuilder<'a> {
587 #[inline]
589 pub fn new(custom_id: impl Into<TitanString<'a>>) -> Self {
590 Self {
591 component: crate::Component::SelectMenu(crate::component::SelectMenu {
592 custom_id: custom_id.into(),
593 options: Vec::with_capacity(25), placeholder: None,
595 min_values: None,
596 max_values: None,
597 disabled: false,
598 component_type: crate::component::ComponentType::StringSelect, }),
600 }
601 }
602
603 pub fn option(
605 mut self,
606 label: impl Into<TitanString<'a>>,
607 value: impl Into<TitanString<'a>>,
608 ) -> Self {
609 if let crate::Component::SelectMenu(s) = &mut self.component {
610 s.options.push(crate::component::SelectOption {
611 label: label.into(),
612 value: value.into(),
613 description: None,
614 emoji: None,
615 default: false,
616 });
617 }
618 self
619 }
620
621 pub fn placeholder(mut self, placeholder: impl Into<TitanString<'a>>) -> Self {
623 if let crate::Component::SelectMenu(s) = &mut self.component {
624 s.placeholder = Some(placeholder.into());
625 }
626 self
627 }
628
629 pub fn min_values(mut self, min: u8) -> Self {
631 if let crate::Component::SelectMenu(s) = &mut self.component {
632 s.min_values = Some(min);
633 }
634 self
635 }
636
637 pub fn max_values(mut self, max: u8) -> Self {
639 if let crate::Component::SelectMenu(s) = &mut self.component {
640 s.max_values = Some(max);
641 }
642 self
643 }
644
645 pub fn disabled(mut self, disabled: bool) -> Self {
647 if let crate::Component::SelectMenu(s) = &mut self.component {
648 s.disabled = disabled;
649 }
650 self
651 }
652
653 pub fn build(self) -> crate::Component<'a> {
655 self.component
656 }
657}
658
659#[derive(Debug, Clone)]
661pub struct ActionRowBuilder<'a> {
662 component: crate::Component<'a>,
663}
664
665impl<'a> ActionRowBuilder<'a> {
666 pub fn new() -> Self {
667 Self {
668 component: crate::Component::ActionRow(crate::component::ActionRow {
669 components: Vec::with_capacity(5), component_type: crate::component::ComponentType::ActionRow,
671 }),
672 }
673 }
674
675 pub fn add_button(mut self, button: ButtonBuilder<'a>) -> Self {
676 if let crate::Component::ActionRow(r) = &mut self.component {
677 r.components.push(button.build());
678 }
679 self
680 }
681
682 pub fn add_select_menu(mut self, menu: SelectMenuBuilder<'a>) -> Self {
683 if let crate::Component::ActionRow(r) = &mut self.component {
684 r.components.push(menu.build());
685 }
686 self
687 }
688
689 pub fn build(self) -> crate::Component<'a> {
690 self.component
691 }
692
693 pub fn input(mut self, input: TextInputBuilder<'a>) -> Self {
694 if let crate::Component::ActionRow(r) = &mut self.component {
695 r.components.push(input.build());
696 }
697 self
698 }
699}
700
701#[derive(Debug, Clone)]
703pub struct ModalBuilder<'a> {
704 custom_id: TitanString<'a>,
705 title: TitanString<'a>,
706 components: Vec<crate::Component<'a>>,
707}
708
709impl<'a> ModalBuilder<'a> {
710 pub fn new(custom_id: impl Into<TitanString<'a>>, title: impl Into<TitanString<'a>>) -> Self {
711 Self {
712 custom_id: custom_id.into(),
713 title: title.into(),
714 components: Vec::new(),
715 }
716 }
717
718 pub fn row(mut self, row: ActionRowBuilder<'a>) -> Self {
719 self.components.push(row.build());
720 self
721 }
722
723 pub fn build(self) -> crate::interaction::Modal<'a> {
724 crate::interaction::Modal {
725 custom_id: self.custom_id,
726 title: self.title,
727 components: self.components,
728 }
729 }
730}
731
732#[derive(Debug, Clone)]
734pub struct TextInputBuilder<'a> {
735 component: crate::Component<'a>,
736}
737
738impl<'a> TextInputBuilder<'a> {
739 pub fn new(
740 custom_id: impl Into<TitanString<'a>>,
741 style: crate::component::TextInputStyle,
742 label: impl Into<TitanString<'a>>,
743 ) -> Self {
744 Self {
745 component: crate::Component::TextInput(crate::component::TextInput {
746 component_type: crate::component::ComponentType::TextInput,
747 custom_id: custom_id.into(),
748 style,
749 label: label.into(),
750 min_length: None,
751 max_length: None,
752 required: None,
753 value: None,
754 placeholder: None,
755 }),
756 }
757 }
758
759 pub fn min_length(mut self, min: u16) -> Self {
760 if let crate::Component::TextInput(t) = &mut self.component {
761 t.min_length = Some(min);
762 }
763 self
764 }
765
766 pub fn max_length(mut self, max: u16) -> Self {
767 if let crate::Component::TextInput(t) = &mut self.component {
768 t.max_length = Some(max);
769 }
770 self
771 }
772
773 pub fn required(mut self, required: bool) -> Self {
774 if let crate::Component::TextInput(t) = &mut self.component {
775 t.required = Some(required);
776 }
777 self
778 }
779
780 pub fn value(mut self, value: impl Into<TitanString<'a>>) -> Self {
781 if let crate::Component::TextInput(t) = &mut self.component {
782 t.value = Some(value.into());
783 }
784 self
785 }
786
787 pub fn placeholder(mut self, placeholder: impl Into<TitanString<'a>>) -> Self {
788 if let crate::Component::TextInput(t) = &mut self.component {
789 t.placeholder = Some(placeholder.into());
790 }
791 self
792 }
793
794 pub fn build(self) -> crate::Component<'a> {
795 self.component
796 }
797}
798
799#[derive(Debug, Clone)]
801pub struct InteractionResponseBuilder<'a> {
802 response: crate::interaction::InteractionResponse<'a>,
803}
804
805impl<'a> Default for InteractionResponseBuilder<'a> {
806 fn default() -> Self {
807 Self::new()
808 }
809}
810
811impl<'a> InteractionResponseBuilder<'a> {
812 pub fn new() -> Self {
814 Self {
815 response: crate::interaction::InteractionResponse {
816 response_type:
817 crate::interaction::InteractionCallbackType::ChannelMessageWithSource,
818 data: Some(Default::default()),
819 },
820 }
821 }
822
823 pub fn kind(mut self, kind: crate::interaction::InteractionCallbackType) -> Self {
824 self.response.response_type = kind;
825 self
826 }
827
828 pub fn content(mut self, content: impl Into<TitanString<'a>>) -> Self {
829 if let Some(data) = &mut self.response.data {
830 data.content = Some(content.into());
831 }
832 self
833 }
834
835 pub fn embed(mut self, embed: impl Into<crate::Embed<'a>>) -> Self {
836 if self.response.data.is_none() {
837 self.response.data = Some(Default::default());
838 }
839 if let Some(data) = &mut self.response.data {
840 data.embeds.push(embed.into());
841 }
842 self
843 }
844
845 pub fn build(self) -> crate::interaction::InteractionResponse<'a> {
846 self.response
847 }
848
849 pub fn modal(mut self, modal: crate::interaction::Modal<'a>) -> Self {
850 self.response.data = Some(crate::interaction::InteractionCallbackData {
851 custom_id: Some(modal.custom_id),
852 title: Some(modal.title),
853 components: modal.components,
854 ..Default::default()
855 });
856 self
857 }
858}
859
860#[derive(Debug, Clone, serde::Serialize, Default)]
867pub struct CreateChannel<'a> {
868 pub name: TitanString<'a>,
869 #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
870 pub kind: Option<u8>,
871 #[serde(skip_serializing_if = "Option::is_none")]
872 pub topic: Option<TitanString<'a>>,
873 #[serde(skip_serializing_if = "Option::is_none")]
874 pub bitrate: Option<u32>,
875 #[serde(skip_serializing_if = "Option::is_none")]
876 pub user_limit: Option<u32>,
877 #[serde(skip_serializing_if = "Option::is_none")]
878 pub rate_limit_per_user: Option<u32>,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub position: Option<u32>,
881 #[serde(skip_serializing_if = "Option::is_none")]
882 pub permission_overwrites: Option<Vec<crate::json::Value>>,
883 #[serde(skip_serializing_if = "Option::is_none")]
884 pub parent_id: Option<crate::Snowflake>,
885 #[serde(skip_serializing_if = "Option::is_none")]
886 pub nsfw: Option<bool>,
887}
888
889#[derive(Debug, Clone, Default)]
891pub struct CreateChannelBuilder<'a> {
892 params: CreateChannel<'a>,
893}
894
895impl<'a> CreateChannelBuilder<'a> {
896 pub fn new(name: impl Into<TitanString<'a>>) -> Self {
897 let mut builder = Self::default();
898 builder.params.name = name.into();
899 builder
900 }
901
902 pub fn kind(mut self, kind: u8) -> Self {
903 self.params.kind = Some(kind);
904 self
905 }
906
907 pub fn topic(mut self, topic: impl Into<TitanString<'a>>) -> Self {
908 self.params.topic = Some(topic.into());
909 self
910 }
911
912 pub fn build(self) -> CreateChannel<'a> {
913 self.params
914 }
915}
916
917#[derive(Debug, Clone, serde::Serialize, Default)]
924pub struct CreateRole<'a> {
925 #[serde(skip_serializing_if = "Option::is_none")]
926 pub name: Option<TitanString<'a>>,
927 #[serde(skip_serializing_if = "Option::is_none")]
928 pub permissions: Option<String>,
929 #[serde(skip_serializing_if = "Option::is_none")]
930 pub color: Option<u32>,
931 #[serde(skip_serializing_if = "Option::is_none")]
932 pub hoist: Option<bool>,
933 #[serde(skip_serializing_if = "Option::is_none")]
934 pub icon: Option<TitanString<'a>>,
935 #[serde(skip_serializing_if = "Option::is_none")]
936 pub unicode_emoji: Option<TitanString<'a>>,
937 #[serde(skip_serializing_if = "Option::is_none")]
938 pub mentionable: Option<bool>,
939}
940
941#[derive(Debug, Clone, Default)]
943pub struct CreateRoleBuilder<'a> {
944 params: CreateRole<'a>,
945}
946
947impl<'a> CreateRoleBuilder<'a> {
948 pub fn new() -> Self {
949 Self::default()
950 }
951
952 pub fn name(mut self, name: impl Into<TitanString<'a>>) -> Self {
953 self.params.name = Some(name.into());
954 self
955 }
956
957 pub fn color(mut self, color: u32) -> Self {
958 self.params.color = Some(color);
959 self
960 }
961
962 pub fn hoist(mut self, hoist: bool) -> Self {
963 self.params.hoist = Some(hoist);
964 self
965 }
966
967 pub fn icon(mut self, icon: impl Into<TitanString<'a>>) -> Self {
968 self.params.icon = Some(icon.into());
969 self
970 }
971
972 pub fn unicode_emoji(mut self, emoji: impl Into<TitanString<'a>>) -> Self {
973 self.params.unicode_emoji = Some(emoji.into());
974 self
975 }
976
977 pub fn mentionable(mut self, mentionable: bool) -> Self {
978 self.params.mentionable = Some(mentionable);
979 self
980 }
981
982 pub fn build(self) -> CreateRole<'a> {
983 self.params
984 }
985}
986
987#[derive(Debug, Clone, serde::Serialize)]
993pub struct CommandBuilder<'a> {
994 pub name: TitanString<'a>,
995 #[serde(skip_serializing_if = "Option::is_none")]
996 pub name_localizations: Option<std::collections::HashMap<String, String>>,
997 #[serde(skip_serializing_if = "Option::is_none")]
998 pub description: Option<TitanString<'a>>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub description_localizations: Option<std::collections::HashMap<String, String>>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub default_member_permissions: Option<TitanString<'a>>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub dm_permission: Option<bool>,
1005 #[serde(default)]
1006 #[serde(rename = "type")]
1007 pub kind: Option<crate::command::CommandType>,
1008 #[serde(skip_serializing_if = "Option::is_none")]
1009 pub nsfw: Option<bool>,
1010}
1011
1012impl<'a> CommandBuilder<'a> {
1013 pub fn new(name: impl Into<TitanString<'a>>, description: impl Into<TitanString<'a>>) -> Self {
1014 Self {
1015 name: name.into(),
1016 description: Some(description.into()),
1017 name_localizations: None,
1018 description_localizations: None,
1019 default_member_permissions: None,
1020 dm_permission: None,
1021 kind: Some(crate::command::CommandType::ChatInput),
1022 nsfw: None,
1023 }
1024 }
1025
1026 pub fn build(self) -> Self {
1027 self
1028 }
1029}
1030
1031#[derive(Debug, Clone, serde::Serialize, Default)]
1036pub struct AutoModRuleBuilder {
1037 pub name: String,
1038}
1039
1040#[derive(Debug, Clone, serde::Serialize, Default)]
1048pub struct CreateScheduledEvent<'a> {
1049 pub name: TitanString<'a>,
1050 pub privacy_level: crate::scheduled::ScheduledEventPrivacyLevel,
1051 pub scheduled_start_time: TitanString<'a>,
1052 #[serde(skip_serializing_if = "Option::is_none")]
1053 pub scheduled_end_time: Option<TitanString<'a>>,
1054 #[serde(skip_serializing_if = "Option::is_none")]
1055 pub description: Option<TitanString<'a>>,
1056 pub entity_type: crate::scheduled::ScheduledEventEntityType,
1057 #[serde(skip_serializing_if = "Option::is_none")]
1058 pub channel_id: Option<crate::Snowflake>,
1059 #[serde(skip_serializing_if = "Option::is_none")]
1060 pub entity_metadata: Option<crate::scheduled::ScheduledEventEntityMetadata<'a>>,
1061 #[serde(skip_serializing_if = "Option::is_none")]
1062 pub image: Option<TitanString<'a>>, }
1064
1065#[derive(Debug, Clone)]
1067pub struct ScheduledEventBuilder<'a> {
1068 params: CreateScheduledEvent<'a>,
1069}
1070
1071impl<'a> ScheduledEventBuilder<'a> {
1072 pub fn new(
1074 name: impl Into<TitanString<'a>>,
1075 start_time: impl Into<TitanString<'a>>,
1076 entity_type: crate::scheduled::ScheduledEventEntityType,
1077 ) -> Self {
1078 Self {
1079 params: CreateScheduledEvent {
1080 name: name.into(),
1081 scheduled_start_time: start_time.into(),
1082 entity_type,
1083 privacy_level: crate::scheduled::ScheduledEventPrivacyLevel::GuildOnly,
1084 ..Default::default()
1085 },
1086 }
1087 }
1088
1089 #[inline]
1091 pub fn description(mut self, description: impl Into<TitanString<'a>>) -> Self {
1092 self.params.description = Some(description.into());
1093 self
1094 }
1095
1096 #[inline]
1098 pub fn end_time(mut self, time: impl Into<TitanString<'a>>) -> Self {
1099 self.params.scheduled_end_time = Some(time.into());
1100 self
1101 }
1102
1103 #[inline]
1105 pub fn channel_id(mut self, id: impl Into<crate::Snowflake>) -> Self {
1106 self.params.channel_id = Some(id.into());
1107 self
1108 }
1109
1110 #[inline]
1112 pub fn location(mut self, location: impl Into<TitanString<'a>>) -> Self {
1113 self.params.entity_metadata = Some(crate::scheduled::ScheduledEventEntityMetadata {
1114 location: Some(location.into()),
1115 });
1116 self
1117 }
1118
1119 #[inline]
1121 pub fn image(mut self, image: impl Into<TitanString<'a>>) -> Self {
1122 self.params.image = Some(image.into());
1123 self
1124 }
1125
1126 #[inline]
1128 pub fn build(self) -> CreateScheduledEvent<'a> {
1129 self.params
1130 }
1131}
1132
1133#[derive(Debug, Clone)]
1135pub struct PollBuilder<'a> {
1136 poll: crate::poll::Poll<'a>,
1137}
1138
1139impl<'a> PollBuilder<'a> {
1140 pub fn new(question: impl Into<TitanString<'a>>) -> Self {
1142 Self {
1143 poll: crate::poll::Poll {
1144 question: crate::poll::PollMedia {
1145 text: Some(question.into()),
1146 emoji: None,
1147 },
1148 answers: Vec::new(),
1149 expiry: None,
1150 allow_multiselect: false,
1151 layout_type: None,
1152 results: None,
1153 },
1154 }
1155 }
1156
1157 pub fn answer(mut self, answer: impl Into<crate::poll::PollAnswer<'a>>) -> Self {
1159 self.poll.answers.push(answer.into());
1160 self
1161 }
1162
1163 pub fn expiry(mut self, expiry: impl Into<TitanString<'a>>) -> Self {
1165 self.poll.expiry = Some(expiry.into());
1166 self
1167 }
1168
1169 pub fn allow_multiselect(mut self, allow: bool) -> Self {
1171 self.poll.allow_multiselect = allow;
1172 self
1173 }
1174
1175 pub fn build(self) -> crate::poll::Poll<'a> {
1177 self.poll
1178 }
1179}
1180
1181#[derive(Debug, Clone, serde::Serialize, Default)]
1183pub struct ExecuteWebhook {
1184 #[serde(skip_serializing_if = "Option::is_none")]
1185 pub content: Option<String>,
1186 #[serde(skip_serializing_if = "Option::is_none")]
1187 pub username: Option<String>,
1188 #[serde(skip_serializing_if = "Option::is_none")]
1189 pub avatar_url: Option<String>,
1190 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub tts: Option<bool>,
1192 #[serde(skip_serializing_if = "Vec::is_empty")]
1193 pub embeds: Vec<crate::Embed<'static>>,
1194 }
1196
1197#[derive(Debug, Clone, Default)]
1199pub struct WebhookExecuteBuilder<'a> {
1200 params: ExecuteWebhook,
1201 _phantom: std::marker::PhantomData<&'a ()>,
1202}
1203
1204impl<'a> WebhookExecuteBuilder<'a> {
1205 pub fn new() -> Self {
1207 Self::default()
1208 }
1209
1210 #[inline]
1212 pub fn content(mut self, content: impl Into<String>) -> Self {
1213 self.params.content = Some(content.into());
1214 self
1215 }
1216
1217 #[inline]
1219 pub fn username(mut self, username: impl Into<String>) -> Self {
1220 self.params.username = Some(username.into());
1221 self
1222 }
1223
1224 #[inline]
1226 pub fn avatar_url(mut self, url: impl Into<String>) -> Self {
1227 self.params.avatar_url = Some(url.into());
1228 self
1229 }
1230
1231 #[inline]
1233 pub fn tts(mut self, tts: bool) -> Self {
1234 self.params.tts = Some(tts);
1235 self
1236 }
1237
1238 #[inline]
1240 pub fn embed(mut self, embed: impl Into<crate::Embed<'static>>) -> Self {
1241 self.params.embeds.push(embed.into());
1242 self
1243 }
1244
1245 #[inline]
1247 pub fn embeds(mut self, embeds: Vec<crate::Embed<'static>>) -> Self {
1248 self.params.embeds.extend(embeds);
1249 self
1250 }
1251
1252 #[inline]
1254 pub fn build(self) -> ExecuteWebhook {
1255 self.params
1256 }
1257}
1258
1259impl<'a> Default for ButtonBuilder<'a> {
1261 fn default() -> Self {
1262 Self::new()
1263 }
1264}
1265
1266impl<'a> Default for ActionRowBuilder<'a> {
1267 fn default() -> Self {
1268 Self::new()
1269 }
1270}
1271
1272impl<'a> Default for SelectMenuBuilder<'a> {
1273 fn default() -> Self {
1274 Self::new("default_select") }
1276}
1277
1278#[cfg(test)]
1279mod modify_tests {
1280 use super::*;
1281 #[test]
1282 fn test_modify_guild_builder() {
1283 let payload = ModifyGuildBuilder::new()
1284 .name("New Guild Name")
1285 .region("us-west")
1286 .verification_level(1)
1287 .build();
1288
1289 assert_eq!(
1290 payload.name,
1291 Some(TitanString::from("New Guild Name".to_string()))
1292 );
1293 assert_eq!(
1294 payload.region,
1295 Some(TitanString::from("us-west".to_string()))
1296 );
1297 assert_eq!(payload.verification_level, Some(1));
1298 }
1299
1300 #[test]
1301 fn test_modify_member_builder() {
1302 let payload = ModifyMemberBuilder::new()
1303 .nick("New Nick")
1304 .mute(true)
1305 .deaf(false)
1306 .build();
1307
1308 assert_eq!(
1309 payload.nick,
1310 Some(TitanString::from("New Nick".to_string()))
1311 );
1312 assert_eq!(payload.mute, Some(true));
1313 assert_eq!(payload.deaf, Some(false));
1314 }
1315
1316 #[test]
1317 fn test_start_thread_builder() {
1318 let payload = StartThreadBuilder::new("Thread Name")
1319 .auto_archive_duration(60)
1320 .kind(11) .build();
1322
1323 assert_eq!(payload.name, "Thread Name".to_string());
1324 assert_eq!(payload.auto_archive_duration, Some(60));
1325 assert_eq!(payload.type_, Some(11));
1326 }
1327}
1328
1329#[derive(Debug, Clone, serde::Serialize, Default)]
1335pub struct CreateInvite {
1336 #[serde(skip_serializing_if = "Option::is_none")]
1337 pub max_age: Option<u32>,
1338 #[serde(skip_serializing_if = "Option::is_none")]
1339 pub max_uses: Option<u32>,
1340 #[serde(skip_serializing_if = "Option::is_none")]
1341 pub temporary: Option<bool>,
1342 #[serde(skip_serializing_if = "Option::is_none")]
1343 pub unique: Option<bool>,
1344 #[serde(skip_serializing_if = "Option::is_none")]
1345 pub target_type: Option<u8>,
1346 #[serde(skip_serializing_if = "Option::is_none")]
1347 pub target_user_id: Option<crate::Snowflake>,
1348 #[serde(skip_serializing_if = "Option::is_none")]
1349 pub target_application_id: Option<crate::Snowflake>,
1350}
1351
1352#[derive(Debug, Clone, Default)]
1354pub struct CreateInviteBuilder {
1355 params: CreateInvite,
1356}
1357
1358impl CreateInviteBuilder {
1359 pub fn new() -> Self {
1361 Self::default()
1362 }
1363
1364 pub fn max_age(mut self, seconds: u32) -> Self {
1366 self.params.max_age = Some(seconds);
1367 self
1368 }
1369
1370 pub fn max_uses(mut self, uses: u32) -> Self {
1372 self.params.max_uses = Some(uses);
1373 self
1374 }
1375
1376 pub fn temporary(mut self, temp: bool) -> Self {
1378 self.params.temporary = Some(temp);
1379 self
1380 }
1381
1382 pub fn unique(mut self, unique: bool) -> Self {
1384 self.params.unique = Some(unique);
1385 self
1386 }
1387
1388 pub fn build(self) -> CreateInvite {
1390 self.params
1391 }
1392}
1393
1394#[derive(Debug, Clone, serde::Serialize, Default)]
1400pub struct CreateEmoji {
1401 pub name: String,
1402 pub image: String, #[serde(skip_serializing_if = "Vec::is_empty")]
1404 pub roles: Vec<crate::Snowflake>,
1405}
1406
1407#[derive(Debug, Clone)]
1409pub struct CreateEmojiBuilder {
1410 params: CreateEmoji,
1411}
1412
1413impl CreateEmojiBuilder {
1414 pub fn new(name: impl Into<String>, image_data: impl Into<String>) -> Self {
1417 Self {
1418 params: CreateEmoji {
1419 name: name.into(),
1420 image: image_data.into(),
1421 roles: Vec::new(),
1422 },
1423 }
1424 }
1425
1426 pub fn role(mut self, role_id: impl Into<crate::Snowflake>) -> Self {
1428 self.params.roles.push(role_id.into());
1429 self
1430 }
1431
1432 pub fn build(self) -> CreateEmoji {
1434 self.params
1435 }
1436}
1437
1438#[cfg(test)]
1439mod final_tests {
1440 use super::*;
1441 use crate::Mention;
1442 use crate::Snowflake; #[test]
1445 fn test_create_invite_builder() {
1446 let payload = CreateInviteBuilder::new()
1447 .max_age(86400)
1448 .max_uses(10)
1449 .unique(true)
1450 .build();
1451
1452 assert_eq!(payload.max_age, Some(86400));
1453 assert_eq!(payload.max_uses, Some(10));
1454 assert_eq!(payload.unique, Some(true));
1455 }
1456
1457 #[test]
1458 fn test_create_emoji_builder() {
1459 let payload = CreateEmojiBuilder::new("test_emoji", "data:image/png;base64,...")
1460 .role(Snowflake(12345))
1461 .build();
1462
1463 assert_eq!(payload.name, "test_emoji");
1464 assert_eq!(payload.roles.len(), 1);
1465 }
1466
1467 #[test]
1468 fn test_mention_trait() {
1469 let user = crate::User {
1470 id: Snowflake(123),
1471 username: "test".to_string().into(),
1472 discriminator: "0000".to_string().into(),
1473 global_name: None,
1474 avatar: None,
1475 bot: false,
1476 system: false,
1477 mfa_enabled: None,
1478 banner: None,
1479 accent_color: None,
1480 locale: None,
1481 verified: None,
1482 email: None,
1483 flags: None,
1484 premium_type: None,
1485 public_flags: None,
1486 avatar_decoration_data: None,
1487 };
1488
1489 let mention = user.mention();
1495 assert_eq!(mention, "<@123>");
1496 }
1497
1498 #[test]
1499 fn test_add_file_builder() {
1500 let msg = MessageBuilder::new()
1501 .content("With file")
1502 .add_file("test.txt", vec![1, 2, 3])
1503 .build();
1504
1505 assert_eq!(msg.files.len(), 1);
1506 assert_eq!(msg.files[0].filename, "test.txt");
1507 assert_eq!(msg.files[0].data, vec![1, 2, 3]);
1508 }
1509}
1510#[cfg(test)]
1511mod optimization_tests {
1512 use super::*;
1513 use TitanString;
1514
1515 #[test]
1516 fn test_embed_builder_zero_allocation() {
1517 let title = "Static Title";
1518 let embed = EmbedBuilder::new().title(title).build();
1520 match embed.title {
1521 Some(TitanString::Borrowed(t)) => assert_eq!(t, "Static Title"),
1522 _ => panic!("Expected Borrowed Cow for static string"),
1523 }
1524 }
1525
1526 #[test]
1527 fn test_embed_builder_owned() {
1528 let title = String::from("Owned Title");
1529 let embed = EmbedBuilder::new().title(title).build();
1530 match embed.title {
1531 Some(TitanString::Owned(t)) => assert_eq!(t, "Owned Title"),
1532 _ => panic!("Expected Owned Cow for String"),
1533 }
1534 }
1535
1536 #[test]
1537 fn test_component_builder_zero_allocation() {
1538 let id = "custom_id";
1539 let btn = ButtonBuilder::new().custom_id(id).build();
1540 if let crate::Component::Button(b) = btn {
1541 match b.custom_id {
1542 Some(TitanString::Borrowed(s)) => assert_eq!(s, "custom_id"),
1543 _ => panic!("Expected Borrowed Cow for button custom_id"),
1544 }
1545 }
1546 }
1547}
1548
1549#[derive(Debug, Clone, serde::Serialize, Default)]
1555pub struct CreateSticker {
1556 pub name: String,
1557 pub description: String,
1558 pub tags: String,
1559}
1560
1561#[derive(Debug, Clone)]
1563pub struct CreateStickerBuilder {
1564 params: CreateSticker,
1565}
1566
1567impl CreateStickerBuilder {
1568 pub fn new(
1570 name: impl Into<String>,
1571 description: impl Into<String>,
1572 tags: impl Into<String>,
1573 ) -> Self {
1574 Self {
1575 params: CreateSticker {
1576 name: name.into(),
1577 description: description.into(),
1578 tags: tags.into(),
1579 },
1580 }
1581 }
1582
1583 pub fn build(self) -> CreateSticker {
1585 self.params
1586 }
1587}
1588
1589#[derive(Debug, Clone, serde::Serialize, Default)]
1595pub struct ModifyEmoji {
1596 #[serde(skip_serializing_if = "Option::is_none")]
1597 pub name: Option<String>,
1598 #[serde(skip_serializing_if = "Option::is_none")]
1599 pub roles: Option<Vec<crate::Snowflake>>,
1600}
1601
1602#[derive(Debug, Clone, Default)]
1604pub struct ModifyEmojiBuilder {
1605 params: ModifyEmoji,
1606}
1607
1608impl ModifyEmojiBuilder {
1609 pub fn new() -> Self {
1611 Self::default()
1612 }
1613
1614 pub fn name(mut self, name: impl Into<String>) -> Self {
1616 self.params.name = Some(name.into());
1617 self
1618 }
1619
1620 pub fn roles(mut self, roles: Vec<crate::Snowflake>) -> Self {
1622 self.params.roles = Some(roles);
1623 self
1624 }
1625
1626 pub fn build(self) -> ModifyEmoji {
1628 self.params
1629 }
1630}
1631
1632#[derive(Debug, Clone, serde::Serialize, Default)]
1638pub struct CreateStageInstance {
1639 pub channel_id: crate::Snowflake,
1640 pub topic: String,
1641 #[serde(skip_serializing_if = "Option::is_none")]
1642 pub privacy_level: Option<crate::stage::StagePrivacyLevel>,
1643 #[serde(skip_serializing_if = "Option::is_none")]
1644 pub send_start_notification: Option<bool>,
1645}
1646
1647#[derive(Debug, Clone)]
1649pub struct StageInstanceBuilder {
1650 params: CreateStageInstance,
1651}
1652
1653impl StageInstanceBuilder {
1654 pub fn new(channel_id: impl Into<crate::Snowflake>, topic: impl Into<String>) -> Self {
1656 Self {
1657 params: CreateStageInstance {
1658 channel_id: channel_id.into(),
1659 topic: topic.into(),
1660 privacy_level: None,
1661 send_start_notification: None,
1662 },
1663 }
1664 }
1665
1666 #[inline]
1668 pub fn privacy_level(mut self, level: crate::stage::StagePrivacyLevel) -> Self {
1669 self.params.privacy_level = Some(level);
1670 self
1671 }
1672
1673 #[inline]
1675 pub fn send_start_notification(mut self, send: bool) -> Self {
1676 self.params.send_start_notification = Some(send);
1677 self
1678 }
1679
1680 #[inline]
1682 pub fn build(self) -> CreateStageInstance {
1683 self.params
1684 }
1685}
1686
1687#[derive(Debug, Clone, serde::Serialize, Default)]
1693pub struct CreateGuild {
1694 pub name: String,
1695 #[serde(skip_serializing_if = "Option::is_none")]
1696 pub icon: Option<String>,
1697 #[serde(skip_serializing_if = "Option::is_none")]
1698 pub verification_level: Option<u8>,
1699 #[serde(skip_serializing_if = "Option::is_none")]
1700 pub default_message_notifications: Option<u8>,
1701 #[serde(skip_serializing_if = "Option::is_none")]
1702 pub explicit_content_filter: Option<u8>,
1703 #[serde(skip_serializing_if = "Vec::is_empty")]
1704 pub roles: Vec<crate::json::Value>,
1705 #[serde(skip_serializing_if = "Vec::is_empty")]
1706 pub channels: Vec<crate::json::Value>,
1707 #[serde(skip_serializing_if = "Option::is_none")]
1708 pub afk_channel_id: Option<crate::Snowflake>,
1709 #[serde(skip_serializing_if = "Option::is_none")]
1710 pub afk_timeout: Option<u32>,
1711 #[serde(skip_serializing_if = "Option::is_none")]
1712 pub system_channel_id: Option<crate::Snowflake>,
1713 #[serde(skip_serializing_if = "Option::is_none")]
1714 pub system_channel_flags: Option<u64>,
1715}
1716
1717#[derive(Debug, Clone)]
1719pub struct CreateGuildBuilder {
1720 params: CreateGuild,
1721}
1722
1723impl CreateGuildBuilder {
1724 pub fn new(name: impl Into<String>) -> Self {
1725 Self {
1726 params: CreateGuild {
1727 name: name.into(),
1728 ..Default::default()
1729 },
1730 }
1731 }
1732
1733 #[inline]
1734 pub fn icon(mut self, icon: impl Into<String>) -> Self {
1735 self.params.icon = Some(icon.into());
1736 self
1737 }
1738
1739 pub fn verification_level(mut self, level: u8) -> Self {
1740 self.params.verification_level = Some(level);
1741 self
1742 }
1743
1744 pub fn build(self) -> CreateGuild {
1745 self.params
1746 }
1747}