amethystate-macros 0.9.1

Type-safe reactive persistence for Rust GUI apps
Documentation
mod generate;

use amethystate_macros_core::{MacroArgs, StoreFieldEntry};
use darling::{FromField, FromMeta, ast::NestedMeta};
use generate::generate_code;
use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::Span;
use quote::quote;
use syn::__private::TokenStream2;
use syn::{Data, DataStruct, DeriveInput, Fields, parse_macro_input};

pub fn amethystate_impl(
    args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let attr_args = match NestedMeta::parse_meta_list(args.into()) {
        Ok(v) => v,
        Err(e) => return darling::Error::from(e).write_errors().into(),
    };

    let mut macro_args = match MacroArgs::from_list(&attr_args) {
        Ok(v) => v,
        Err(e) => return e.write_errors().into(),
    };

    if macro_args.as_root {
        macro_args.prefix = Some(".".to_string());
    }

    let input = parse_macro_input!(input as DeriveInput);
    let struct_name = &input.ident;
    let struct_vis = &input.vis;
    let attrs = &input.attrs;
    let amethystate = amethystate_crate_path();

    let named_fields = match &input.data {
        Data::Struct(DataStruct {
            fields: Fields::Named(f),
            ..
        }) => &f.named,
        _ => {
            return darling::Error::custom(
                "amethystate can only be used on structs with named fields",
            )
            .with_span(struct_name)
            .write_errors()
            .into();
        }
    };

    let mut entries = Vec::new();
    for field in named_fields {
        let entry = match StoreFieldEntry::from_field(field) {
            Ok(v) => v,
            Err(e) => return e.write_errors().into(),
        };

        entries.push(entry);
    }

    let expanded = generate_code(
        amethystate,
        struct_vis,
        struct_name,
        attrs,
        macro_args.prefix.clone(),
        &entries,
        macro_args,
    );

    proc_macro::TokenStream::from(expanded)
}

pub fn amethystate_crate_path() -> TokenStream2 {
    match crate_name("amethystate") {
        Ok(FoundCrate::Itself) => quote!(crate),
        Ok(FoundCrate::Name(name)) => {
            let ident = syn::Ident::new(&name, Span::call_site());
            quote!(::#ident)
        }
        _ => quote!(::amethystate),
    }
}