Add #![visibility = "..."] attribute to specify visibility

This commit is contained in:
Lukas Kalbertodt
2021-04-29 19:30:19 +02:00
parent bfab0e8798
commit 24dec3b037
4 changed files with 52 additions and 3 deletions

View File

@@ -1,8 +1,12 @@
//! Definition of the intermediate representation or AST.
use proc_macro2::TokenStream;
/// The parsed input to the `gen_config` macro.
pub(crate) struct Input {
pub(crate) root: Node,
pub(crate) visibility: Option<TokenStream>,
}
/// One node in the tree of the configuration format. Can either be a leaf node

View File

@@ -7,7 +7,7 @@ use crate::ast::{Expr, Input, Node};
pub(crate) fn gen(input: Input) -> TokenStream {
let visibility = quote! { pub(crate) };
let visibility = input.visibility.clone().unwrap_or(quote! { pub(crate) });
let toml = gen_toml(&input);
let root_mod = gen_root_mod(&input, &visibility);
let raw_mod = gen_raw_mod(&input, &visibility);

View File

@@ -14,8 +14,14 @@ impl Parse for Input {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
let mut outer_attrs = input.call(syn::Attribute::parse_inner)?;
let doc = extract_doc(&mut outer_attrs)?;
let children = input.call(<Punctuated<_, syn::Token![,]>>::parse_terminated)?;
// `#![visibility = "..."]`
let visibility = extract_single_name_value_attr("visibility", &mut outer_attrs)?
.map(|v| Ok::<_, syn::Error>(assert_string_lit(v)?.parse::<TokenStream>()?))
.transpose()?;
assert_no_extra_attrs(&outer_attrs)?;
let children = input.call(<Punctuated<_, syn::Token![,]>>::parse_terminated)?;
let root = Node::Internal {
doc,
@@ -23,7 +29,7 @@ impl Parse for Input {
children: children.into_iter().collect(),
};
Ok(Self { root })
Ok(Self { root, visibility })
}
}
@@ -141,3 +147,39 @@ fn extract_doc(attrs: &mut Vec<syn::Attribute>) -> Result<Vec<String>, Error> {
Ok(out)
}
fn extract_single_name_value_attr(
name: &str,
attrs: &mut Vec<syn::Attribute>,
) -> Result<Option<syn::Lit>, Error> {
let mut filtered = attrs.iter().filter(|attr| attr.path.is_ident(name));
let meta = match filtered.next() {
None => return Ok(None),
Some(attr) => attr.parse_meta()?,
};
let nv = match meta {
syn::Meta::NameValue(nv) => nv,
other => {
let msg = format!(r#"expected `name = "value"` attribute syntax for `{}`"#, name);
return Err(Error::new(other.span(), msg));
}
};
if let Some(dupe) = filtered.next() {
let msg = format!("duplicate `{}` attribute", name);
return Err(Error::new(dupe.span(), msg));
}
// Remove the attribute from the vector
attrs.retain(|attr| !attr.path.is_ident(name));
Ok(Some(nv.lit))
}
fn assert_string_lit(lit: syn::Lit) -> Result<String, Error> {
match lit {
syn::Lit::Str(s) => Ok(s.value()),
_ => Err(Error::new(lit.span(), "expected string literal")),
}
}

View File

@@ -12,6 +12,9 @@ use std::{net::IpAddr, path::PathBuf};
use crate as confique;
crate::config! {
//! An example configuration.
#![visibility = "pub"]
dns: {
/// The DNS server IP address.
#[example = "1.1.1.1"]