1use std::collections::HashMap;
2
3use serde::de::{Deserializer, Error as DeError};
4use serde::ser::{Error as _, Serializer};
5use serde::{Deserialize, Serialize};
6
7use super::{AuthorizingIntegrationOwners, InteractionContext};
8#[cfg(feature = "model")]
9use crate::builder::{
10 Builder,
11 CreateInteractionResponse,
12 CreateInteractionResponseFollowup,
13 CreateInteractionResponseMessage,
14 EditInteractionResponse,
15};
16#[cfg(feature = "collector")]
17use crate::client::Context;
18#[cfg(feature = "model")]
19use crate::http::{CacheHttp, Http};
20use crate::internal::prelude::*;
21use crate::json::{self, JsonError};
22use crate::model::application::{CommandOptionType, CommandType};
23use crate::model::channel::{Attachment, Message, PartialChannel};
24use crate::model::guild::{Member, PartialMember, Role};
25use crate::model::id::{
26 ApplicationId,
27 AttachmentId,
28 ChannelId,
29 CommandId,
30 GenericId,
31 GuildId,
32 InteractionId,
33 MessageId,
34 RoleId,
35 TargetId,
36 UserId,
37};
38use crate::model::monetization::Entitlement;
39use crate::model::user::User;
40use crate::model::Permissions;
41#[cfg(all(feature = "collector", feature = "utils"))]
42use crate::utils::{CreateQuickModal, QuickModalResponse};
43
44#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
48#[derive(Clone, Debug, Deserialize, Serialize)]
49#[serde(remote = "Self")]
50#[non_exhaustive]
51pub struct CommandInteraction {
52 pub id: InteractionId,
54 pub application_id: ApplicationId,
56 pub data: CommandData,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub guild_id: Option<GuildId>,
61 pub channel: Option<PartialChannel>,
63 pub channel_id: ChannelId,
65 #[serde(skip_serializing_if = "Option::is_none")]
69 pub member: Option<Box<Member>>,
70 #[serde(default)]
72 pub user: User,
73 pub token: String,
75 pub version: u8,
77 pub app_permissions: Option<Permissions>,
80 pub locale: String,
82 pub guild_locale: Option<String>,
84 pub entitlements: Vec<Entitlement>,
86 #[serde(default)]
88 pub authorizing_integration_owners: AuthorizingIntegrationOwners,
89 pub context: Option<InteractionContext>,
91 pub attachment_size_limit: u32,
93}
94
95#[cfg(feature = "model")]
96impl CommandInteraction {
97 pub async fn get_response(&self, http: impl AsRef<Http>) -> Result<Message> {
103 http.as_ref().get_original_interaction_response(&self.token).await
104 }
105
106 pub async fn create_response(
116 &self,
117 cache_http: impl CacheHttp,
118 builder: CreateInteractionResponse,
119 ) -> Result<()> {
120 builder.execute(cache_http, (self.id, &self.token)).await
121 }
122
123 pub async fn edit_response(
133 &self,
134 cache_http: impl CacheHttp,
135 builder: EditInteractionResponse,
136 ) -> Result<Message> {
137 builder.execute(cache_http, &self.token).await
138 }
139
140 pub async fn delete_response(&self, http: impl AsRef<Http>) -> Result<()> {
149 http.as_ref().delete_original_interaction_response(&self.token).await
150 }
151
152 pub async fn create_followup(
162 &self,
163 cache_http: impl CacheHttp,
164 builder: CreateInteractionResponseFollowup,
165 ) -> Result<Message> {
166 builder.execute(cache_http, (None, &self.token)).await
167 }
168
169 pub async fn edit_followup(
179 &self,
180 cache_http: impl CacheHttp,
181 message_id: impl Into<MessageId>,
182 builder: CreateInteractionResponseFollowup,
183 ) -> Result<Message> {
184 builder.execute(cache_http, (Some(message_id.into()), &self.token)).await
185 }
186
187 pub async fn delete_followup<M: Into<MessageId>>(
194 &self,
195 http: impl AsRef<Http>,
196 message_id: M,
197 ) -> Result<()> {
198 http.as_ref().delete_followup_message(&self.token, message_id.into()).await
199 }
200
201 pub async fn get_followup<M: Into<MessageId>>(
208 &self,
209 http: impl AsRef<Http>,
210 message_id: M,
211 ) -> Result<Message> {
212 http.as_ref().get_followup_message(&self.token, message_id.into()).await
213 }
214
215 pub async fn defer(&self, cache_http: impl CacheHttp) -> Result<()> {
222 let builder = CreateInteractionResponse::Defer(CreateInteractionResponseMessage::default());
223 self.create_response(cache_http, builder).await
224 }
225
226 pub async fn defer_ephemeral(&self, cache_http: impl CacheHttp) -> Result<()> {
233 let builder = CreateInteractionResponse::Defer(
234 CreateInteractionResponseMessage::new().ephemeral(true),
235 );
236 self.create_response(cache_http, builder).await
237 }
238
239 #[cfg(all(feature = "collector", feature = "utils"))]
245 pub async fn quick_modal(
246 &self,
247 ctx: &Context,
248 builder: CreateQuickModal,
249 ) -> Result<Option<QuickModalResponse>> {
250 builder.execute(ctx, self.id, &self.token).await
251 }
252}
253
254impl<'de> Deserialize<'de> for CommandInteraction {
256 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
257 let mut interaction = Self::deserialize(deserializer)?;
259 if let Some(guild_id) = interaction.guild_id {
260 if let Some(member) = &mut interaction.member {
261 member.guild_id = guild_id;
262 interaction.user = member.user.clone();
264 }
265 interaction.data.resolved.roles.values_mut().for_each(|r| r.guild_id = guild_id);
266 }
267 Ok(interaction)
268 }
269}
270
271impl Serialize for CommandInteraction {
272 fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
273 Self::serialize(self, serializer)
275 }
276}
277
278#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
282#[derive(Clone, Debug, Deserialize, Serialize)]
283#[non_exhaustive]
284pub struct CommandData {
285 pub id: CommandId,
287 pub name: String,
289 #[serde(rename = "type")]
291 pub kind: CommandType,
292 #[serde(default)]
294 pub resolved: CommandDataResolved,
295 #[serde(default)]
296 pub options: Vec<CommandDataOption>,
297 #[serde(skip_serializing_if = "Option::is_none")]
299 pub guild_id: Option<GuildId>,
300 pub target_id: Option<TargetId>,
309}
310
311impl CommandData {
312 #[must_use]
314 pub fn autocomplete(&self) -> Option<AutocompleteOption<'_>> {
315 fn find_option(opts: &[CommandDataOption]) -> Option<AutocompleteOption<'_>> {
316 for opt in opts {
317 match &opt.value {
318 CommandDataOptionValue::SubCommand(opts)
319 | CommandDataOptionValue::SubCommandGroup(opts) => {
320 return find_option(opts);
321 },
322 CommandDataOptionValue::Autocomplete {
323 kind,
324 value,
325 } => {
326 return Some(AutocompleteOption {
327 name: &opt.name,
328 kind: *kind,
329 value,
330 });
331 },
332 _ => {},
333 }
334 }
335 None
336 }
337 find_option(&self.options)
338 }
339
340 #[must_use]
342 pub fn options(&self) -> Vec<ResolvedOption<'_>> {
343 fn resolve_options<'a>(
344 opts: &'a [CommandDataOption],
345 resolved: &'a CommandDataResolved,
346 ) -> Vec<ResolvedOption<'a>> {
347 let mut options = Vec::new();
348 for opt in opts {
349 let value = match &opt.value {
350 CommandDataOptionValue::SubCommand(opts) => {
351 ResolvedValue::SubCommand(resolve_options(opts, resolved))
352 },
353 CommandDataOptionValue::SubCommandGroup(opts) => {
354 ResolvedValue::SubCommandGroup(resolve_options(opts, resolved))
355 },
356 CommandDataOptionValue::Autocomplete {
357 kind,
358 value,
359 } => ResolvedValue::Autocomplete {
360 kind: *kind,
361 value,
362 },
363 CommandDataOptionValue::Boolean(v) => ResolvedValue::Boolean(*v),
364 CommandDataOptionValue::Integer(v) => ResolvedValue::Integer(*v),
365 CommandDataOptionValue::Number(v) => ResolvedValue::Number(*v),
366 CommandDataOptionValue::String(v) => ResolvedValue::String(v),
367 CommandDataOptionValue::Attachment(id) => resolved.attachments.get(id).map_or(
368 ResolvedValue::Unresolved(Unresolved::Attachment(*id)),
369 ResolvedValue::Attachment,
370 ),
371 CommandDataOptionValue::Channel(id) => resolved.channels.get(id).map_or(
372 ResolvedValue::Unresolved(Unresolved::Channel(*id)),
373 ResolvedValue::Channel,
374 ),
375 CommandDataOptionValue::Mentionable(id) => {
376 let user_id = UserId::new(id.get());
377 let value = if let Some(user) = resolved.users.get(&user_id) {
378 Some(ResolvedValue::User(user, resolved.members.get(&user_id)))
379 } else {
380 resolved.roles.get(&RoleId::new(id.get())).map(ResolvedValue::Role)
381 };
382 value.unwrap_or(ResolvedValue::Unresolved(Unresolved::Mentionable(*id)))
383 },
384 CommandDataOptionValue::User(id) => resolved
385 .users
386 .get(id)
387 .map(|u| ResolvedValue::User(u, resolved.members.get(id)))
388 .unwrap_or(ResolvedValue::Unresolved(Unresolved::User(*id))),
389 CommandDataOptionValue::Role(id) => resolved.roles.get(id).map_or(
390 ResolvedValue::Unresolved(Unresolved::RoleId(*id)),
391 ResolvedValue::Role,
392 ),
393 CommandDataOptionValue::Unknown(unknown) => {
394 ResolvedValue::Unresolved(Unresolved::Unknown(*unknown))
395 },
396 };
397
398 options.push(ResolvedOption {
399 name: &opt.name,
400 value,
401 });
402 }
403 options
404 }
405
406 resolve_options(&self.options, &self.resolved)
407 }
408
409 #[must_use]
413 pub fn target(&self) -> Option<ResolvedTarget<'_>> {
414 match (self.kind, self.target_id) {
415 (CommandType::User, Some(id)) => {
416 let user_id = id.to_user_id();
417
418 let user = self.resolved.users.get(&user_id)?;
419 let member = self.resolved.members.get(&user_id);
420
421 Some(ResolvedTarget::User(user, member))
422 },
423 (CommandType::Message, Some(id)) => {
424 let message_id = id.to_message_id();
425 let message = self.resolved.messages.get(&message_id)?;
426
427 Some(ResolvedTarget::Message(message))
428 },
429 _ => None,
430 }
431 }
432}
433
434#[derive(Clone, Debug)]
436#[non_exhaustive]
437pub struct AutocompleteOption<'a> {
438 pub name: &'a str,
439 pub kind: CommandOptionType,
440 pub value: &'a str,
441}
442
443#[derive(Clone, Debug)]
444#[non_exhaustive]
445pub struct ResolvedOption<'a> {
446 pub name: &'a str,
447 pub value: ResolvedValue<'a>,
448}
449
450#[derive(Clone, Debug)]
452#[non_exhaustive]
453pub enum ResolvedValue<'a> {
454 Autocomplete { kind: CommandOptionType, value: &'a str },
455 Boolean(bool),
456 Integer(i64),
457 Number(f64),
458 String(&'a str),
459 SubCommand(Vec<ResolvedOption<'a>>),
460 SubCommandGroup(Vec<ResolvedOption<'a>>),
461 Attachment(&'a Attachment),
462 Channel(&'a PartialChannel),
463 Role(&'a Role),
464 User(&'a User, Option<&'a PartialMember>),
465 Unresolved(Unresolved),
466}
467
468#[derive(Clone, Debug)]
470#[non_exhaustive]
471pub enum Unresolved {
472 Attachment(AttachmentId),
473 Channel(ChannelId),
474 Mentionable(GenericId),
475 RoleId(RoleId),
476 User(UserId),
477 Unknown(u8),
479}
480
481#[derive(Clone, Debug)]
483#[non_exhaustive]
484pub enum ResolvedTarget<'a> {
485 User(&'a User, Option<&'a PartialMember>),
486 Message(&'a Message),
487}
488
489#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
494#[derive(Clone, Debug, Default, Deserialize, Serialize)]
495#[non_exhaustive]
496pub struct CommandDataResolved {
497 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
499 pub users: HashMap<UserId, User>,
500 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
502 pub members: HashMap<UserId, PartialMember>,
503 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
505 pub roles: HashMap<RoleId, Role>,
506 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
508 pub channels: HashMap<ChannelId, PartialChannel>,
509 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
511 pub messages: HashMap<MessageId, Message>,
512 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
514 pub attachments: HashMap<AttachmentId, Attachment>,
515}
516
517#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
527#[derive(Clone, Debug, PartialEq)]
528#[non_exhaustive]
529pub struct CommandDataOption {
530 pub name: String,
532 pub value: CommandDataOptionValue,
534}
535
536impl CommandDataOption {
537 #[must_use]
538 pub fn kind(&self) -> CommandOptionType {
539 self.value.kind()
540 }
541}
542
543#[derive(Deserialize, Serialize)]
544struct RawCommandDataOption {
545 name: String,
546 #[serde(rename = "type")]
547 kind: CommandOptionType,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 value: Option<json::Value>,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 options: Option<Vec<RawCommandDataOption>>,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 focused: Option<bool>,
554}
555
556fn option_from_raw(raw: RawCommandDataOption) -> Result<CommandDataOption> {
557 macro_rules! value {
558 () => {{
559 json::from_value(
560 raw.value.ok_or_else::<JsonError, _>(|| DeError::missing_field("value"))?,
561 )?
562 }};
563 }
564
565 let value = match raw.kind {
566 _ if raw.focused == Some(true) => CommandDataOptionValue::Autocomplete {
567 kind: raw.kind,
568 value: value!(),
569 },
570 CommandOptionType::Boolean => CommandDataOptionValue::Boolean(value!()),
571 CommandOptionType::Integer => CommandDataOptionValue::Integer(value!()),
572 CommandOptionType::Number => CommandDataOptionValue::Number(value!()),
573 CommandOptionType::String => CommandDataOptionValue::String(value!()),
574 CommandOptionType::SubCommand => {
575 let options =
576 raw.options.ok_or_else::<JsonError, _>(|| DeError::missing_field("options"))?;
577 let options = options.into_iter().map(option_from_raw).collect::<Result<_>>()?;
578 CommandDataOptionValue::SubCommand(options)
579 },
580 CommandOptionType::SubCommandGroup => {
581 let options =
582 raw.options.ok_or_else::<JsonError, _>(|| DeError::missing_field("options"))?;
583 let options = options.into_iter().map(option_from_raw).collect::<Result<_>>()?;
584 CommandDataOptionValue::SubCommandGroup(options)
585 },
586 CommandOptionType::Attachment => CommandDataOptionValue::Attachment(value!()),
587 CommandOptionType::Channel => CommandDataOptionValue::Channel(value!()),
588 CommandOptionType::Mentionable => CommandDataOptionValue::Mentionable(value!()),
589 CommandOptionType::Role => CommandDataOptionValue::Role(value!()),
590 CommandOptionType::User => CommandDataOptionValue::User(value!()),
591 CommandOptionType::Unknown(unknown) => CommandDataOptionValue::Unknown(unknown),
592 };
593
594 Ok(CommandDataOption {
595 name: raw.name,
596 value,
597 })
598}
599
600fn option_to_raw(option: &CommandDataOption) -> Result<RawCommandDataOption> {
601 let mut raw = RawCommandDataOption {
602 name: option.name.clone(),
603 kind: option.kind(),
604 value: None,
605 options: None,
606 focused: None,
607 };
608
609 match &option.value {
610 CommandDataOptionValue::Autocomplete {
611 kind: _,
612 value,
613 } => {
614 raw.value = Some(json::to_value(value)?);
615 raw.focused = Some(true);
616 },
617 CommandDataOptionValue::Boolean(v) => raw.value = Some(json::to_value(v)?),
618 CommandDataOptionValue::Integer(v) => raw.value = Some(json::to_value(v)?),
619 CommandDataOptionValue::Number(v) => raw.value = Some(json::to_value(v)?),
620 CommandDataOptionValue::String(v) => raw.value = Some(json::to_value(v)?),
621 CommandDataOptionValue::SubCommand(o) | CommandDataOptionValue::SubCommandGroup(o) => {
622 raw.options = Some(o.iter().map(option_to_raw).collect::<Result<_>>()?);
623 },
624 CommandDataOptionValue::Attachment(v) => raw.value = Some(json::to_value(v)?),
625 CommandDataOptionValue::Channel(v) => raw.value = Some(json::to_value(v)?),
626 CommandDataOptionValue::Mentionable(v) => raw.value = Some(json::to_value(v)?),
627 CommandDataOptionValue::Role(v) => raw.value = Some(json::to_value(v)?),
628 CommandDataOptionValue::User(v) => raw.value = Some(json::to_value(v)?),
629 CommandDataOptionValue::Unknown(_) => {},
630 }
631
632 Ok(raw)
633}
634
635impl<'de> Deserialize<'de> for CommandDataOption {
637 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
638 option_from_raw(RawCommandDataOption::deserialize(deserializer)?).map_err(D::Error::custom)
639 }
640}
641
642impl Serialize for CommandDataOption {
643 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
644 option_to_raw(self).map_err(S::Error::custom)?.serialize(serializer)
645 }
646}
647
648#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
652#[derive(Clone, Debug, PartialEq)]
653#[non_exhaustive]
654pub enum CommandDataOptionValue {
655 Autocomplete { kind: CommandOptionType, value: String },
656 Boolean(bool),
657 Integer(i64),
658 Number(f64),
659 String(String),
660 SubCommand(Vec<CommandDataOption>),
661 SubCommandGroup(Vec<CommandDataOption>),
662 Attachment(AttachmentId),
663 Channel(ChannelId),
664 Mentionable(GenericId),
665 Role(RoleId),
666 User(UserId),
667 Unknown(u8),
668}
669
670impl CommandDataOptionValue {
671 #[must_use]
672 pub fn kind(&self) -> CommandOptionType {
673 match self {
674 Self::Autocomplete {
675 kind, ..
676 } => *kind,
677 Self::Boolean(_) => CommandOptionType::Boolean,
678 Self::Integer(_) => CommandOptionType::Integer,
679 Self::Number(_) => CommandOptionType::Number,
680 Self::String(_) => CommandOptionType::String,
681 Self::SubCommand(_) => CommandOptionType::SubCommand,
682 Self::SubCommandGroup(_) => CommandOptionType::SubCommandGroup,
683 Self::Attachment(_) => CommandOptionType::Attachment,
684 Self::Channel(_) => CommandOptionType::Channel,
685 Self::Mentionable(_) => CommandOptionType::Mentionable,
686 Self::Role(_) => CommandOptionType::Role,
687 Self::User(_) => CommandOptionType::User,
688 Self::Unknown(unknown) => CommandOptionType::Unknown(*unknown),
689 }
690 }
691
692 #[must_use]
694 pub fn as_bool(&self) -> Option<bool> {
695 match *self {
696 Self::Boolean(b) => Some(b),
697 _ => None,
698 }
699 }
700
701 #[must_use]
703 pub fn as_i64(&self) -> Option<i64> {
704 match *self {
705 Self::Integer(v) => Some(v),
706 _ => None,
707 }
708 }
709
710 #[must_use]
712 pub fn as_f64(&self) -> Option<f64> {
713 match *self {
714 Self::Number(v) => Some(v),
715 _ => None,
716 }
717 }
718
719 #[must_use]
721 pub fn as_str(&self) -> Option<&str> {
722 match self {
723 Self::String(s) => Some(s),
724 Self::Autocomplete {
725 value, ..
726 } => Some(value),
727 _ => None,
728 }
729 }
730
731 #[must_use]
733 pub fn as_attachment_id(&self) -> Option<AttachmentId> {
734 match self {
735 Self::Attachment(id) => Some(*id),
736 _ => None,
737 }
738 }
739
740 #[must_use]
742 pub fn as_channel_id(&self) -> Option<ChannelId> {
743 match self {
744 Self::Channel(id) => Some(*id),
745 _ => None,
746 }
747 }
748
749 #[must_use]
751 pub fn as_mentionable(&self) -> Option<GenericId> {
752 match self {
753 Self::Mentionable(id) => Some(*id),
754 _ => None,
755 }
756 }
757
758 #[must_use]
760 pub fn as_user_id(&self) -> Option<UserId> {
761 match self {
762 Self::User(id) => Some(*id),
763 _ => None,
764 }
765 }
766
767 #[must_use]
769 pub fn as_role_id(&self) -> Option<RoleId> {
770 match self {
771 Self::Role(id) => Some(*id),
772 _ => None,
773 }
774 }
775}
776
777impl TargetId {
778 #[must_use]
780 pub fn to_user_id(self) -> UserId {
781 self.get().into()
782 }
783
784 #[must_use]
786 pub fn to_message_id(self) -> MessageId {
787 self.get().into()
788 }
789}
790
791impl From<MessageId> for TargetId {
792 fn from(id: MessageId) -> Self {
793 Self::new(id.into())
794 }
795}
796
797impl From<UserId> for TargetId {
798 fn from(id: UserId) -> Self {
799 Self::new(id.into())
800 }
801}
802
803impl From<TargetId> for MessageId {
804 fn from(id: TargetId) -> Self {
805 Self::new(id.into())
806 }
807}
808
809impl From<TargetId> for UserId {
810 fn from(id: TargetId) -> Self {
811 Self::new(id.into())
812 }
813}
814
815#[cfg(test)]
816mod tests {
817 use super::*;
818 use crate::json::{assert_json, json};
819
820 #[test]
821 fn nested_options() {
822 let value = CommandDataOption {
823 name: "subcommand_group".into(),
824 value: CommandDataOptionValue::SubCommandGroup(vec![CommandDataOption {
825 name: "subcommand".into(),
826 value: CommandDataOptionValue::SubCommand(vec![CommandDataOption {
827 name: "channel".into(),
828 value: CommandDataOptionValue::Channel(ChannelId::new(3)),
829 }]),
830 }]),
831 };
832
833 assert_json(
834 &value,
835 json!({
836 "name": "subcommand_group",
837 "type": 2,
838 "options": [{
839 "name": "subcommand",
840 "type": 1,
841 "options": [{"name": "channel", "type": 7, "value": "3"}],
842 }]
843 }),
844 );
845 }
846
847 #[test]
848 fn mixed_options() {
849 let value = vec![
850 CommandDataOption {
851 name: "boolean".into(),
852 value: CommandDataOptionValue::Boolean(true),
853 },
854 CommandDataOption {
855 name: "integer".into(),
856 value: CommandDataOptionValue::Integer(1),
857 },
858 CommandDataOption {
859 name: "number".into(),
860 value: CommandDataOptionValue::Number(2.0),
861 },
862 CommandDataOption {
863 name: "string".into(),
864 value: CommandDataOptionValue::String("foobar".into()),
865 },
866 CommandDataOption {
867 name: "empty_subcommand".into(),
868 value: CommandDataOptionValue::SubCommand(vec![]),
869 },
870 CommandDataOption {
871 name: "autocomplete".into(),
872 value: CommandDataOptionValue::Autocomplete {
873 kind: CommandOptionType::Integer,
874 value: "not an integer".into(),
875 },
876 },
877 ];
878
879 assert_json(
880 &value,
881 json!([
882 {"name": "boolean", "type": 5, "value": true},
883 {"name": "integer", "type": 4, "value": 1},
884 {"name": "number", "type": 10, "value": 2.0},
885 {"name": "string", "type": 3, "value": "foobar"},
886 {"name": "empty_subcommand", "type": 1, "options": []},
887 {"name": "autocomplete", "type": 4, "value": "not an integer", "focused": true},
888 ]),
889 );
890 }
891}