mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Improve error handling by adding custom Error
type
This commit is contained in:
parent
3580fd35c5
commit
b16256b8ea
4 changed files with 48 additions and 28 deletions
|
@ -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<String>,
|
||||
pub description: Option<String>,
|
||||
pub parser: Option<ParserType>,
|
||||
|
@ -14,7 +15,7 @@ pub struct Command {
|
|||
}
|
||||
|
||||
impl Command {
|
||||
pub fn try_from(attrs: &[Attr], name: &str) -> Result<Self, String> {
|
||||
pub fn try_from(attrs: &[Attr], name: &str) -> Result<Self> {
|
||||
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<String>,
|
||||
pub(crate) description: Option<String>,
|
||||
pub(crate) rename: Option<String>,
|
||||
|
@ -72,7 +73,7 @@ pub struct CommandAttrs {
|
|||
pub(crate) separator: Option<String>,
|
||||
}
|
||||
|
||||
pub fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs, String> {
|
||||
pub(crate) fn parse_attrs(attrs: &[Attr]) -> Result<CommandAttrs> {
|
||||
let mut prefix = None;
|
||||
let mut description = None;
|
||||
let mut rename_rule = None;
|
||||
|
|
|
@ -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<String>,
|
||||
pub description: Option<String>,
|
||||
pub rename_rule: Option<String>,
|
||||
|
@ -9,7 +12,7 @@ pub struct CommandEnum {
|
|||
}
|
||||
|
||||
impl CommandEnum {
|
||||
pub fn try_from(attrs: &[Attr]) -> Result<Self, String> {
|
||||
pub fn try_from(attrs: &[Attr]) -> Result<Self> {
|
||||
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 {
|
||||
|
|
25
src/error.rs
Normal file
25
src/error.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
pub(crate) struct Error(TokenStream);
|
||||
|
||||
pub(crate) fn compile_error<T>(data: T) -> Error
|
||||
where
|
||||
T: ToTokens,
|
||||
{
|
||||
Error(TokenStream::from(quote! { compile_error!(#data) }))
|
||||
}
|
||||
|
||||
impl From<Error> for proc_macro::TokenStream {
|
||||
fn from(Error(e): Error) -> Self {
|
||||
e.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syn::Error> for Error {
|
||||
fn from(e: syn::Error) -> Self {
|
||||
Self(e.to_compile_error())
|
||||
}
|
||||
}
|
31
src/lib.rs
31
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<TokenStream, TokenStream> {
|
||||
let input = syn::parse_macro_input::parse::<DeriveInput>(tokens)
|
||||
.map_err(|e| compile_error(e.to_compile_error()))?;
|
||||
fn bot_commands_impl(tokens: TokenStream) -> Result<TokenStream, Error> {
|
||||
let input = syn::parse_macro_input::parse::<DeriveInput>(tokens)?;
|
||||
|
||||
let data_enum: &syn::DataEnum = get_enum_data(&input)?;
|
||||
let enum_attrs: Vec<Attr> = 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<TokenStream, TokenStream> {
|
|||
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<Vec<Attr>, TokenStream> {
|
||||
fn parse_attributes(input: &[syn::Attribute]) -> Result<Vec<Attr>> {
|
||||
let mut enum_attrs = Vec::new();
|
||||
for attr in input.iter() {
|
||||
match attr.parse_args::<VecAttrs>() {
|
||||
|
@ -199,10 +197,3 @@ fn parse_attributes(
|
|||
}
|
||||
Ok(enum_attrs)
|
||||
}
|
||||
|
||||
fn compile_error<T>(data: T) -> TokenStream
|
||||
where
|
||||
T: ToTokens,
|
||||
{
|
||||
TokenStream::from(quote! { compile_error!(#data) })
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue