csv_deserializer/
struct_gen.rs

1#![allow(clippy::uninlined_format_args)]
2
3use crate::{
4    COLUMN_TYPE_ENUM_NAME, ColName, CsvDataset, MAIN_STRUCT_NAME, SanitizedStr, csv_type::CsvAny, dataset_info::{ColumnInfo, Variant}
5};
6
7/// It generates a struct named `CsvDataFrame` which
8/// contains all `Vec<T>` where T is the generated enums
9/// for each columns
10pub fn gen_struct(dataset: &CsvDataset) -> String {
11    let mut final_str = format!("pub struct {MAIN_STRUCT_NAME}{{\n");
12
13    // final_str.push_str(&format!("\tpub columns: Vec<{COLUMN_TYPE_ENUM_NAME}>,\n"));
14    dataset.names.iter().for_each(|name| {
15        final_str.push_str(&format!(
16            "\tpub {}: {},\n",
17            name.sanitized.0.to_lowercase(),
18            COLUMN_TYPE_ENUM_NAME
19        ));
20    });
21    final_str.push('}');
22
23    let impl_str_open = format!(
24        "impl {MAIN_STRUCT_NAME}{{
25"
26    );
27    let new_method = gen_new_method(&dataset.names, &dataset.info);
28    let column_list_method = gen_column_list_method(&dataset.names);
29    let impl_str_close = '}';
30
31    final_str.push_str(&impl_str_open);
32    final_str.push_str(&new_method);
33    final_str.push_str(&column_list_method);
34    final_str.push(impl_str_close);
35
36    final_str
37}
38
39fn gen_column_list_method(col_names: &[ColName]) -> String {
40    let mut number_of_cols = 0;
41    let columns = col_names
42        .iter()
43        .map(|x| {
44            number_of_cols += 1;
45            format!("&self.{},", x.sanitized.0)
46        })
47        .collect::<String>();
48    format!(
49        "\
50    pub fn get_columns(&self)-> [&{COLUMN_TYPE_ENUM_NAME};{number_of_cols}] {{
51        [{columns}]
52    }}"
53    )
54}
55
56fn gen_new_method(col_names: &[ColName], cols_info: &[ColumnInfo]) -> String {
57    let vecs_of_enums = cols_info
58        .iter()
59        .map(|col_info| gen_vec_of_enums(&col_info.column_name, &col_info.unique_values) + "\n\n")
60        .collect::<String>();
61
62    let fields_list = col_names
63        .iter()
64        .map(|colname| format!("{},\n\t\t\t", colname.sanitized.0.to_lowercase()))
65        .collect::<String>();
66    format!(
67        "\
68    pub fn new(dataset: &csv_deserializer::CsvDataset) -> Self{{
69        {vecs_of_enums}
70
71        {MAIN_STRUCT_NAME}{{
72            {fields_list}
73        }}
74    }}
75"
76    )
77}
78
79fn gen_vec_of_enums(col_name: &ColName, unique_values: &[Variant]) -> String {
80    let ColName {
81        raw: _raw,
82        sanitized,
83    } = col_name;
84    let SanitizedStr(sanitized) = sanitized;
85    let sanitized_lower = sanitized.to_lowercase();
86    let mut float_case_already_written = false;
87    let mut int_case_already_written = false;
88    let mut str_case_already_written = false;
89    let match_arms = unique_values
90        .iter()
91        .filter_map(|v| match &v.csvany {
92            CsvAny::Str(_) if !str_case_already_written => {
93                str_case_already_written = true;
94                Some(format!(
95                    "csv_deserializer::csv_type::CsvAny::Str(s) => {sanitized}::from_str(s).unwrap(),\n"
96                ))
97            }
98            CsvAny::Int(_) if !int_case_already_written => {
99                int_case_already_written = true;
100                Some(format!(
101                    "csv_deserializer::csv_type::CsvAny::Int(i) => {sanitized}::Int(*i),\n"
102                ))
103            }
104            CsvAny::Float(_) if !float_case_already_written => {
105                float_case_already_written = true;
106                Some(format!(
107                    "csv_deserializer::csv_type::CsvAny::Float(f) => {sanitized}::Float(*f),\n"
108                ))
109            }
110            CsvAny::Null => Some(format!(
111                "csv_deserializer::csv_type::CsvAny::Null => {sanitized}::Null,\n"
112            )),
113            CsvAny::Empty => Some(format!(
114                "csv_deserializer::csv_type::CsvAny::Empty => {sanitized}::Null,\n"
115            )),
116            _ => None,
117        })
118        .collect::<String>();
119    format!(
120        "\
121let (index, _) = dataset
122            .names
123            .iter()
124            .enumerate()
125            .find(|(index, cl)| &cl.sanitized.0 == \"{sanitized}\")
126            .unwrap();
127let {sanitized_lower} = {COLUMN_TYPE_ENUM_NAME}::{sanitized}(dataset.values[index].iter().map(|val| match val{{
128    {match_arms}
129    _ => panic!(),
130}}).collect::<Vec<{sanitized}>>());
131    "
132    )
133}