alacritty_config_derive/
lib.rs

1#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]
2#![cfg_attr(clippy, deny(warnings))]
3
4use proc_macro::TokenStream;
5use proc_macro2::TokenStream as TokenStream2;
6use quote::quote;
7use syn::parse::{self, Parse, ParseStream};
8use syn::punctuated::Punctuated;
9use syn::{GenericParam, Ident, LitStr, Token, TypeParam};
10
11mod config_deserialize;
12mod serde_replace;
13
14/// Error message when attempting to flatten multiple fields.
15pub(crate) const MULTIPLE_FLATTEN_ERROR: &str =
16    "At most one instance of #[config(flatten)] is supported";
17
18#[proc_macro_derive(ConfigDeserialize, attributes(config))]
19pub fn derive_config_deserialize(input: TokenStream) -> TokenStream {
20    config_deserialize::derive(input)
21}
22
23#[proc_macro_derive(SerdeReplace)]
24pub fn derive_serde_replace(input: TokenStream) -> TokenStream {
25    serde_replace::derive(input)
26}
27
28/// Storage for all necessary generics information.
29#[derive(Default)]
30struct GenericsStreams {
31    unconstrained: TokenStream2,
32    constrained: TokenStream2,
33    phantoms: TokenStream2,
34}
35
36/// Create the necessary generics annotations.
37///
38/// This will create three different token streams, which might look like this:
39///  - unconstrained: `T`
40///  - constrained: `T: Default + Deserialize<'de>`
41///  - phantoms: `T: PhantomData<T>,`
42pub(crate) fn generics_streams<T>(params: &Punctuated<GenericParam, T>) -> GenericsStreams {
43    let mut generics = GenericsStreams::default();
44
45    for generic in params {
46        // NOTE: Lifetimes and const params are not supported.
47        if let GenericParam::Type(TypeParam { ident, .. }) = generic {
48            generics.unconstrained.extend(quote!( #ident , ));
49            generics.constrained.extend(quote! {
50                #ident : Default + serde::Deserialize<'de> + alacritty_config::SerdeReplace,
51            });
52            generics.phantoms.extend(quote! {
53                #ident : std::marker::PhantomData < #ident >,
54            });
55        }
56    }
57
58    generics
59}
60
61/// Field attribute.
62pub(crate) struct Attr {
63    ident: String,
64    param: Option<LitStr>,
65}
66
67impl Parse for Attr {
68    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
69        let ident = input.parse::<Ident>()?.to_string();
70        let param = input.parse::<Token![=]>().and_then(|_| input.parse()).ok();
71        Ok(Self { ident, param })
72    }
73}