From c7980494439d56639884d69b6c24c78893f3a4c9 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Fri, 30 Apr 2021 17:51:06 +0200 Subject: [PATCH] Require single `config` root object Otherwise global attributes and attributes for the root object have the same syntax (`#![...]`). This way, it is way clearer. --- examples/simple.rs | 20 +++++++++++--------- macro/src/parse.rs | 43 ++++++++++++++++++++----------------------- src/example.rs | 43 ++++++++++++++++++++++--------------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 3d599c7..bc4ba22 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -5,16 +5,18 @@ mod config { confique::config! { #![derive_for_all(Debug, Clone)] - log: { - /// Determines how many messages are logged. Log messages below - /// this level are not emitted. Possible values: "trace", "debug", - /// "info", "warn", "error" and "off". - level: log::LevelFilter = "debug", + config: { + log: { + /// Determines how many messages are logged. Log messages below + /// this level are not emitted. Possible values: "trace", "debug", + /// "info", "warn", "error" and "off". + level: log::LevelFilter = "debug", - /// If this is set, log messages are also written to this file. - #[example = "/var/log/test.log"] - file: Option, - }, + /// If this is set, log messages are also written to this file. + #[example = "/var/log/test.log"] + file: Option, + }, + } } } diff --git a/macro/src/parse.rs b/macro/src/parse.rs index f4aa46f..9deb87d 100644 --- a/macro/src/parse.rs +++ b/macro/src/parse.rs @@ -1,4 +1,4 @@ -use proc_macro2::{Span, TokenStream}; +use proc_macro2::TokenStream; use quote::ToTokens; use syn::{ Error, Ident, @@ -16,31 +16,28 @@ impl Parse for Input { let mut outer_attrs = input.call(syn::Attribute::parse_inner)?; let visibility = extract_visibility(&mut outer_attrs)?; let derive_for_all = extract_single_list_attr("derive_for_all", &mut outer_attrs)?; - - let doc = extract_doc(&mut outer_attrs)?; - let typename = extract_typename(&mut outer_attrs)?; - - // Extract attributes that we will just forward/emit verbatim. Well, not - // completely verbatim: we have to change the type to outer attribute. - let mut forwarded_attrs = extract_attrs(&["derive"], &mut outer_attrs); - for a in &mut forwarded_attrs { - a.style = syn::AttrStyle::Outer; - } - assert_no_extra_attrs(&outer_attrs)?; - // Parse children - let children = input.call(>::parse_terminated)?; + // Parse top level object. + let root: Node = input.parse()?; + if root.name != "config" { + return Err(syn::Error::new( + root.name.span(), + "top level object must have the name 'config'", + )); + } - let root = Node { - doc, - attrs: forwarded_attrs, - name: Ident::new("config", Span::call_site()), - kind: NodeKind::Obj(Obj { - typename, - children: children.into_iter().collect(), - }), - }; + // Make sure we have at most one trailing comma + if input.peek(syn::Token![,]) { + let _: syn::Token![,] = input.parse().unwrap(); + } + + if !input.is_empty() { + return Err(syn::Error::new( + input.span(), + "unexpected additional tokens (only one root element allowed)", + )); + } Ok(Self { root, visibility, derive_for_all }) } diff --git a/src/example.rs b/src/example.rs index 849daef..a348658 100644 --- a/src/example.rs +++ b/src/example.rs @@ -12,31 +12,32 @@ use std::{net::IpAddr, path::PathBuf}; use crate as confique; crate::config! { - //! An example configuration. + // This is used here to make all items show up in the documentation. #![visibility = "pub"] - #![derive(Clone)] - #[derive(Clone, Copy)] - dns: { - /// The DNS server IP address. - #[example = "1.1.1.1"] - server: IpAddr, + /// An example configuration. + config: { + dns: { + /// The DNS server IP address. + #[example = "1.1.1.1"] + server: IpAddr, - /// Whether to use a local DNS resolution cache. - use_cache: bool = true, + /// Whether to use a local DNS resolution cache. + use_cache: bool = true, - /// How often to reattempt reaching the DNS server. - retry_attempts: u32 = 27, - }, + /// How often to reattempt reaching the DNS server. + retry_attempts: u32 = 27, + }, - #[typename = "Logger"] - log: { - /// Sets the log level. Possible values: "trace", "debug", "info", - /// "warn", "error" and "off". - level: log::LevelFilter = "info", + #[typename = "Logger"] + log: { + /// Sets the log level. Possible values: "trace", "debug", "info", + /// "warn", "error" and "off". + level: log::LevelFilter = "info", - /// If this is set, log messages are also written to this file. - #[example = "/var/log/test.log"] - file: Option, - }, + /// If this is set, log messages are also written to this file. + #[example = "/var/log/test.log"] + file: Option, + }, + } }