Skip to content

Make prettytable smarter #109

Open
Open
@thymbahutymba

Description

@thymbahutymba

I thought to implement something to make pretty table smarter adding a proc_macro and a macro. Below an initial version of code:

lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemStruct};

#[proc_macro_derive(TableElem)]
pub fn derive_table_elem(input: TokenStream) -> TokenStream {
    let parsed_input = parse_macro_input!(input as ItemStruct);

    let struct_name = &parsed_input.ident;
    let field = &parsed_input.fields;

    // Get struct field name
    let f_name_str: Vec<String> = field
        .iter()
        .map(|f| f.ident.clone().unwrap().to_string())
        .collect();

    let f_name: Vec<syn::Ident> = field.iter().map(|f| f.ident.clone().unwrap()).collect();

    TokenStream::from(quote! {
        pub trait TableElem {
            fn get_field_name(&self) -> Vec<&'static str>;
            fn get_field(self) -> Vec<String>;
        }

        impl TableElem for #struct_name {
            fn get_field_name(&self) -> Vec<&'static str> {
                vec![#(#f_name_str),*]
            }

            fn get_field(self) -> Vec<String> {
                vec![#(self.#f_name.into()),*]
            }
        }
    })
}

main.rs

use macros::TableElem;
use prettytable::{format, Cell, Row, Table};

#[derive(TableElem)]
struct NameStruct {
    name: String,
    surname: String,
}

fn construct_table<T: TableElem>(v: Vec<T>) -> Table {
    // Create the table
    let mut table = Table::new();

    table.set_titles(Row::new(
        v.first()
            .unwrap()
            .get_field_name()
            .iter()
            .map(|f| Cell::new(f))
            .collect(),
    ));
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);

    v.into_iter().for_each(|r| {
        table.add_row(Row::new(
            r.get_field().iter().map(|elem| Cell::new(elem)).collect(),
        ));
    });

    table
}

macro_rules! print_as_table {
    ($v: ident) => {
        construct_table($v).printstd();
    };
}

fn main() {
    let t: Vec<NameStruct> = vec![
        NameStruct {
            name: "name_1".to_string(),
            surname: "surname_1".to_string(),
        },
        NameStruct {
            name: "name_2".to_string(),
            surname: "surname_2".to_string(),
        },
    ];

    print_as_table!(t);
}

Of course the previous code can be improved but I prefer get a feedback before make a pull request.

Metadata

Metadata

Assignees

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions