envl 0.4.0

load .envl and .envlconf
Documentation
use std::{collections::HashMap, io::Error};

use envl_config::misc::variable::{Type, Value};
use proc_macro2::TokenStream;
use quote::quote;

use crate::{generator::rust::value::gen_value, VarData, VariableHashMap};

pub mod array;
pub mod gen_struct;
pub mod value;

pub fn parse_v_type(v_name: String, v_type: Type, structs: &mut Vec<String>) -> TokenStream {
    match v_type {
        Type::Array(boxed_element_type) => {
            let value = parse_v_type(v_name, *boxed_element_type, structs);
            quote! {
                Vec<#value>
            }
        }
        Type::Bool => quote! {bool},
        Type::Char => quote! {char},
        Type::Float => quote! {f64},
        Type::Int => quote! {i64},
        Type::Null => quote! {None},
        Type::String => quote! {String},
        Type::Option(t) => {
            let value = parse_v_type(v_name, *t, structs);
            quote! {
                Option<#value>
            }
        }
        Type::Struct(elements) => {
            let struct_name = format!("Struct{}", v_name);
            let struct_value = elements
                .iter()
                .map(|(n, v)| {
                    let name = match v {
                        Type::Struct(_) => {
                            format!("{}{}", n, struct_name)
                        }
                        _ => n.to_string(),
                    };
                    let v_type = parse_v_type(name.to_owned(), v.to_owned(), structs);
                    quote! {#name, #v_type}
                })
                .collect::<Vec<_>>();

            structs.push(
                quote! {
                    #[derive(Debug, Clone)]
                    struct #struct_name {
                        #(
                            pub #struct_value,
                        )*
                    }
                }
                .to_string(),
            );

            let result = struct_name.parse::<TokenStream>().unwrap();

            quote! {
                #result
            }
        }
        Type::Uint => quote! {u64},
    }
}

pub fn parse_var(name: String, var: VarData, structs: &mut Vec<String>) -> Result<String, Error> {
    match var.value {
        Value::Null => {
            match gen_value(
                name,
                var.v_type.to_owned(),
                var.default_value.to_owned(),
                structs,
            ) {
                Ok(r) => Ok(r.to_string()),
                Err(err) => Err(err),
            }
        }
        _ => match gen_value(name, var.v_type.to_owned(), var.value.to_owned(), structs) {
            Ok(r) => Ok(r.to_string()),
            Err(err) => Err(err),
        },
    }
}

pub fn generate_rust_file(data: VariableHashMap) -> Result<String, Error> {
    let mut structs = Vec::new();
    let mut struct_values = Vec::new();
    let mut types_hm = HashMap::new();
    let mut value_hm = HashMap::new();

    for (name, value) in data {
        let parsed_type = parse_v_type(name.to_owned(), value.to_owned().v_type, &mut structs);
        types_hm.insert(name.to_owned(), parsed_type);

        match parse_var(name.to_owned(), value.to_owned(), &mut struct_values) {
            Ok(v) => {
                value_hm.insert(name, v);
            }
            Err(err) => {
                return Err(err);
            }
        }
    }

    let env_type = types_hm
        .iter()
        .map(|(n, v)| {
            let name = n.parse::<proc_macro2::TokenStream>().unwrap();
            quote! { #name: #v }
        })
        .collect::<Vec<_>>();
    let env_value = value_hm
        .iter()
        .map(|(n, v)| {
            let name = n.parse::<proc_macro2::TokenStream>().unwrap();
            let value = v.parse::<proc_macro2::TokenStream>().unwrap();
            quote! { #name: #value }
        })
        .collect::<Vec<_>>();

    Ok(quote! {
        #(#structs)*

        #[derive(Debug, Clone)]
        #[rustfmt::skip]
        pub struct Env {
            #(
                pub #env_type,
            )*
        }

        #[rustfmt::skip]
        pub fn envl() -> Env {
            #(#struct_values)*

            Env {
                #(
                    #env_value,
                )*
            }
        }
    }
    .to_string())
}