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
694#[derive(Debug, Clone)]
696pub struct InteractionResponseBuilder<'a> {
697 response: crate::interaction::InteractionResponse<'a>,
698}
699
700impl<'a> Default for InteractionResponseBuilder<'a> {
701 fn default() -> Self {
702 Self::new()
703 }
704}
705
706impl<'a> InteractionResponseBuilder<'a> {
707 pub fn new() -> Self {
709 Self {
710 response: crate::interaction::InteractionResponse {
711 response_type:
712 crate::interaction::InteractionCallbackType::ChannelMessageWithSource,
713 data: Some(Default::default()),
714 },
715 }
716 }
717
718 pub fn kind(mut self, kind: crate::interaction::InteractionCallbackType) -> Self {
719 self.response.response_type = kind;
720 self
721 }
722
723 pub fn content(mut self, content: impl Into<TitanString<'a>>) -> Self {
724 if let Some(data) = &mut self.response.data {
725 data.content = Some(content.into());
726 }
727 self
728 }
729
730 pub fn embed(mut self, embed: impl Into<crate::Embed<'a>>) -> Self {
731 if self.response.data.is_none() {
732 self.response.data = Some(Default::default());
733 }
734 if let Some(data) = &mut self.response.data {
735 data.embeds.push(embed.into());
736 }
737 self
738 }
739
740 pub fn build(self) -> crate::interaction::InteractionResponse<'a> {
741 self.response
742 }
743}
744
745#[derive(Debug, Clone, serde::Serialize, Default)]
752pub struct CreateChannel<'a> {
753 pub name: TitanString<'a>,
754 #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
755 pub kind: Option<u8>,
756 #[serde(skip_serializing_if = "Option::is_none")]
757 pub topic: Option<TitanString<'a>>,
758 #[serde(skip_serializing_if = "Option::is_none")]
759 pub bitrate: Option<u32>,
760 #[serde(skip_serializing_if = "Option::is_none")]
761 pub user_limit: Option<u32>,
762 #[serde(skip_serializing_if = "Option::is_none")]
763 pub rate_limit_per_user: Option<u32>,
764 #[serde(skip_serializing_if = "Option::is_none")]
765 pub position: Option<u32>,
766 #[serde(skip_serializing_if = "Option::is_none")]
767 pub permission_overwrites: Option<Vec<crate::json::Value>>,
768 #[serde(skip_serializing_if = "Option::is_none")]
769 pub parent_id: Option<crate::Snowflake>,
770 #[serde(skip_serializing_if = "Option::is_none")]
771 pub nsfw: Option<bool>,
772}
773
774#[derive(Debug, Clone, Default)]
776pub struct CreateChannelBuilder<'a> {
777 params: CreateChannel<'a>,
778}
779
780impl<'a> CreateChannelBuilder<'a> {
781 pub fn new(name: impl Into<TitanString<'a>>) -> Self {
782 let mut builder = Self::default();
783 builder.params.name = name.into();
784 builder
785 }
786
787 pub fn kind(mut self, kind: u8) -> Self {
788 self.params.kind = Some(kind);
789 self
790 }
791
792 pub fn topic(mut self, topic: impl Into<TitanString<'a>>) -> Self {
793 self.params.topic = Some(topic.into());
794 self
795 }
796
797 pub fn build(self) -> CreateChannel<'a> {
798 self.params
799 }
800}
801
802#[derive(Debug, Clone, serde::Serialize, Default)]
809pub struct CreateRole<'a> {
810 #[serde(skip_serializing_if = "Option::is_none")]
811 pub name: Option<TitanString<'a>>,
812 #[serde(skip_serializing_if = "Option::is_none")]
813 pub permissions: Option<String>,
814 #[serde(skip_serializing_if = "Option::is_none")]
815 pub color: Option<u32>,
816 #[serde(skip_serializing_if = "Option::is_none")]
817 pub hoist: Option<bool>,
818 #[serde(skip_serializing_if = "Option::is_none")]
819 pub icon: Option<TitanString<'a>>,
820 #[serde(skip_serializing_if = "Option::is_none")]
821 pub unicode_emoji: Option<TitanString<'a>>,
822 #[serde(skip_serializing_if = "Option::is_none")]
823 pub mentionable: Option<bool>,
824}
825
826#[derive(Debug, Clone, Default)]
828pub struct CreateRoleBuilder<'a> {
829 params: CreateRole<'a>,
830}
831
832impl<'a> CreateRoleBuilder<'a> {
833 pub fn new() -> Self {
834 Self::default()
835 }
836
837 pub fn name(mut self, name: impl Into<TitanString<'a>>) -> Self {
838 self.params.name = Some(name.into());
839 self
840 }
841
842 pub fn color(mut self, color: u32) -> Self {
843 self.params.color = Some(color);
844 self
845 }
846
847 pub fn hoist(mut self, hoist: bool) -> Self {
848 self.params.hoist = Some(hoist);
849 self
850 }
851
852 pub fn icon(mut self, icon: impl Into<TitanString<'a>>) -> Self {
853 self.params.icon = Some(icon.into());
854 self
855 }
856
857 pub fn unicode_emoji(mut self, emoji: impl Into<TitanString<'a>>) -> Self {
858 self.params.unicode_emoji = Some(emoji.into());
859 self
860 }
861
862 pub fn mentionable(mut self, mentionable: bool) -> Self {
863 self.params.mentionable = Some(mentionable);
864 self
865 }
866
867 pub fn build(self) -> CreateRole<'a> {
868 self.params
869 }
870}
871
872#[derive(Debug, Clone, serde::Serialize)]
878pub struct CommandBuilder<'a> {
879 pub name: TitanString<'a>,
880 #[serde(skip_serializing_if = "Option::is_none")]
881 pub name_localizations: Option<std::collections::HashMap<String, String>>,
882 #[serde(skip_serializing_if = "Option::is_none")]
883 pub description: Option<TitanString<'a>>,
884 #[serde(skip_serializing_if = "Option::is_none")]
885 pub description_localizations: Option<std::collections::HashMap<String, String>>,
886 #[serde(skip_serializing_if = "Option::is_none")]
887 pub default_member_permissions: Option<TitanString<'a>>,
888 #[serde(skip_serializing_if = "Option::is_none")]
889 pub dm_permission: Option<bool>,
890 #[serde(default)]
891 #[serde(rename = "type")]
892 pub kind: Option<crate::command::CommandType>,
893 #[serde(skip_serializing_if = "Option::is_none")]
894 pub nsfw: Option<bool>,
895}
896
897impl<'a> CommandBuilder<'a> {
898 pub fn new(name: impl Into<TitanString<'a>>, description: impl Into<TitanString<'a>>) -> Self {
899 Self {
900 name: name.into(),
901 description: Some(description.into()),
902 name_localizations: None,
903 description_localizations: None,
904 default_member_permissions: None,
905 dm_permission: None,
906 kind: Some(crate::command::CommandType::ChatInput),
907 nsfw: None,
908 }
909 }
910
911 pub fn build(self) -> Self {
912 self
913 }
914}
915
916#[derive(Debug, Clone, serde::Serialize, Default)]
921pub struct AutoModRuleBuilder {
922 pub name: String,
923}
924
925#[derive(Debug, Clone, serde::Serialize, Default)]
933pub struct CreateScheduledEvent<'a> {
934 pub name: TitanString<'a>,
935 pub privacy_level: crate::scheduled::ScheduledEventPrivacyLevel,
936 pub scheduled_start_time: TitanString<'a>,
937 #[serde(skip_serializing_if = "Option::is_none")]
938 pub scheduled_end_time: Option<TitanString<'a>>,
939 #[serde(skip_serializing_if = "Option::is_none")]
940 pub description: Option<TitanString<'a>>,
941 pub entity_type: crate::scheduled::ScheduledEventEntityType,
942 #[serde(skip_serializing_if = "Option::is_none")]
943 pub channel_id: Option<crate::Snowflake>,
944 #[serde(skip_serializing_if = "Option::is_none")]
945 pub entity_metadata: Option<crate::scheduled::ScheduledEventEntityMetadata<'a>>,
946 #[serde(skip_serializing_if = "Option::is_none")]
947 pub image: Option<TitanString<'a>>, }
949
950#[derive(Debug, Clone)]
952pub struct ScheduledEventBuilder<'a> {
953 params: CreateScheduledEvent<'a>,
954}
955
956impl<'a> ScheduledEventBuilder<'a> {
957 pub fn new(
959 name: impl Into<TitanString<'a>>,
960 start_time: impl Into<TitanString<'a>>,
961 entity_type: crate::scheduled::ScheduledEventEntityType,
962 ) -> Self {
963 Self {
964 params: CreateScheduledEvent {
965 name: name.into(),
966 scheduled_start_time: start_time.into(),
967 entity_type,
968 privacy_level: crate::scheduled::ScheduledEventPrivacyLevel::GuildOnly,
969 ..Default::default()
970 },
971 }
972 }
973
974 #[inline]
976 pub fn description(mut self, description: impl Into<TitanString<'a>>) -> Self {
977 self.params.description = Some(description.into());
978 self
979 }
980
981 #[inline]
983 pub fn end_time(mut self, time: impl Into<TitanString<'a>>) -> Self {
984 self.params.scheduled_end_time = Some(time.into());
985 self
986 }
987
988 #[inline]
990 pub fn channel_id(mut self, id: impl Into<crate::Snowflake>) -> Self {
991 self.params.channel_id = Some(id.into());
992 self
993 }
994
995 #[inline]
997 pub fn location(mut self, location: impl Into<TitanString<'a>>) -> Self {
998 self.params.entity_metadata = Some(crate::scheduled::ScheduledEventEntityMetadata {
999 location: Some(location.into()),
1000 });
1001 self
1002 }
1003
1004 #[inline]
1006 pub fn image(mut self, image: impl Into<TitanString<'a>>) -> Self {
1007 self.params.image = Some(image.into());
1008 self
1009 }
1010
1011 #[inline]
1013 pub fn build(self) -> CreateScheduledEvent<'a> {
1014 self.params
1015 }
1016}
1017
1018#[derive(Debug, Clone)]
1020pub struct PollBuilder<'a> {
1021 poll: crate::poll::Poll<'a>,
1022}
1023
1024impl<'a> PollBuilder<'a> {
1025 pub fn new(question: impl Into<TitanString<'a>>) -> Self {
1027 Self {
1028 poll: crate::poll::Poll {
1029 question: crate::poll::PollMedia {
1030 text: Some(question.into()),
1031 emoji: None,
1032 },
1033 answers: Vec::new(),
1034 expiry: None,
1035 allow_multiselect: false,
1036 layout_type: None,
1037 results: None,
1038 },
1039 }
1040 }
1041
1042 pub fn answer(mut self, answer: impl Into<crate::poll::PollAnswer<'a>>) -> Self {
1044 self.poll.answers.push(answer.into());
1045 self
1046 }
1047
1048 pub fn expiry(mut self, expiry: impl Into<TitanString<'a>>) -> Self {
1050 self.poll.expiry = Some(expiry.into());
1051 self
1052 }
1053
1054 pub fn allow_multiselect(mut self, allow: bool) -> Self {
1056 self.poll.allow_multiselect = allow;
1057 self
1058 }
1059
1060 pub fn build(self) -> crate::poll::Poll<'a> {
1062 self.poll
1063 }
1064}
1065
1066#[derive(Debug, Clone, serde::Serialize, Default)]
1068pub struct ExecuteWebhook {
1069 #[serde(skip_serializing_if = "Option::is_none")]
1070 pub content: Option<String>,
1071 #[serde(skip_serializing_if = "Option::is_none")]
1072 pub username: Option<String>,
1073 #[serde(skip_serializing_if = "Option::is_none")]
1074 pub avatar_url: Option<String>,
1075 #[serde(skip_serializing_if = "Option::is_none")]
1076 pub tts: Option<bool>,
1077 #[serde(skip_serializing_if = "Vec::is_empty")]
1078 pub embeds: Vec<crate::Embed<'static>>,
1079 }
1081
1082#[derive(Debug, Clone, Default)]
1084pub struct WebhookExecuteBuilder<'a> {
1085 params: ExecuteWebhook,
1086 _phantom: std::marker::PhantomData<&'a ()>,
1087}
1088
1089impl<'a> WebhookExecuteBuilder<'a> {
1090 pub fn new() -> Self {
1092 Self::default()
1093 }
1094
1095 #[inline]
1097 pub fn content(mut self, content: impl Into<String>) -> Self {
1098 self.params.content = Some(content.into());
1099 self
1100 }
1101
1102 #[inline]
1104 pub fn username(mut self, username: impl Into<String>) -> Self {
1105 self.params.username = Some(username.into());
1106 self
1107 }
1108
1109 #[inline]
1111 pub fn avatar_url(mut self, url: impl Into<String>) -> Self {
1112 self.params.avatar_url = Some(url.into());
1113 self
1114 }
1115
1116 #[inline]
1118 pub fn tts(mut self, tts: bool) -> Self {
1119 self.params.tts = Some(tts);
1120 self
1121 }
1122
1123 #[inline]
1125 pub fn embed(mut self, embed: impl Into<crate::Embed<'static>>) -> Self {
1126 self.params.embeds.push(embed.into());
1127 self
1128 }
1129
1130 #[inline]
1132 pub fn embeds(mut self, embeds: Vec<crate::Embed<'static>>) -> Self {
1133 self.params.embeds.extend(embeds);
1134 self
1135 }
1136
1137 #[inline]
1139 pub fn build(self) -> ExecuteWebhook {
1140 self.params
1141 }
1142}
1143
1144impl<'a> Default for ButtonBuilder<'a> {
1146 fn default() -> Self {
1147 Self::new()
1148 }
1149}
1150
1151impl<'a> Default for ActionRowBuilder<'a> {
1152 fn default() -> Self {
1153 Self::new()
1154 }
1155}
1156
1157impl<'a> Default for SelectMenuBuilder<'a> {
1158 fn default() -> Self {
1159 Self::new("default_select") }
1161}
1162
1163#[cfg(test)]
1164mod modify_tests {
1165 use super::*;
1166 #[test]
1167 fn test_modify_guild_builder() {
1168 let payload = ModifyGuildBuilder::new()
1169 .name("New Guild Name")
1170 .region("us-west")
1171 .verification_level(1)
1172 .build();
1173
1174 assert_eq!(
1175 payload.name,
1176 Some(TitanString::from("New Guild Name".to_string()))
1177 );
1178 assert_eq!(
1179 payload.region,
1180 Some(TitanString::from("us-west".to_string()))
1181 );
1182 assert_eq!(payload.verification_level, Some(1));
1183 }
1184
1185 #[test]
1186 fn test_modify_member_builder() {
1187 let payload = ModifyMemberBuilder::new()
1188 .nick("New Nick")
1189 .mute(true)
1190 .deaf(false)
1191 .build();
1192
1193 assert_eq!(
1194 payload.nick,
1195 Some(TitanString::from("New Nick".to_string()))
1196 );
1197 assert_eq!(payload.mute, Some(true));
1198 assert_eq!(payload.deaf, Some(false));
1199 }
1200
1201 #[test]
1202 fn test_start_thread_builder() {
1203 let payload = StartThreadBuilder::new("Thread Name")
1204 .auto_archive_duration(60)
1205 .kind(11) .build();
1207
1208 assert_eq!(payload.name, "Thread Name".to_string());
1209 assert_eq!(payload.auto_archive_duration, Some(60));
1210 assert_eq!(payload.type_, Some(11));
1211 }
1212}
1213
1214#[derive(Debug, Clone, serde::Serialize, Default)]
1220pub struct CreateInvite {
1221 #[serde(skip_serializing_if = "Option::is_none")]
1222 pub max_age: Option<u32>,
1223 #[serde(skip_serializing_if = "Option::is_none")]
1224 pub max_uses: Option<u32>,
1225 #[serde(skip_serializing_if = "Option::is_none")]
1226 pub temporary: Option<bool>,
1227 #[serde(skip_serializing_if = "Option::is_none")]
1228 pub unique: Option<bool>,
1229 #[serde(skip_serializing_if = "Option::is_none")]
1230 pub target_type: Option<u8>,
1231 #[serde(skip_serializing_if = "Option::is_none")]
1232 pub target_user_id: Option<crate::Snowflake>,
1233 #[serde(skip_serializing_if = "Option::is_none")]
1234 pub target_application_id: Option<crate::Snowflake>,
1235}
1236
1237#[derive(Debug, Clone, Default)]
1239pub struct CreateInviteBuilder {
1240 params: CreateInvite,
1241}
1242
1243impl CreateInviteBuilder {
1244 pub fn new() -> Self {
1246 Self::default()
1247 }
1248
1249 pub fn max_age(mut self, seconds: u32) -> Self {
1251 self.params.max_age = Some(seconds);
1252 self
1253 }
1254
1255 pub fn max_uses(mut self, uses: u32) -> Self {
1257 self.params.max_uses = Some(uses);
1258 self
1259 }
1260
1261 pub fn temporary(mut self, temp: bool) -> Self {
1263 self.params.temporary = Some(temp);
1264 self
1265 }
1266
1267 pub fn unique(mut self, unique: bool) -> Self {
1269 self.params.unique = Some(unique);
1270 self
1271 }
1272
1273 pub fn build(self) -> CreateInvite {
1275 self.params
1276 }
1277}
1278
1279#[derive(Debug, Clone, serde::Serialize, Default)]
1285pub struct CreateEmoji {
1286 pub name: String,
1287 pub image: String, #[serde(skip_serializing_if = "Vec::is_empty")]
1289 pub roles: Vec<crate::Snowflake>,
1290}
1291
1292#[derive(Debug, Clone)]
1294pub struct CreateEmojiBuilder {
1295 params: CreateEmoji,
1296}
1297
1298impl CreateEmojiBuilder {
1299 pub fn new(name: impl Into<String>, image_data: impl Into<String>) -> Self {
1302 Self {
1303 params: CreateEmoji {
1304 name: name.into(),
1305 image: image_data.into(),
1306 roles: Vec::new(),
1307 },
1308 }
1309 }
1310
1311 pub fn role(mut self, role_id: impl Into<crate::Snowflake>) -> Self {
1313 self.params.roles.push(role_id.into());
1314 self
1315 }
1316
1317 pub fn build(self) -> CreateEmoji {
1319 self.params
1320 }
1321}
1322
1323#[cfg(test)]
1324mod final_tests {
1325 use super::*;
1326 use crate::Mention;
1327 use crate::Snowflake; #[test]
1330 fn test_create_invite_builder() {
1331 let payload = CreateInviteBuilder::new()
1332 .max_age(86400)
1333 .max_uses(10)
1334 .unique(true)
1335 .build();
1336
1337 assert_eq!(payload.max_age, Some(86400));
1338 assert_eq!(payload.max_uses, Some(10));
1339 assert_eq!(payload.unique, Some(true));
1340 }
1341
1342 #[test]
1343 fn test_create_emoji_builder() {
1344 let payload = CreateEmojiBuilder::new("test_emoji", "data:image/png;base64,...")
1345 .role(Snowflake(12345))
1346 .build();
1347
1348 assert_eq!(payload.name, "test_emoji");
1349 assert_eq!(payload.roles.len(), 1);
1350 }
1351
1352 #[test]
1353 fn test_mention_trait() {
1354 let user = crate::User {
1355 id: Snowflake(123),
1356 username: "test".to_string().into(),
1357 discriminator: "0000".to_string().into(),
1358 global_name: None,
1359 avatar: None,
1360 bot: false,
1361 system: false,
1362 mfa_enabled: None,
1363 banner: None,
1364 accent_color: None,
1365 locale: None,
1366 verified: None,
1367 email: None,
1368 flags: None,
1369 premium_type: None,
1370 public_flags: None,
1371 avatar_decoration_data: None,
1372 };
1373
1374 let mention = user.mention();
1380 assert_eq!(mention, "<@123>");
1381 }
1382
1383 #[test]
1384 fn test_add_file_builder() {
1385 let msg = MessageBuilder::new()
1386 .content("With file")
1387 .add_file("test.txt", vec![1, 2, 3])
1388 .build();
1389
1390 assert_eq!(msg.files.len(), 1);
1391 assert_eq!(msg.files[0].filename, "test.txt");
1392 assert_eq!(msg.files[0].data, vec![1, 2, 3]);
1393 }
1394}
1395#[cfg(test)]
1396mod optimization_tests {
1397 use super::*;
1398 use TitanString;
1399
1400 #[test]
1401 fn test_embed_builder_zero_allocation() {
1402 let title = "Static Title";
1403 let embed = EmbedBuilder::new().title(title).build();
1405 match embed.title {
1406 Some(TitanString::Borrowed(t)) => assert_eq!(t, "Static Title"),
1407 _ => panic!("Expected Borrowed Cow for static string"),
1408 }
1409 }
1410
1411 #[test]
1412 fn test_embed_builder_owned() {
1413 let title = String::from("Owned Title");
1414 let embed = EmbedBuilder::new().title(title).build();
1415 match embed.title {
1416 Some(TitanString::Owned(t)) => assert_eq!(t, "Owned Title"),
1417 _ => panic!("Expected Owned Cow for String"),
1418 }
1419 }
1420
1421 #[test]
1422 fn test_component_builder_zero_allocation() {
1423 let id = "custom_id";
1424 let btn = ButtonBuilder::new().custom_id(id).build();
1425 if let crate::Component::Button(b) = btn {
1426 match b.custom_id {
1427 Some(TitanString::Borrowed(s)) => assert_eq!(s, "custom_id"),
1428 _ => panic!("Expected Borrowed Cow for button custom_id"),
1429 }
1430 }
1431 }
1432}
1433
1434#[derive(Debug, Clone, serde::Serialize, Default)]
1440pub struct CreateSticker {
1441 pub name: String,
1442 pub description: String,
1443 pub tags: String,
1444}
1445
1446#[derive(Debug, Clone)]
1448pub struct CreateStickerBuilder {
1449 params: CreateSticker,
1450}
1451
1452impl CreateStickerBuilder {
1453 pub fn new(
1455 name: impl Into<String>,
1456 description: impl Into<String>,
1457 tags: impl Into<String>,
1458 ) -> Self {
1459 Self {
1460 params: CreateSticker {
1461 name: name.into(),
1462 description: description.into(),
1463 tags: tags.into(),
1464 },
1465 }
1466 }
1467
1468 pub fn build(self) -> CreateSticker {
1470 self.params
1471 }
1472}
1473
1474#[derive(Debug, Clone, serde::Serialize, Default)]
1480pub struct ModifyEmoji {
1481 #[serde(skip_serializing_if = "Option::is_none")]
1482 pub name: Option<String>,
1483 #[serde(skip_serializing_if = "Option::is_none")]
1484 pub roles: Option<Vec<crate::Snowflake>>,
1485}
1486
1487#[derive(Debug, Clone, Default)]
1489pub struct ModifyEmojiBuilder {
1490 params: ModifyEmoji,
1491}
1492
1493impl ModifyEmojiBuilder {
1494 pub fn new() -> Self {
1496 Self::default()
1497 }
1498
1499 pub fn name(mut self, name: impl Into<String>) -> Self {
1501 self.params.name = Some(name.into());
1502 self
1503 }
1504
1505 pub fn roles(mut self, roles: Vec<crate::Snowflake>) -> Self {
1507 self.params.roles = Some(roles);
1508 self
1509 }
1510
1511 pub fn build(self) -> ModifyEmoji {
1513 self.params
1514 }
1515}
1516
1517#[derive(Debug, Clone, serde::Serialize, Default)]
1523pub struct CreateStageInstance {
1524 pub channel_id: crate::Snowflake,
1525 pub topic: String,
1526 #[serde(skip_serializing_if = "Option::is_none")]
1527 pub privacy_level: Option<crate::stage::StagePrivacyLevel>,
1528 #[serde(skip_serializing_if = "Option::is_none")]
1529 pub send_start_notification: Option<bool>,
1530}
1531
1532#[derive(Debug, Clone)]
1534pub struct StageInstanceBuilder {
1535 params: CreateStageInstance,
1536}
1537
1538impl StageInstanceBuilder {
1539 pub fn new(channel_id: impl Into<crate::Snowflake>, topic: impl Into<String>) -> Self {
1541 Self {
1542 params: CreateStageInstance {
1543 channel_id: channel_id.into(),
1544 topic: topic.into(),
1545 privacy_level: None,
1546 send_start_notification: None,
1547 },
1548 }
1549 }
1550
1551 #[inline]
1553 pub fn privacy_level(mut self, level: crate::stage::StagePrivacyLevel) -> Self {
1554 self.params.privacy_level = Some(level);
1555 self
1556 }
1557
1558 #[inline]
1560 pub fn send_start_notification(mut self, send: bool) -> Self {
1561 self.params.send_start_notification = Some(send);
1562 self
1563 }
1564
1565 #[inline]
1567 pub fn build(self) -> CreateStageInstance {
1568 self.params
1569 }
1570}
1571
1572#[derive(Debug, Clone, serde::Serialize, Default)]
1578pub struct CreateGuild {
1579 pub name: String,
1580 #[serde(skip_serializing_if = "Option::is_none")]
1581 pub icon: Option<String>,
1582 #[serde(skip_serializing_if = "Option::is_none")]
1583 pub verification_level: Option<u8>,
1584 #[serde(skip_serializing_if = "Option::is_none")]
1585 pub default_message_notifications: Option<u8>,
1586 #[serde(skip_serializing_if = "Option::is_none")]
1587 pub explicit_content_filter: Option<u8>,
1588 #[serde(skip_serializing_if = "Vec::is_empty")]
1589 pub roles: Vec<crate::json::Value>,
1590 #[serde(skip_serializing_if = "Vec::is_empty")]
1591 pub channels: Vec<crate::json::Value>,
1592 #[serde(skip_serializing_if = "Option::is_none")]
1593 pub afk_channel_id: Option<crate::Snowflake>,
1594 #[serde(skip_serializing_if = "Option::is_none")]
1595 pub afk_timeout: Option<u32>,
1596 #[serde(skip_serializing_if = "Option::is_none")]
1597 pub system_channel_id: Option<crate::Snowflake>,
1598 #[serde(skip_serializing_if = "Option::is_none")]
1599 pub system_channel_flags: Option<u64>,
1600}
1601
1602#[derive(Debug, Clone)]
1604pub struct CreateGuildBuilder {
1605 params: CreateGuild,
1606}
1607
1608impl CreateGuildBuilder {
1609 pub fn new(name: impl Into<String>) -> Self {
1610 Self {
1611 params: CreateGuild {
1612 name: name.into(),
1613 ..Default::default()
1614 },
1615 }
1616 }
1617
1618 #[inline]
1619 pub fn icon(mut self, icon: impl Into<String>) -> Self {
1620 self.params.icon = Some(icon.into());
1621 self
1622 }
1623
1624 pub fn verification_level(mut self, level: u8) -> Self {
1625 self.params.verification_level = Some(level);
1626 self
1627 }
1628
1629 pub fn build(self) -> CreateGuild {
1630 self.params
1631 }
1632}