tulpje-framework 0.17.0

Multi-purpose discord bot & framework
Documentation
use twilight_model::{
    application::interaction::{
        InteractionData,
        application_command::{CommandDataOption, CommandOptionValue},
    },
    gateway::payload::incoming::InteractionCreate,
};

use crate::{Error, Metadata, context};

pub fn parse<T: Clone + Send + Sync>(
    event: &InteractionCreate,
    meta: Metadata,
    ctx: context::Context<T>,
) -> Result<context::InteractionContext<T>, Error> {
    match &event.data {
        Some(InteractionData::ApplicationCommand(command)) => {
            let (name, options) = extract_command(&command.name, &command.options, &mut Vec::new());
            Ok(context::InteractionContext::<T>::Command(
                context::CommandContext::from_context(
                    meta,
                    ctx,
                    event.clone(),
                    *command.clone(),
                    name,
                    options,
                ),
            ))
        }
        Some(InteractionData::MessageComponent(interaction)) => {
            Ok(context::InteractionContext::<T>::ComponentInteraction(
                context::ComponentInteractionContext::from_context(
                    ctx,
                    meta,
                    event.clone(),
                    *interaction.clone(),
                ),
            ))
        }
        Some(InteractionData::ModalSubmit(data)) => Ok(context::InteractionContext::<T>::Modal(
            context::ModalContext::from_context(ctx, meta, event.clone(), *data.clone()),
        )),
        Some(_) => Err(format!("unknown interaction type: {:?}", event.kind).into()),
        None => Err("no interaction data".into()),
    }
}

fn extract_command<'a>(
    name: &'a str,
    options: &'a [CommandDataOption],
    parents: &mut Vec<&'a str>,
) -> (String, &'a [CommandDataOption]) {
    parents.push(name);

    if let Some((name, options)) = options.iter().find_map(|opt| match opt.value {
        CommandOptionValue::SubCommand(ref sub_options)
        | CommandOptionValue::SubCommandGroup(ref sub_options) => Some((&opt.name, sub_options)),
        _ => None,
    }) {
        extract_command(name, options, parents)
    } else {
        (parents.join(" "), options)
    }
}