Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make prettytable smarter #109

Open
thymbahutymba opened this issue Jul 30, 2019 · 0 comments
Open

Make prettytable smarter #109

thymbahutymba opened this issue Jul 30, 2019 · 0 comments
Assignees
Milestone

Comments

@thymbahutymba
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants