diff --git a/src/parser.rs b/src/parser.rs index b4e7bca..3ba7d67 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,7 +5,7 @@ use std::convert::identity; use convert_case::{Case, Casing}; use darling::{ ast::{self, Data}, - util::{Override, PathList}, + util::{Flag, Override, PathList}, Error, FromDeriveInput, FromField, FromMeta, }; use proc_macro2::{Span, TokenStream}; @@ -26,6 +26,7 @@ pub struct ConfigField { typ: Option, get: Option, set: Option, + no_serde: Flag, #[darling(skip)] description: Option, #[darling(skip)] @@ -34,7 +35,7 @@ pub struct ConfigField { impl ConfigField { pub(crate) fn needs_newtype(&self) -> bool { - self.helper_keys().len() > 1 + self.helper_keys().len() > 1 || self.typ.is_some() } pub(crate) fn helper(&self, attrs: &[syn::Attribute]) -> (Option, syn::Type) { @@ -170,7 +171,10 @@ impl ConfigField { }) } - pub(crate) fn helper_serde(&self) -> TokenStream { + pub(crate) fn helper_serde(&self) -> Option { + if self.no_serde.is_present() { + return None; + } let ident = self.helper_ident(); let conversion = if self.has_custom_limits() { quote! { @@ -184,7 +188,7 @@ impl ConfigField { } }; let ty = &self.ty; - quote! { + Some(quote! { impl ::serde::Serialize for #ident { fn serialize(&self, serializer: S) -> ::core::result::Result:: where @@ -204,7 +208,7 @@ impl ConfigField { #conversion } } - } + }) } pub(crate) fn helper_tree(&self) -> TokenStream { @@ -350,6 +354,13 @@ impl ConfigField { .typ .as_ref() .map_or_else(|| quote!(Self), |typ| quote!(#typ)); + let match_range = if num_keys > 1 { + Some( + quote!(1..=#num_keys => ::core::result::Result::Err(::miniconf::Traversal::Access(0, "Cannot write limits").into()),), + ) + } else { + None + }; quote! { impl<'de> ::miniconf::TreeDeserialize<'de, 1> for #ident { fn deserialize_by_key( @@ -374,8 +385,7 @@ impl ConfigField { #set(<#typ as ::serde::Deserialize>::deserialize(de).map_err(|err| ::miniconf::Error::Inner(0, err))?)?; Ok(0) } - , - 1..=#num_keys => ::core::result::Result::Err(::miniconf::Traversal::Access(0, "Cannot write limits").into()), + #match_range _ => unreachable!(), } } @@ -391,6 +401,13 @@ impl ConfigField { } else { quote!(::core::result::Result::Ok(&mut *self)) }; + let match_range = if num_keys > 1 { + Some( + quote!(1..#num_keys => ::core::result::Result::Err(::miniconf::Traversal::Access(1, "cannot return reference to local variable")),), + ) + } else { + None + }; quote! { impl ::miniconf::TreeAny<1> for #ident { fn ref_any_by_key(&self, mut keys: K) -> ::core::result::Result<&dyn ::core::any::Any, ::miniconf::Traversal> @@ -406,7 +423,7 @@ impl ConfigField { } match index { 0 => ::core::result::Result::Ok(&*self), - 1..#num_keys => ::core::result::Result::Err(::miniconf::Traversal::Access(1, "cannot return reference to local variable")), + #match_range _ => unreachable!(), } } @@ -424,7 +441,7 @@ impl ConfigField { } match index { 0 => #ref_mut, - 1..#num_keys => ::core::result::Result::Err(::miniconf::Traversal::Access(1, "cannot return reference to local variable")), + #match_range _ => unreachable!(), } }