From 8b4470838203e201ed5b53d64be1cbfab3baa985 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Thu, 7 Mar 2024 22:19:40 +0000 Subject: [PATCH] Remove content and prefix from PrefixContext --- src/builtins/mod.rs | 5 ++-- src/dispatch/prefix.rs | 45 ++++++++++++++++++++-------------- src/structs/context.rs | 2 +- src/structs/framework_error.rs | 13 +++++----- src/structs/prefix.rs | 10 ++++---- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 54a1be635ac3..30868bb0fffc 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -179,10 +179,9 @@ pub async fn on_error( ); } crate::FrameworkError::UnknownCommand { - msg_content, - prefix, - .. + msg, content_start, .. } => { + let (prefix, msg_content) = msg.content.split_at(content_start.into()); tracing::warn!( "Recognized prefix `{}`, but didn't recognize command name in `{}`", prefix, diff --git a/src/dispatch/prefix.rs b/src/dispatch/prefix.rs index 235a3df13e10..d517772cf4c5 100644 --- a/src/dispatch/prefix.rs +++ b/src/dispatch/prefix.rs @@ -1,14 +1,24 @@ //! Dispatches incoming messages and message edits onto framework commands +use std::convert::TryInto as _; + use crate::serenity_prelude as serenity; +/// Converts a prefix string's length into u16, panicking if it doesn't fit. +fn prefix_len_to_u16(prefix: &str) -> u16 { + prefix + .len() + .try_into() + .expect("messages should not be more than 64k bytes, let alone a prefix") +} + /// Checks if this message is a bot invocation by attempting to strip the prefix /// /// Returns tuple of stripped prefix and rest of the message, if any prefix matches async fn strip_prefix<'a, U, E>( framework: crate::FrameworkContext<'a, U, E>, msg: &'a serenity::Message, -) -> Option<(&'a str, &'a str)> { +) -> Option { let partial_ctx = crate::PartialContext { guild_id: msg.guild_id, channel_id: msg.channel_id, @@ -22,7 +32,7 @@ async fn strip_prefix<'a, U, E>( Ok(prefix) => { if let Some(prefix) = prefix { if msg.content.starts_with(prefix.as_ref()) { - return Some(msg.content.split_at(prefix.len())); + return Some(prefix_len_to_u16(&prefix)); } } } @@ -38,22 +48,22 @@ async fn strip_prefix<'a, U, E>( } if let Some(prefix) = framework.options.prefix_options.prefix.as_deref() { - if let Some(content) = msg.content.strip_prefix(prefix) { - return Some((prefix, content)); + if msg.content.starts_with(prefix) { + return Some(prefix_len_to_u16(prefix)); } } - if let Some((prefix, content)) = framework + if let Some(prefix) = framework .options .prefix_options .additional_prefixes .iter() .find_map(|prefix| match prefix { - &crate::Prefix::Literal(prefix) => Some((prefix, msg.content.strip_prefix(prefix)?)), + &crate::Prefix::Literal(prefix) => Some(prefix), crate::Prefix::Regex(prefix) => { let regex_match = prefix.find(&msg.content)?; if regex_match.start() == 0 { - Some(msg.content.split_at(regex_match.end())) + Some(msg.content.split_at(regex_match.end()).0) } else { None } @@ -61,14 +71,14 @@ async fn strip_prefix<'a, U, E>( crate::Prefix::__NonExhaustive => unreachable!(), }) { - return Some((prefix, content)); + return Some(prefix_len_to_u16(prefix)); } if let Some(dynamic_prefix) = framework.options.prefix_options.stripped_dynamic_prefix { match dynamic_prefix(framework.serenity_context, msg, framework.user_data).await { Ok(result) => { - if let Some((prefix, content)) = result { - return Some((prefix, content)); + if let Some(prefix) = result { + return Some(prefix_len_to_u16(prefix)); } } Err(error) => { @@ -92,7 +102,7 @@ async fn strip_prefix<'a, U, E>( .strip_prefix('>') })() { let mention_prefix = &msg.content[..(msg.content.len() - stripped_content.len())]; - return Some((mention_prefix, stripped_content)); + return Some(prefix_len_to_u16(mention_prefix)); } } @@ -242,11 +252,11 @@ pub async fn parse_invocation<'a, U: Send + Sync, E>( } // Strip prefix, trim whitespace between prefix and rest, split rest into command name and args - let (prefix, msg_content) = match strip_prefix(framework, msg).await { - Some(x) => x, - None => return Ok(None), + let Some(content_start) = strip_prefix(framework, msg).await else { + return Ok(None); }; - let msg_content = msg_content.trim_start(); + + let msg_content = msg.content.split_at(content_start.into()).1.trim_start(); let (command, invoked_command_name, args) = find_command( &framework.options.commands, @@ -256,8 +266,7 @@ pub async fn parse_invocation<'a, U: Send + Sync, E>( ) .ok_or(crate::FrameworkError::UnknownCommand { msg, - prefix, - msg_content, + content_start, framework, invocation_data, trigger, @@ -269,7 +278,7 @@ pub async fn parse_invocation<'a, U: Send + Sync, E>( Ok(Some(crate::PrefixContext { msg, - prefix, + content_start, invoked_command_name, args, framework, diff --git a/src/structs/context.rs b/src/structs/context.rs index 74a5dadd3f96..00e45d891f3a 100644 --- a/src/structs/context.rs +++ b/src/structs/context.rs @@ -348,7 +348,7 @@ context_methods! { (prefix self) (pub fn prefix(self) -> &'a str) { match self { - Context::Prefix(ctx) => ctx.prefix, + Context::Prefix(ctx) => ctx.msg.content.split_at(ctx.content_start.into()).0, Context::Application(_) => "/", } } diff --git a/src/structs/framework_error.rs b/src/structs/framework_error.rs index 441a654b6e48..284d1b675480 100644 --- a/src/structs/framework_error.rs +++ b/src/structs/framework_error.rs @@ -164,12 +164,8 @@ pub enum FrameworkError<'a, U, E> { UnknownCommand { /// The message in question msg: &'a serenity::Message, - /// The prefix that was recognized - prefix: &'a str, - /// The rest of the message (after the prefix) which was not recognized as a command - /// - /// This is a single field instead of two fields (command name and args) due to subcommands - msg_content: &'a str, + /// The position in the message that the prefix ends. + content_start: u16, /// Framework context #[derivative(Debug = "ignore")] framework: crate::FrameworkContext<'a, U, E>, @@ -403,7 +399,10 @@ impl std::fmt::Display for FrameworkError<'_, U, E> { msg.content ) } - Self::UnknownCommand { msg_content, .. } => { + Self::UnknownCommand { + content_start, msg, .. + } => { + let (_prefix, msg_content) = msg.content.split_at((*content_start).into()); write!(f, "unknown command `{}`", msg_content) } Self::UnknownInteraction { interaction, .. } => { diff --git a/src/structs/prefix.rs b/src/structs/prefix.rs index 539f0190d3a2..f77cd2efcb86 100644 --- a/src/structs/prefix.rs +++ b/src/structs/prefix.rs @@ -26,8 +26,8 @@ pub enum MessageDispatchTrigger { pub struct PrefixContext<'a, U, E> { /// The invoking user message pub msg: &'a serenity::Message, - /// Prefix used by the user to invoke this command - pub prefix: &'a str, + /// Position in the string that the prefix used by the user to invoke this command ends. + pub content_start: u16, /// Command name used by the user to invoke this command pub invoked_command_name: &'a str, /// Entire argument string @@ -97,12 +97,12 @@ pub struct PrefixFrameworkOptions { /// /// Override this field for advanced dynamic prefixes which change depending on guild or user. /// - /// Return value is a tuple of the prefix and the rest of the message: + /// Return value is the prefix found /// ```rust,no_run /// # poise::PrefixFrameworkOptions::<(), ()> { stripped_dynamic_prefix: Some(|_, msg, _| Box::pin(async move { /// let my_cool_prefix = "$"; /// if msg.content.starts_with(my_cool_prefix) { - /// return Ok(Some(msg.content.split_at(my_cool_prefix.len()))); + /// return Ok(Some(msg.content.split_at(my_cool_prefix.len()).0)); /// } /// Ok(None) /// # })), ..Default::default() }; @@ -113,7 +113,7 @@ pub struct PrefixFrameworkOptions { &'a serenity::Context, &'a serenity::Message, &'a U, - ) -> BoxFuture<'a, Result, E>>, + ) -> BoxFuture<'a, Result, E>>, >, /// Treat a bot mention (a ping) like a prefix pub mention_as_prefix: bool,