mirror of
https://github.com/starship/starship.git
synced 2024-11-30 12:14:08 +01:00
9a1569444b
We can use `and_then()` to string `Option` values together so that we only need a single `?` assertion. This makes it generally possible to have e.g. `unwrap_or()` at the end.
77 lines
2.5 KiB
Rust
77 lines
2.5 KiB
Rust
extern crate proc_macro;
|
|
extern crate proc_macro2;
|
|
|
|
use proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use syn::{parse_macro_input, DeriveInput};
|
|
|
|
#[proc_macro_derive(ModuleConfig)]
|
|
pub fn derive_module_config(input: TokenStream) -> TokenStream {
|
|
let dinput = parse_macro_input!(input as DeriveInput);
|
|
impl_module_config(dinput)
|
|
}
|
|
|
|
fn impl_module_config(dinput: DeriveInput) -> proc_macro::TokenStream {
|
|
let struct_ident = &dinput.ident;
|
|
let (_impl_generics, ty_generics, where_clause) = dinput.generics.split_for_impl();
|
|
|
|
let mut from_config = quote! {};
|
|
let mut load_config = quote! {};
|
|
|
|
if let syn::Data::Struct(data) = dinput.data {
|
|
if let syn::Fields::Named(fields_named) = data.fields {
|
|
let mut load_tokens = quote! {};
|
|
let mut from_tokens = quote! {};
|
|
|
|
for field in fields_named.named.iter() {
|
|
let ident = field.ident.as_ref().unwrap();
|
|
let ty = &field.ty;
|
|
|
|
let new_load_tokens = quote! {
|
|
if let Some(config_str) = config.get(stringify!(#ident)) {
|
|
new_module_config.#ident = new_module_config.#ident.load_config(config_str);
|
|
}
|
|
};
|
|
let new_from_tokens = quote! {
|
|
#ident: config.get(stringify!(#ident)).and_then(<#ty>::from_config)?,
|
|
};
|
|
|
|
load_tokens = quote! {
|
|
#load_tokens
|
|
#new_load_tokens
|
|
};
|
|
from_tokens = quote! {
|
|
#from_tokens
|
|
#new_from_tokens
|
|
}
|
|
}
|
|
|
|
load_config = quote! {
|
|
fn load_config(&self, config: &'a toml::Value) -> Self {
|
|
let mut new_module_config = self.clone();
|
|
if let toml::Value::Table(config) = config {
|
|
#load_tokens
|
|
}
|
|
new_module_config
|
|
}
|
|
};
|
|
from_config = quote! {
|
|
fn from_config(config: &'a toml::Value) -> Option<Self> {
|
|
let config = config.as_table()?;
|
|
|
|
Some(#struct_ident {
|
|
#from_tokens
|
|
})
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
TokenStream::from(quote! {
|
|
impl<'a> ModuleConfig<'a> for #struct_ident #ty_generics #where_clause {
|
|
#from_config
|
|
#load_config
|
|
}
|
|
})
|
|
}
|