worktable_macros 0.9.0

Proc-macro companion crate for worktable: the worktable! macro and its derives. Formerly published as worktable_codegen.
Documentation
use proc_macro2::{Literal, TokenStream};
use quote::quote;

use crate::common::name_generator::{WorktableNameGenerator, is_unsized_vec};
use crate::generators::in_memory::InMemoryGenerator;

mod impls;
mod index_fns;
mod select_executor;

impl InMemoryGenerator {
    pub fn gen_table_def(&mut self) -> syn::Result<TokenStream> {
        let page_size_consts = self.gen_page_size_consts();
        let type_ = self.gen_table_type();
        let default = self.gen_table_default();
        let impl_ = self.gen_table_impl();
        let index_fns = self.gen_table_index_fns()?;
        let select_query_executor_impl = self.gen_table_select_query_executor_impl();
        let column_range_type = self.gen_table_column_range_type();

        Ok(quote! {
            #page_size_consts
            #type_
            #default
            #impl_
            #index_fns
            #select_query_executor_impl
            #column_range_type
        })
    }

    fn gen_table_default(&self) -> TokenStream {
        let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
        let ident = name_generator.get_work_table_ident();
        let table_name = name_generator.get_work_table_literal_name();

        quote! {
             impl Default for #ident {
                fn default() -> Self {
                    let mut inner = WorkTable::default();
                    inner.table_name = #table_name;
                    Self(inner)
                }
            }
        }
    }

    fn gen_table_type(&self) -> TokenStream {
        let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
        let ident = name_generator.get_work_table_ident();
        let row_type = name_generator.get_row_type_ident();
        let primary_key_type = name_generator.get_primary_key_type_ident();
        let index_type = name_generator.get_index_type_ident();
        let inner_const_name = name_generator.get_page_inner_size_const_ident();
        let avt_type_ident = name_generator.get_available_type_ident();
        let avt_index_ident = name_generator.get_available_indexes_ident();
        let lock_ident = name_generator.get_lock_type_ident();

        let pk_types = &self
            .columns
            .primary_keys
            .iter()
            .map(|i| {
                self.columns
                    .columns_map
                    .get(i)
                    .expect("should exist as got from definition")
                    .to_string()
            })
            .collect::<Vec<_>>();
        let pk_types_unsized = is_unsized_vec(pk_types);

        let derive = quote! {
             #[derive(Debug)]
        };

        let node_type = if pk_types_unsized {
            quote! {
                UnsizedNode<IndexPair<#primary_key_type, OffsetEqLink<#inner_const_name>>>
            }
        } else {
            quote! {
                Vec<IndexPair<#primary_key_type, OffsetEqLink<#inner_const_name>>>
            }
        };

        if self.config.as_ref().and_then(|c| c.page_size).is_some() {
            quote! {
                #derive
                pub struct #ident(
                    WorkTable<
                        #row_type,
                        #primary_key_type,
                        #avt_type_ident,
                        #avt_index_ident,
                        #index_type,
                        #lock_ident,
                        <#primary_key_type as TablePrimaryKey>::Generator,
                        #inner_const_name,
                        #node_type
                    >
                );
            }
        } else {
            quote! {
                #derive
                pub struct #ident(
                    WorkTable<
                        #row_type,
                        #primary_key_type,
                        #avt_type_ident,
                        #avt_index_ident,
                        #index_type,
                        #lock_ident,
                        <#primary_key_type as TablePrimaryKey>::Generator,
                        { INNER_PAGE_SIZE },
                        #node_type
                    >
                );
            }
        }
    }

    fn gen_page_size_consts(&self) -> TokenStream {
        let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
        let page_const_name = name_generator.get_page_size_const_ident();
        let inner_const_name = name_generator.get_page_inner_size_const_ident();

        if let Some(page_size) = &self.config.as_ref().and_then(|c| c.page_size) {
            let page_size = Literal::usize_unsuffixed(*page_size as usize);
            quote! {
                const #page_const_name: usize = #page_size;
                const #inner_const_name: usize = #page_size - GENERAL_HEADER_SIZE;
            }
        } else {
            quote! {
                const #page_const_name: usize = PAGE_SIZE;
                const #inner_const_name: usize = #page_const_name - GENERAL_HEADER_SIZE;
            }
        }
    }
}