diff --git a/itconfig-macro/src/ast.rs b/itconfig-macro/src/ast.rs index 4425e34..e3ea887 100644 --- a/itconfig-macro/src/ast.rs +++ b/itconfig-macro/src/ast.rs @@ -2,14 +2,14 @@ use crate::utils::SupportedBox; use proc_macro2::TokenStream as TokenStream2; use syn::{Attribute, Expr, Ident, Type}; -pub struct RootNamespace { +pub(crate) struct RootNamespace { pub name: Option, pub variables: Vec, pub namespaces: Vec, pub meta: Vec, } -pub struct Namespace { +pub(crate) struct Namespace { pub name: Ident, pub variables: Vec, pub namespaces: Vec, @@ -17,7 +17,7 @@ pub struct Namespace { pub meta: Vec, } -pub struct Variable { +pub(crate) struct Variable { pub is_static: bool, pub name: Ident, pub ty: Type, diff --git a/itconfig-macro/src/expand.rs b/itconfig-macro/src/expand.rs index 3aa9dae..6894aac 100644 --- a/itconfig-macro/src/expand.rs +++ b/itconfig-macro/src/expand.rs @@ -138,8 +138,8 @@ impl ToTokens for Variable { }} } else if let Some(initial) = &self.initial { match self.supported_box.clone() { - Some(SupportedBox::Vec(sep)) => { - let sep = &sep.unwrap_or_else(|| String::from(",")); + Some(SupportedBox::Vec(params)) => { + let sep = ¶ms.sep(); quote!(::itconfig::get_vec_env_or_set_default(#env_name, #sep, #initial)) } _ => quote!(::itconfig::get_env_or_set_default(#env_name, #initial)), @@ -149,12 +149,12 @@ impl ToTokens for Variable { Some(SupportedBox::Option) => { quote!(::itconfig::maybe_get_env(#env_name)) } - Some(SupportedBox::OptionVec(sep)) => { - let sep = &sep.unwrap_or_else(|| String::from(",")); + Some(SupportedBox::OptionVec(params)) => { + let sep = ¶ms.sep(); quote!(::itconfig::maybe_get_vec_env(#env_name, #sep)) } - Some(SupportedBox::Vec(sep)) => { - let sep = &sep.unwrap_or_else(|| String::from(",")); + Some(SupportedBox::Vec(params)) => { + let sep = ¶ms.sep(); quote!(::itconfig::get_vec_env_or_panic(#env_name, #sep)) } None => { diff --git a/itconfig-macro/src/parse.rs b/itconfig-macro/src/parse.rs index 9755b1a..7440da3 100644 --- a/itconfig-macro/src/parse.rs +++ b/itconfig-macro/src/parse.rs @@ -1,5 +1,5 @@ use crate::ast::*; -use crate::utils::{maybe_supported_box, SupportedBox}; +use crate::utils::{maybe_supported_box, SupportedBox, VecBoxParams}; use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::quote; use syn::ext::IdentExt; @@ -60,7 +60,8 @@ fn parse_namespace_content( for attr in attributes { if attr.path.is_ident("env_prefix") { - namespace.env_prefix = parse_attribute(attr, "env_prefix", &namespace.env_prefix)?; + let env_prefix = parse_attribute(attr, "env_prefix", &namespace.env_prefix)?; + namespace.env_prefix = Some(env_prefix); } else { namespace.meta.push(attr); } @@ -72,12 +73,14 @@ fn parse_namespace_content( for attr in attributes { if attr.path.is_ident("env_name") { - variable.env_name = parse_attribute(attr, "env_name", &variable.env_name)?; + let env_name = parse_attribute(attr, "env_name", &variable.env_name)?; + variable.env_name = Some(env_name); } else { match variable.supported_box { - Some(SupportedBox::Vec(current_sep)) if attr.path.is_ident("sep") => { - let sep = parse_attribute(attr, "sep", ¤t_sep)?; - variable.supported_box = Some(SupportedBox::Vec(sep)); + Some(SupportedBox::Vec(params)) if attr.path.is_ident("sep") => { + let sep = parse_attribute(attr, "sep", ¶ms.sep_opt())?; + variable.supported_box = + Some(SupportedBox::Vec(VecBoxParams::new(Some(sep)))); } _ => variable.meta.push(attr), } @@ -90,11 +93,7 @@ fn parse_namespace_content( Ok(()) } -fn parse_attribute( - attr: Attribute, - name: &'static str, - var: &Option, -) -> Result> { +fn parse_attribute(attr: Attribute, name: &'static str, var: &Option) -> Result { if var.is_some() { let message = format!("You cannot use {} meta twice", &name); return Err(Error::new_spanned(attr, message)); @@ -104,7 +103,7 @@ fn parse_attribute( Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. - }) => Ok(Some(lit_str.value())), + }) => Ok(lit_str.value()), _ => { let message = format!("expected #[{} = \"...\"]", &name); Err(Error::new_spanned(attr, message)) diff --git a/itconfig-macro/src/utils.rs b/itconfig-macro/src/utils.rs index 1c4d71a..fe62e95 100644 --- a/itconfig-macro/src/utils.rs +++ b/itconfig-macro/src/utils.rs @@ -5,14 +5,34 @@ use syn::{GenericArgument, Path, PathArguments, Type}; const OPTION_PATH_IDENTS: &[&str] = &["Option|", "std|option|Option|", "core|option|Option|"]; const VEC_PATH_IDENTS: &[&str] = &["Vec|", "std|vec|Vec|"]; -#[derive(Debug, Clone)] -pub enum SupportedBox { - Vec(Option), - Option, - OptionVec(Option), +#[derive(Debug, Clone, Default)] +pub(crate) struct VecBoxParams(Option); + +impl VecBoxParams { + #[inline] + pub(crate) fn new(sep: Option) -> Self { + VecBoxParams(sep) + } + + #[inline] + pub(crate) fn sep_opt(&self) -> Option { + self.0.clone() + } + + #[inline] + pub(crate) fn sep(&self) -> String { + self.0.clone().unwrap_or_else(|| String::from(",")) + } } -pub fn vec_to_token_stream_2(input: &[T]) -> Vec +#[derive(Debug, Clone)] +pub(crate) enum SupportedBox { + Vec(VecBoxParams), + Option, + OptionVec(VecBoxParams), +} + +pub(crate) fn vec_to_token_stream_2(input: &[T]) -> Vec where T: ToTokens, { @@ -38,27 +58,27 @@ fn is_vec_path_ident(path_ident: &str) -> bool { VEC_PATH_IDENTS.iter().any(|s| path_ident == *s) } -pub fn maybe_supported_box(ty: &Type) -> Option { +pub(crate) fn maybe_supported_box(ty: &Type) -> Option { match ty { Type::Path(ty_path) if ty_path.qself.is_none() => { let ty_path_ident = path_ident(&ty_path.path); if is_option_path_ident(&ty_path_ident) { - match &ty_path.path.segments.iter().last().unwrap().arguments { - PathArguments::AngleBracketed(params) => match params.args.first() { - Some(GenericArgument::Type(Type::Path(inner_ty_path))) => { - let ty_path_ident = path_ident(&inner_ty_path.path); - if is_vec_path_ident(&ty_path_ident) { - Some(SupportedBox::OptionVec(None)) - } else { - Some(SupportedBox::Option) - } + if let PathArguments::AngleBracketed(params) = + &ty_path.path.segments.iter().last().unwrap().arguments + { + if let Some(GenericArgument::Type(Type::Path(inner_ty_path))) = + params.args.first() + { + let ty_path_ident = path_ident(&inner_ty_path.path); + if is_vec_path_ident(&ty_path_ident) { + return Some(SupportedBox::OptionVec(Default::default())); } - _ => Some(SupportedBox::Option), - }, - _ => Some(SupportedBox::Option), + } } + + Some(SupportedBox::Option) } else if is_vec_path_ident(&ty_path_ident) { - Some(SupportedBox::Vec(None)) + Some(SupportedBox::Vec(Default::default())) } else { None }