mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 22:46:39 +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,
|
command_enum::CommandEnum,
|
||||||
fields_parse::ParserType,
|
fields_parse::ParserType,
|
||||||
rename_rules::rename_by_rule,
|
rename_rules::rename_by_rule,
|
||||||
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Command {
|
pub(crate) struct Command {
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub parser: Option<ParserType>,
|
pub parser: Option<ParserType>,
|
||||||
|
@ -14,7 +15,7 @@ pub struct Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 attrs = parse_attrs(attrs)?;
|
||||||
let mut new_name = name.to_string();
|
let mut new_name = name.to_string();
|
||||||
let mut renamed = false;
|
let mut renamed = false;
|
||||||
|
@ -64,7 +65,7 @@ impl Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommandAttrs {
|
pub(crate) struct CommandAttrs {
|
||||||
pub(crate) prefix: Option<String>,
|
pub(crate) prefix: Option<String>,
|
||||||
pub(crate) description: Option<String>,
|
pub(crate) description: Option<String>,
|
||||||
pub(crate) rename: Option<String>,
|
pub(crate) rename: Option<String>,
|
||||||
|
@ -72,7 +73,7 @@ pub struct CommandAttrs {
|
||||||
pub(crate) separator: Option<String>,
|
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 prefix = None;
|
||||||
let mut description = None;
|
let mut description = None;
|
||||||
let mut rename_rule = 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)]
|
#[derive(Debug)]
|
||||||
pub struct CommandEnum {
|
pub(crate) struct CommandEnum {
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub rename_rule: Option<String>,
|
pub rename_rule: Option<String>,
|
||||||
|
@ -9,7 +12,7 @@ pub struct CommandEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 attrs = parse_attrs(attrs)?;
|
||||||
|
|
||||||
let prefix = attrs.prefix;
|
let prefix = attrs.prefix;
|
||||||
|
@ -32,7 +35,7 @@ impl CommandEnum {
|
||||||
| "SCREAMING_SNAKE_CASE"
|
| "SCREAMING_SNAKE_CASE"
|
||||||
| "kebab-case"
|
| "kebab-case"
|
||||||
| "SCREAMING-KEBAB-CASE" => {}
|
| "SCREAMING-KEBAB-CASE" => {}
|
||||||
_ => return Err("disallowed value".to_owned()),
|
_ => return Err(compile_error("disallowed value")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Self {
|
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 attr;
|
||||||
mod command;
|
mod command;
|
||||||
mod command_enum;
|
mod command_enum;
|
||||||
|
mod error;
|
||||||
mod fields_parse;
|
mod fields_parse;
|
||||||
mod rename_rules;
|
mod rename_rules;
|
||||||
|
|
||||||
|
@ -16,22 +17,22 @@ use crate::{
|
||||||
fields_parse::{impl_parse_args_named, impl_parse_args_unnamed},
|
fields_parse::{impl_parse_args_named, impl_parse_args_unnamed},
|
||||||
};
|
};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{quote, ToTokens};
|
use quote::quote;
|
||||||
use syn::{DeriveInput, Fields};
|
use syn::{DeriveInput, Fields};
|
||||||
|
|
||||||
|
pub(crate) use error::{compile_error, Error, Result};
|
||||||
|
|
||||||
#[proc_macro_derive(BotCommands, attributes(command))]
|
#[proc_macro_derive(BotCommands, attributes(command))]
|
||||||
pub fn bot_commands_derive(tokens: TokenStream) -> TokenStream {
|
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> {
|
fn bot_commands_impl(tokens: TokenStream) -> Result<TokenStream, Error> {
|
||||||
let input = syn::parse_macro_input::parse::<DeriveInput>(tokens)
|
let input = syn::parse_macro_input::parse::<DeriveInput>(tokens)?;
|
||||||
.map_err(|e| compile_error(e.to_compile_error()))?;
|
|
||||||
|
|
||||||
let data_enum: &syn::DataEnum = get_enum_data(&input)?;
|
let data_enum: &syn::DataEnum = get_enum_data(&input)?;
|
||||||
let enum_attrs: Vec<Attr> = parse_attributes(&input.attrs)?;
|
let enum_attrs: Vec<Attr> = parse_attributes(&input.attrs)?;
|
||||||
let command_enum =
|
let command_enum = CommandEnum::try_from(enum_attrs.as_slice())?;
|
||||||
CommandEnum::try_from(enum_attrs.as_slice()).map_err(compile_error)?;
|
|
||||||
|
|
||||||
let variants: Vec<&syn::Variant> = data_enum.variants.iter().collect();
|
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());
|
attrs.append(attrs_.data.as_mut());
|
||||||
}
|
}
|
||||||
let command =
|
let command =
|
||||||
Command::try_from(attrs.as_slice(), &variant.ident.to_string())
|
Command::try_from(attrs.as_slice(), &variant.ident.to_string())?;
|
||||||
.map_err(compile_error)?;
|
|
||||||
|
|
||||||
variant_infos.push(command);
|
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 {
|
match &input.data {
|
||||||
syn::Data::Enum(data) => Ok(data),
|
syn::Data::Enum(data) => Ok(data),
|
||||||
_ => Err(compile_error("TelegramBotCommand allowed only for enums")),
|
_ => Err(compile_error("TelegramBotCommand allowed only for enums")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_attributes(
|
fn parse_attributes(input: &[syn::Attribute]) -> Result<Vec<Attr>> {
|
||||||
input: &[syn::Attribute],
|
|
||||||
) -> Result<Vec<Attr>, TokenStream> {
|
|
||||||
let mut enum_attrs = Vec::new();
|
let mut enum_attrs = Vec::new();
|
||||||
for attr in input.iter() {
|
for attr in input.iter() {
|
||||||
match attr.parse_args::<VecAttrs>() {
|
match attr.parse_args::<VecAttrs>() {
|
||||||
|
@ -199,10 +197,3 @@ fn parse_attributes(
|
||||||
}
|
}
|
||||||
Ok(enum_attrs)
|
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