diff --git a/src/command.rs b/src/command.rs index 446017e1..15216041 100644 --- a/src/command.rs +++ b/src/command.rs @@ -3,9 +3,10 @@ use crate::{ command_enum::CommandEnum, fields_parse::ParserType, rename_rules::rename_by_rule, + Result, }; -pub struct Command { +pub(crate) struct Command { pub prefix: Option, pub description: Option, pub parser: Option, @@ -14,7 +15,7 @@ pub struct Command { } impl Command { - pub fn try_from(attrs: &[Attr], name: &str) -> Result { + pub fn try_from(attrs: &[Attr], name: &str) -> Result { let attrs = parse_attrs(attrs)?; let mut new_name = name.to_string(); let mut renamed = false; @@ -64,7 +65,7 @@ impl Command { } } -pub struct CommandAttrs { +pub(crate) struct CommandAttrs { pub(crate) prefix: Option, pub(crate) description: Option, pub(crate) rename: Option, @@ -72,7 +73,7 @@ pub struct CommandAttrs { pub(crate) separator: Option, } -pub fn parse_attrs(attrs: &[Attr]) -> Result { +pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result { let mut prefix = None; let mut description = None; let mut rename_rule = None; diff --git a/src/command_enum.rs b/src/command_enum.rs index 18b8bf95..46b12a1e 100644 --- a/src/command_enum.rs +++ b/src/command_enum.rs @@ -1,7 +1,10 @@ -use crate::{attr::Attr, command::parse_attrs, fields_parse::ParserType}; +use crate::{ + attr::Attr, command::parse_attrs, error::compile_error, + fields_parse::ParserType, Result, +}; #[derive(Debug)] -pub struct CommandEnum { +pub(crate) struct CommandEnum { pub prefix: Option, pub description: Option, pub rename_rule: Option, @@ -9,7 +12,7 @@ pub struct CommandEnum { } impl CommandEnum { - pub fn try_from(attrs: &[Attr]) -> Result { + pub fn try_from(attrs: &[Attr]) -> Result { let attrs = parse_attrs(attrs)?; let prefix = attrs.prefix; @@ -32,7 +35,7 @@ impl CommandEnum { | "SCREAMING_SNAKE_CASE" | "kebab-case" | "SCREAMING-KEBAB-CASE" => {} - _ => return Err("disallowed value".to_owned()), + _ => return Err(compile_error("disallowed value")), } } Ok(Self { diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..950a85d9 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; + +pub(crate) type Result = std::result::Result; + +pub(crate) struct Error(TokenStream); + +pub(crate) fn compile_error(data: T) -> Error +where + T: ToTokens, +{ + Error(TokenStream::from(quote! { compile_error!(#data) })) +} + +impl From for proc_macro::TokenStream { + fn from(Error(e): Error) -> Self { + e.into() + } +} + +impl From for Error { + fn from(e: syn::Error) -> Self { + Self(e.to_compile_error()) + } +} diff --git a/src/lib.rs b/src/lib.rs index fb256d9c..a4406f88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ mod attr; mod command; mod command_enum; +mod error; mod fields_parse; mod rename_rules; @@ -16,22 +17,22 @@ use crate::{ fields_parse::{impl_parse_args_named, impl_parse_args_unnamed}, }; use proc_macro::TokenStream; -use quote::{quote, ToTokens}; +use quote::quote; use syn::{DeriveInput, Fields}; +pub(crate) use error::{compile_error, Error, Result}; + #[proc_macro_derive(BotCommands, attributes(command))] pub fn bot_commands_derive(tokens: TokenStream) -> TokenStream { - bot_commands_impl(tokens).unwrap_or_else(|err| err) + bot_commands_impl(tokens).unwrap_or_else(Error::into) } -fn bot_commands_impl(tokens: TokenStream) -> Result { - let input = syn::parse_macro_input::parse::(tokens) - .map_err(|e| compile_error(e.to_compile_error()))?; +fn bot_commands_impl(tokens: TokenStream) -> Result { + let input = syn::parse_macro_input::parse::(tokens)?; let data_enum: &syn::DataEnum = get_enum_data(&input)?; let enum_attrs: Vec = parse_attributes(&input.attrs)?; - let command_enum = - CommandEnum::try_from(enum_attrs.as_slice()).map_err(compile_error)?; + let command_enum = CommandEnum::try_from(enum_attrs.as_slice())?; let variants: Vec<&syn::Variant> = data_enum.variants.iter().collect(); @@ -45,8 +46,7 @@ fn bot_commands_impl(tokens: TokenStream) -> Result { attrs.append(attrs_.data.as_mut()); } let command = - Command::try_from(attrs.as_slice(), &variant.ident.to_string()) - .map_err(compile_error)?; + Command::try_from(attrs.as_slice(), &variant.ident.to_string())?; variant_infos.push(command); } @@ -176,16 +176,14 @@ fn impl_parse( } } -fn get_enum_data(input: &DeriveInput) -> Result<&syn::DataEnum, TokenStream> { +fn get_enum_data(input: &DeriveInput) -> Result<&syn::DataEnum> { match &input.data { syn::Data::Enum(data) => Ok(data), _ => Err(compile_error("TelegramBotCommand allowed only for enums")), } } -fn parse_attributes( - input: &[syn::Attribute], -) -> Result, TokenStream> { +fn parse_attributes(input: &[syn::Attribute]) -> Result> { let mut enum_attrs = Vec::new(); for attr in input.iter() { match attr.parse_args::() { @@ -199,10 +197,3 @@ fn parse_attributes( } Ok(enum_attrs) } - -fn compile_error(data: T) -> TokenStream -where - T: ToTokens, -{ - TokenStream::from(quote! { compile_error!(#data) }) -}