mirror of
https://github.com/OMGeeky/confique.git
synced 2025-12-26 16:07:44 +01:00
Add #[config(partial_attr(...))] to add attributes for partial type
CC #17
This commit is contained in:
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
- Add `#[config(partial_attr(...))]` struct attribute to specify attributes for
|
||||
the partial type.
|
||||
|
||||
## [0.2.4] - 2023-07-02
|
||||
- Fixed enum deserialization from env values
|
||||
|
||||
@@ -15,6 +15,7 @@ struct Conf {
|
||||
|
||||
/// Configuring the HTTP server of our app.
|
||||
#[derive(Debug, Config)]
|
||||
#[config(partial_attr(derive(Clone)))]
|
||||
struct Http {
|
||||
/// The port the server will listen on.
|
||||
#[config(env = "PORT")]
|
||||
|
||||
@@ -246,6 +246,8 @@ fn gen_partial_mod(input: &ir::Input) -> TokenStream {
|
||||
input.name,
|
||||
);
|
||||
|
||||
let partial_attrs = &input.partial_attrs;
|
||||
|
||||
quote! {
|
||||
#[doc = #module_doc]
|
||||
#visibility mod #mod_name {
|
||||
@@ -253,6 +255,7 @@ fn gen_partial_mod(input: &ir::Input) -> TokenStream {
|
||||
use super::*;
|
||||
|
||||
#[derive(confique::serde::Deserialize)]
|
||||
#( #[ #partial_attrs ])*
|
||||
#struct_visibility struct #struct_name {
|
||||
#( #struct_fields, )*
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
//! Definition of the intermediate representation.
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
|
||||
/// The parsed input to the `gen_config` macro.
|
||||
pub(crate) struct Input {
|
||||
pub(crate) doc: Vec<String>,
|
||||
pub(crate) visibility: syn::Visibility,
|
||||
pub(crate) partial_attrs: Vec<TokenStream>,
|
||||
pub(crate) name: syn::Ident,
|
||||
pub(crate) fields: Vec<Field>,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use proc_macro2::{TokenStream, Group, Delimiter, Ident};
|
||||
use syn::{Error, Token, parse::{Parse, ParseStream}, spanned::Spanned, punctuated::Punctuated};
|
||||
|
||||
use crate::{
|
||||
@@ -17,6 +18,7 @@ impl Input {
|
||||
};
|
||||
|
||||
let doc = extract_doc(&mut input.attrs);
|
||||
let partial_attrs = extract_struct_attrs(input.attrs)?;
|
||||
let fields = fields.named.into_iter()
|
||||
.map(Field::from_ast)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
@@ -25,12 +27,54 @@ impl Input {
|
||||
Ok(Self {
|
||||
doc,
|
||||
visibility: input.vis,
|
||||
partial_attrs,
|
||||
name: input.ident,
|
||||
fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_struct_attrs(attrs: Vec<syn::Attribute>) -> Result<Vec<TokenStream>, Error> {
|
||||
#[derive(Debug)]
|
||||
enum StructAttr {
|
||||
InternalAttr(TokenStream),
|
||||
}
|
||||
|
||||
impl Parse for StructAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let content;
|
||||
syn::parenthesized!(content in input);
|
||||
assert_empty_or_comma(input)?;
|
||||
|
||||
let name: Ident = content.parse()?;
|
||||
match &*name.to_string() {
|
||||
"partial_attr" => {
|
||||
let g: Group = content.parse()?;
|
||||
if g.delimiter() != Delimiter::Parenthesis {
|
||||
return Err(Error::new_spanned(g,
|
||||
"expected `(...)` but found different delimiter"));
|
||||
}
|
||||
assert_empty_or_comma(&content)?;
|
||||
Ok(Self::InternalAttr(g.stream()))
|
||||
}
|
||||
_ => Err(Error::new_spanned(name, "unknown attribute")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut partial_attrs = Vec::new();
|
||||
for attr in attrs {
|
||||
if !attr.path.is_ident("config") {
|
||||
continue;
|
||||
}
|
||||
match syn::parse2::<StructAttr>(attr.tokens)? {
|
||||
StructAttr::InternalAttr(tokens) => partial_attrs.push(tokens),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(partial_attrs)
|
||||
}
|
||||
|
||||
impl Field {
|
||||
fn from_ast(mut field: syn::Field) -> Result<Self, Error> {
|
||||
let doc = extract_doc(&mut field.attrs);
|
||||
|
||||
@@ -326,6 +326,13 @@ pub use crate::{
|
||||
/// the field.. Can only be present if the `env` attribute is present. Also
|
||||
/// see [`env::parse`].
|
||||
///
|
||||
/// There are also the following attributes on the struct itself:
|
||||
///
|
||||
/// - **`#[config(partial_attr(...))]`: specify attributes that should be
|
||||
/// attached to the partial struct definition. For example,
|
||||
/// `#[config(partial_attr(derive(Clone)))]` can be used to make the partial
|
||||
/// type implement `Clone`.
|
||||
///
|
||||
/// [serde-deser]: https://serde.rs/field-attrs.html#deserialize_with
|
||||
///
|
||||
/// ## Special types for leaf fields
|
||||
|
||||
Reference in New Issue
Block a user