From 65b47996e35b98287499f3a407baf6e3469ace88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20K=C3=A4nner?= Date: Mon, 15 Apr 2024 21:40:32 +0200 Subject: [PATCH] remove unwraps and panics --- src/lib.rs | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 64d25da..4b1b696 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::iter::once; use convert_case::{Case, Casing}; use proc_macro::TokenStream; use proc_macro2::{Span as Span2, TokenStream as TokenStream2}; -use quote::{format_ident, quote}; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse_macro_input, parse_quote, Attribute, DataStruct, DeriveInput, Expr, ExprLit, Field, Ident, Lit, Type, Visibility, @@ -12,10 +12,6 @@ use syn::{ /// Creates structs for the values to extend them with extra metadata. /// /// supported metadata is `min`, `max` and `default`. Doc comments are parsed as `description` -/// -/// # Panics -/// -/// Panics if it is unable to generate a config struct from the input #[proc_macro_attribute] pub fn config(_attr: TokenStream, item: TokenStream) -> TokenStream { let mut input = parse_macro_input!(item as DeriveInput); @@ -33,8 +29,12 @@ pub fn config(_attr: TokenStream, item: TokenStream) -> TokenStream { } } } - syn::Data::Enum(_) => panic!("Enums are not supported"), - syn::Data::Union(_) => panic!("Unions are not supported"), + syn::Data::Enum(_) => { + return quote! {compile_error!("Enums are not supported")}.into(); + } + syn::Data::Union(_) => { + return quote! {compile_error!("Unions are not supported")}.into(); + } } quote! { @@ -145,9 +145,12 @@ fn parse_min( let const_ident = Ident::new(KEY.to_case(Case::Upper).as_str(), Span2::mixed_site()); let (value, new_check) = attr.meta.require_path_only().map_or_else( |_| { - let value = &attr.meta.require_name_value().unwrap().value; + let value = match &attr.meta.require_name_value() { + Ok(meta) => &meta.value, + Err(e) => return (e.to_owned().into_compile_error(), None), + }; ( - quote!(#value), + value.to_token_stream(), Some(quote! { if (value < Self::#const_ident.0) { return None; @@ -177,9 +180,12 @@ fn parse_max( let const_ident = Ident::new(KEY.to_case(Case::Upper).as_str(), Span2::mixed_site()); let (value, new_check) = attr.meta.require_path_only().map_or_else( |_| { - let value = &attr.meta.require_name_value().unwrap().value; + let value = match &attr.meta.require_name_value() { + Ok(meta) => &meta.value, + Err(e) => return (e.to_owned().into_compile_error(), None), + }; ( - quote!(#value), + value.to_token_stream(), Some(quote! { if (value > Self::#const_ident.0) { return None; @@ -208,9 +214,9 @@ fn parse_default( } let const_ident = Ident::new(KEY.to_case(Case::Upper).as_str(), Span2::mixed_site()); let value = attr.meta.require_path_only().map_or_else( - |_| { - let value = &attr.meta.require_name_value().unwrap().value; - quote!(#value) + |_| match &attr.meta.require_name_value() { + Ok(meta) => meta.value.to_token_stream(), + Err(e) => e.to_owned().into_compile_error(), }, |_| quote!(#ty::#const_ident), ); @@ -237,13 +243,24 @@ fn parse_description( return None; } let const_ident = Ident::new(KEY.to_case(Case::Upper).as_str(), Span2::mixed_site()); - let value = &attr.meta.require_name_value().ok()?.value; + let value = match attr.meta.require_name_value() { + Ok(meta) => &meta.value, + Err(e) => { + return Some((e.into_compile_error(), const_ident, KEY)); + } + }; let value = match value { Expr::Lit(ExprLit { attrs: _, lit: Lit::Str(ref string), }) => string.value(), - _ => panic!("doc comment must be a string"), + _ => { + return Some(( + quote!(compile_error!("doc comment must be a string")), + const_ident, + KEY, + )) + } }; let trimmed_value = value.trim(); let impl_quote = quote! {