db-rs-derive 0.3.7

macros for db-rs
Documentation
use db_rs::TableId;
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
use syn::*;

#[proc_macro_derive(Schema)]
pub fn schema(input: TokenStream) -> TokenStream {
    let DeriveInput { ident, data, .. } = parse_macro_input!(input);

    let tables = match data {
        Data::Struct(DataStruct { struct_token: _, fields, semi_token: _ }) => match fields {
            Fields::Named(FieldsNamed { brace_token: _, named: tables }) => tables,
            _ => panic!("db fields must all be named"),
        },
        _ => panic!("db schema must be a struct"),
    };

    let types = tables.iter().map(|table| &table.ty);

    let idents: &Vec<&Ident> = &tables
        .iter()
        .map(|table| table.ident.as_ref().unwrap())
        .collect();

    let last = &tables
        .iter()
        .map(|table| table.ident.as_ref().unwrap())
        .next_back()
        .unwrap_or_else(|| panic!("No tables found!"));

    let max_tables = TableId::MAX - 1 as TableId;
    if idents.len() > max_tables as usize {
        panic!(
            "Too many tables found, the maximum is: {max_tables}. Please file an issue with db-rs."
        );
    }

    let ids: Vec<u8> = (1..(idents.len() + 1) as u8).collect();

    let output = quote! {

        impl db_rs::Db for #ident {
            fn init(mut config: db_rs::Config) -> db_rs::DbResult<Self> {
                use db_rs::table::Table;

                let schema_name = stringify!(#ident);
                config.schema_name = Some(schema_name.to_string());
                let mut log = db_rs::Logger::init(config)?;
                let log_data = log.get_bytes()?;
                let log_entries = log.get_entries(&log_data)?;

                #( let mut #idents = <#types>::init(#ids, log.clone()); )*

                for entry in log_entries {
                    match entry.table_id {
                        #( #ids => #idents.handle_event(entry.bytes)?, )*
                        _ => todo!()
                    }
                }

                Ok(
                    Self {
                        #( #idents, )*
                    }
                )
            }

            fn compact_log(&mut self) -> db_rs::DbResult<()> {
                use db_rs::table::Table;

                let mut data = vec![];
                #( data.append(&mut self.#idents.compact_repr()?);)*
                self.get_logger().compact_log(data)?;
                Ok(())
            }

            fn get_logger(&self) -> &db_rs::Logger {
                &self.#last.logger
            }
        }
    };
    output.into()
}