memtable-macros 0.2.0

Macro library that provides ability to derive typed tables and generate tables compile-time.
use darling::FromDeriveInput;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Path};

mod codegen;
mod parse;

use parse::{StructTable, TableColumn, TableMode};

pub fn do_derive_table(root: Path, input: DeriveInput) -> darling::Result<TokenStream> {
    match &input.data {
        Data::Struct(_) => Ok(derive_table_from_struct(
            root,
            StructTable::from_derive_input(&input)?,
        )),
        Data::Enum(_) => Err(darling::Error::custom("Enums are not supported").with_span(&input)),
        Data::Union(_) => Err(darling::Error::custom("Unions are not supported").with_span(&input)),
    }
}

fn derive_table_from_struct(root: Path, table: StructTable) -> TokenStream {
    let vis = &table.vis;
    let (impl_generics, _, where_clause) = table.generics.split_for_impl();

    let table_name = table.to_table_name();
    let table_data_name = table.to_table_data_name();
    let generics = &table.generics;
    let columns = table.columns();
    let mode = table.mode;
    let style = table.as_style();

    let codegen::data::Return {
        definition: data_definition,
        core_impl: data_core_impl,
        default_impl: data_default_impl,
    } = codegen::data::make(codegen::data::Args {
        vis,
        style,
        mode,
        table_data_name: &table_data_name,
        generics,
        derive: table.data_attr.as_ref().and_then(|x| x.derive.as_ref()),
        columns: &columns,
    });

    let common_traits = codegen::traits::make_common(codegen::traits::CommonArgs {
        root: &root,
        mode,
        table_name: &table_name,
        generics,
        table_data_name: &table_data_name,
        columns: &columns,
    });

    let table_trait = codegen::traits::table::make(codegen::traits::table::Args {
        root: &root,
        mode,
        table_name: &table_name,
        generics,
        table_data_name: &table_data_name,
        columns: &columns,
    });

    let (struct_to_parts, parts_to_struct) = if table.skip_parts.is_none() {
        let (x, y) = codegen::parts::make(codegen::parts::Args {
            origin_struct_name: &table.ident,
            generics,
            columns: &columns,
            style,
        });
        (Some(x), Some(y))
    } else {
        (None, None)
    };

    let table_impl = codegen::make_table_impl(codegen::TableImplArgs {
        root: &root,
        mode,
        style,
        origin_struct_name: &table.ident,
        table_name: &table_name,
        generics: &table.generics,
        table_data_name: &table_data_name,
        columns: &columns,
    });

    let inner_table_ty = codegen::utils::make_inner_table_type(
        &root,
        mode,
        &table_data_name,
        &table.generics,
        columns.len(),
    );

    let derive_attr = table
        .derive
        .filter(|list| !list.is_empty())
        .map(|list| quote!(#[derive(#(#list),*)]));

    quote! {
        #[automatically_derived]
        #derive_attr
        #vis struct #table_name #impl_generics(#inner_table_ty) #where_clause;

        #data_definition
        #data_core_impl
        #data_default_impl
        #common_traits
        #struct_to_parts
        #parts_to_struct
        #table_trait
        #table_impl
    }
}