diff --git a/CHANGELOG.md b/CHANGELOG.md index 96ef58d6..aecef03e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * Deserializing with borrowed data is now supported. +* [derive] Added `#[tree(skip)]` macro attribute to allow skipping entries. ## [0.8.0](https://github.com/quartiq/miniconf/compare/v0.7.1...v0.8.0) - 2023-08-03 diff --git a/README.md b/README.md index c85473a4..82e07eb7 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,10 @@ struct Settings { array: [i32; 2], option: Option, + // Exclude an element (not Deserialize/Serialize) + #[tree(skip)] + skipped: (), + // Exposing elements of containers // ... by field name #[tree] diff --git a/miniconf_derive/src/field.rs b/miniconf_derive/src/field.rs index 66d58d13..c1a51f12 100644 --- a/miniconf_derive/src/field.rs +++ b/miniconf_derive/src/field.rs @@ -14,17 +14,13 @@ impl StructField { } .iter() .cloned() - .map(Self::new) + .filter_map(Self::new) .collect() } - pub fn new(field: syn::Field) -> Self { - let depth = Self::parse_depth(&field); - Self { field, depth } - } - - fn parse_depth(field: &syn::Field) -> usize { + pub fn new(field: syn::Field) -> Option { let mut depth = 0; + let mut skip = false; for attr in field.attrs.iter() { if attr.path().is_ident("tree") { @@ -39,6 +35,9 @@ impl StructField { let lit: LitInt = content.parse()?; depth = lit.base10_parse()?; Ok(()) + } else if meta.path.is_ident("skip") { + skip = true; + Ok(()) } else { Err(meta.error(format!("unrecognized miniconf attribute {:?}", meta.path))) } @@ -46,7 +45,11 @@ impl StructField { .unwrap(); } } - depth + if skip { + None + } else { + Some(Self { field, depth }) + } } fn walk_type_params( diff --git a/src/array.rs b/src/array.rs index 59b2a74e..ef0c9922 100644 --- a/src/array.rs +++ b/src/array.rs @@ -17,7 +17,7 @@ const fn digits(x: usize) -> usize { macro_rules! depth { ($($y:literal)+) => {$( impl, const N: usize> TreeKey<$y> for [T; N] { - fn name_to_index(value: &str) -> core::option::Option { + fn name_to_index(value: &str) -> Option { value.parse().ok() } fn traverse_by_key(mut keys: K, mut func: F) -> Result> @@ -79,7 +79,7 @@ depth!(2 3 4 5 6 7 8); // Y == 1 impl TreeKey for [T; N] { - fn name_to_index(value: &str) -> core::option::Option { + fn name_to_index(value: &str) -> Option { value.parse().ok() } diff --git a/src/tree.rs b/src/tree.rs index 08ffbe18..20575ceb 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1,4 +1,5 @@ use crate::PathIter; +use core::fmt::{Display, Formatter, Write}; use serde::{Deserializer, Serializer}; /// Errors that can occur when using the Tree traits. @@ -44,8 +45,8 @@ pub enum Error { PostDeserialization(E), } -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { Error::Absent(index) => { write!(f, "Path is not currently available (Key level: {})", index) @@ -140,13 +141,13 @@ impl Metadata { /// Capability to convert a key into a node index for a given `M: TreeKey`. pub trait Key { /// Convert the key `self` to a `usize` index. - fn find>(&self) -> core::option::Option; + fn find>(&self) -> Option; } // `usize` index as Key impl Key for usize { #[inline] - fn find(&self) -> core::option::Option { + fn find(&self) -> Option { Some(*self) } } @@ -154,7 +155,7 @@ impl Key for usize { // &str name as Key impl Key for &str { #[inline] - fn find>(&self) -> core::option::Option { + fn find>(&self) -> Option { M::name_to_index(self) } } @@ -322,7 +323,7 @@ pub trait TreeKey { /// } /// assert_eq!(S::name_to_index("bar"), Some(1)); /// ``` - fn name_to_index(name: &str) -> core::option::Option; + fn name_to_index(name: &str) -> Option; /// Call a function for each node on the path described by keys. /// @@ -414,7 +415,7 @@ pub trait TreeKey { where K: IntoIterator, K::Item: Key, - P: core::fmt::Write, + P: Write, { Self::traverse_by_key(keys.into_iter(), |_index, name| { path.write_str(sep).and_then(|_| path.write_str(name)) @@ -492,7 +493,7 @@ pub trait TreeKey { /// # Returns /// An iterator of paths with a trusted and exact [`Iterator::size_hint()`]. #[inline] - fn iter_paths(sep: &str) -> PathIter<'_, Self, Y, P> { + fn iter_paths(sep: &str) -> PathIter<'_, Self, Y, P> { PathIter::new(sep) } @@ -522,7 +523,7 @@ pub trait TreeKey { /// # Returns /// A iterator of paths. #[inline] - fn iter_paths_unchecked(sep: &str) -> PathIter<'_, Self, Y, P> { + fn iter_paths_unchecked(sep: &str) -> PathIter<'_, Self, Y, P> { PathIter::new_unchecked(sep) } }