Require single config root object

Otherwise global attributes and attributes for the root object have the
same syntax (`#![...]`). This way, it is way clearer.
This commit is contained in:
Lukas Kalbertodt
2021-04-30 17:51:06 +02:00
parent 5075b4df17
commit c798049443
3 changed files with 53 additions and 53 deletions

View File

@@ -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<PathBuf>,
},
/// If this is set, log messages are also written to this file.
#[example = "/var/log/test.log"]
file: Option<PathBuf>,
},
}
}
}

View File

@@ -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(<Punctuated<_, syn::Token![,]>>::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 })
}

View File

@@ -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<PathBuf>,
},
/// If this is set, log messages are also written to this file.
#[example = "/var/log/test.log"]
file: Option<PathBuf>,
},
}
}