diff --git a/src/utils/parsers.rs b/src/utils/parsers.rs index 85eafd17..994c2513 100644 --- a/src/utils/parsers.rs +++ b/src/utils/parsers.rs @@ -1,53 +1,106 @@ -pub use teloxide_macros::TelegramCommandEnum; +pub use teloxide_macros::TelegramBotCommand; /// Enum for telegram commands /// /// Example: /// ``` -/// use teloxide::utils::TelegramCommandEnum; +/// use teloxide::utils::TelegramBotCommand; /// use teloxide::utils::parse_command_into_enum; -/// #[derive(TelegramCommandEnum, PartialEq, Debug)] -/// enum TelegramCommand { -/// Start, -/// Help, +/// #[derive(TelegramBotCommand, PartialEq, Debug)] +/// enum TelegramAdminCommand { +/// Ban, +/// Kick, /// } -/// let (command, args) = parse_command_into_enum::("/", "/start arg1 arg2").unwrap(); -/// assert_eq!(command, TelegramCommand::Start); -/// assert_eq!(args, vec!["arg1", "arg2"]); +/// let (command, args) = parse_command_into_enum::("/ban 5 h").unwrap(); +/// assert_eq!(command, TelegramAdminCommand::Ban); +/// assert_eq!(args, vec!["5", "h"]); /// ``` -pub trait TelegramCommandEnum: Sized { +pub trait TelegramBotCommand: Sized { fn try_from(s: &str) -> Option; } -pub fn parse_command_into_enum<'a, T>( +/// Function to parse message with command into enum. Command must started with `/` +/// +/// Example: +/// ``` +/// use teloxide::utils::TelegramBotCommand; +/// use teloxide::utils::parse_command_into_enum; +/// #[derive(TelegramBotCommand, PartialEq, Debug)] +/// enum TelegramAdminCommand { +/// Ban, +/// Kick, +/// } +/// let (command, args) = parse_command_into_enum::("/ban 5 h").unwrap(); +/// assert_eq!(command, TelegramAdminCommand::Ban); +/// assert_eq!(args, vec!["5", "h"]); +/// ``` +pub fn parse_command_into_enum( + text: &str, +) -> Option<(T, Vec<&str>)> +where + T: TelegramBotCommand, +{ + parse_command_into_enum_with_prefix("/", text) +} + +/// Function to parse message with command with custom prefix into enum. +/// +/// Example: +/// ``` +/// use teloxide::utils::TelegramBotCommand; +/// use teloxide::utils::parse_command_into_enum_with_prefix; +/// #[derive(TelegramBotCommand, PartialEq, Debug)] +/// enum TelegramAdminCommand { +/// Ban, +/// Kick, +/// } +/// let (command, args) = parse_command_into_enum_with_prefix::("!", "!ban 5 h").unwrap(); +/// assert_eq!(command, TelegramAdminCommand::Ban); +/// assert_eq!(args, vec!["5", "h"]); +/// ``` +pub fn parse_command_into_enum_with_prefix<'a, T>( prefix: &str, text: &'a str, ) -> Option<(T, Vec<&'a str>)> where - T: TelegramCommandEnum, + T: TelegramBotCommand, { - let (command, args) = parse_command(prefix,text)?; - return match T::try_from(command) { + let (command, args) = parse_command_with_prefix(prefix, text)?; + match T::try_from(command) { Some(command) => Some((command, args)), _ => None, - }; + } } -/// Function which parse string and return command with args +/// Function which parse string and return command with args. It calls [`parse_command_with_prefix`] with default prefix `/` /// /// Example: /// ``` /// use teloxide::utils::parse_command; /// let text = "/ban 5 hours"; -/// let (command, args) = parse_command("/", text).unwrap(); +/// let (command, args) = parse_command(text).unwrap(); /// assert_eq!(command, "ban"); /// assert_eq!(args, vec!["5", "hours"]); /// ``` -pub fn parse_command<'a>(prefix: &str, text: &'a str) -> Option<(&'a str, Vec<&'a str>)> { +pub fn parse_command(text: &str) -> Option<(&str, Vec<&str>)> { + parse_command_with_prefix("/", text) +} + +/// Function which parse string and return command with args. Prefix - start symbols which denote start of command +/// +/// Example: +/// ``` +/// use teloxide::utils::parse_command_with_prefix; +/// let text = "!ban 5 hours"; +/// let (command, args) = parse_command_with_prefix("!", text).unwrap(); +/// assert_eq!(command, "ban"); +/// assert_eq!(args, vec!["5", "hours"]); +/// ``` +pub fn parse_command_with_prefix<'a>(prefix: &str, text: &'a str) -> Option<(&'a str, Vec<&'a str>)> { if !text.starts_with(prefix) { return None; } let mut words = text.split_whitespace(); - let command = &words.next()?[1..]; + let command = &words.next()?[prefix.len()..]; Some((command, words.collect())) } @@ -59,7 +112,7 @@ mod tests { fn parse_command_with_args_() { let data = "/command arg1 arg2"; let expected = Some(("command", vec!["arg1", "arg2"])); - let actual = parse_command("/", data); + let actual = parse_command(data); assert_eq!(actual, expected) } @@ -67,13 +120,13 @@ mod tests { fn parse_command_with_args_without_args() { let data = "/command"; let expected = Some(("command", vec![])); - let actual = parse_command("/", data); + let actual = parse_command(data); assert_eq!(actual, expected) } #[test] fn parse_command__with_args() { - #[derive(TelegramCommandEnum, Debug, PartialEq)] + #[derive(TelegramBotCommand, Debug, PartialEq)] enum DefaultCommands { Start, Help, @@ -81,7 +134,7 @@ mod tests { let data = "/start arg1 arg2"; let expected = Some((DefaultCommands::Start, vec!["arg1", "arg2"])); - let actual = parse_command_into_enum::("/", data); + let actual = parse_command_into_enum::(data); assert_eq!(actual, expected) } } diff --git a/teloxide-macros/src/lib.rs b/teloxide-macros/src/lib.rs index 748f70da..f56186e6 100644 --- a/teloxide-macros/src/lib.rs +++ b/teloxide-macros/src/lib.rs @@ -4,7 +4,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{DeriveInput, parse_macro_input}; -#[proc_macro_derive(TelegramCommandEnum)] +#[proc_macro_derive(TelegramBotCommand)] pub fn derive_telegram_command_enum(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as DeriveInput); @@ -15,13 +15,13 @@ pub fn derive_telegram_command_enum(tokens: TokenStream) -> TokenStream { variant.ident.to_string().to_lowercase() })) } - _ => panic!("TelegramCommandEnum allowed only for enums") + _ => return TokenStream::from(quote! { compile_error!("TelegramBotCommand allowed only for enums") }) }; let ident = input.ident; let expanded = quote! { - impl TelegramCommandEnum for #ident { + impl TelegramBotCommand for #ident { fn try_from(value: &str) -> Option { match value { #(