memtable-macros 0.2.0

Macro library that provides ability to derive typed tables and generate tables compile-time.
use super::{utils, TableColumn, TableMode};
use quote::format_ident;
use syn::{parse_quote, Generics, Ident, ItemImpl, Path};
use voca_rs::case;

pub struct Args<'a> {
    pub root: &'a Path,
    pub mode: TableMode,
    pub table_name: &'a Ident,
    pub generics: &'a Generics,
    pub table_data_name: &'a Ident,
    pub columns: &'a [&'a TableColumn],
}

pub fn make(args: Args) -> ItemImpl {
    let Args {
        root,
        mode,
        table_name,
        generics,
        table_data_name,
        columns,
    } = args;

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    let variant = utils::make_variant_idents(columns);
    let ty = utils::make_variant_types(columns);
    let is_ty: Vec<Ident> = utils::make_column_names(columns, case::snake_case)
        .into_iter()
        .map(|name| format_ident!("is_{}", name))
        .collect();
    let idx = utils::make_column_indexes(columns);
    let inner_table_ty =
        utils::make_inner_table_type(root, mode, table_data_name, generics, columns.len());

    parse_quote! {
        #[automatically_derived]
        impl #impl_generics ::core::convert::TryFrom<#inner_table_ty>
            for #table_name #ty_generics #where_clause
        {
            type Error = &'static ::core::primitive::str;

            fn try_from(table: #inner_table_ty) -> ::core::result::Result<Self, Self::Error> {
                for row in 0..#root::Table::row_cnt(&table) {
                    #(
                        let cell = #root::Table::cell(&table, row, #idx);

                        if cell.is_none() {
                            return ::core::result::Result::Err(
                                ::core::concat!(
                                    "Cell in column ",
                                    ::core::stringify!(#idx),
                                    "/",
                                    ::core::stringify!(#variant),
                                    " is missing",
                                )
                            );
                        }

                        if !cell.unwrap().#is_ty() {
                            return ::core::result::Result::Err(
                                ::core::concat!(
                                    "Cell in column ",
                                    ::core::stringify!(#idx),
                                    "/",
                                    ::core::stringify!(#variant),
                                    " is not of type ",
                                    ::core::stringify!(#ty),
                                )
                            );
                        }
                    )*
                }

                ::core::result::Result::Ok(Self(table))
            }
        }
    }
}