libikarus 0.1.2

The core functionality of Ikarus wrapped neatly in a rust library
Documentation
use std::io::Write;
use std::path::Path;
use std::{fs::File, process::Command};

use indoc::{formatdoc, writedoc};

pub fn mod_commented(s: impl AsRef<str>) -> String {
    s.as_ref()
        .lines()
        .map(|l| format!("///! {l}"))
        .collect::<Vec<String>>()
        .join("\n")
}

pub fn commented(s: impl AsRef<str>) -> String {
    s.as_ref()
        .lines()
        .map(|l| format!("// {l}"))
        .collect::<Vec<String>>()
        .join("\n")
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // rerun if we update the version of libikarus
    println!("cargo:rerun-if-changed=Cargo.toml");

    let types = ikarusdef::get_types();

    let out_dir_env = std::env::var_os("OUT_DIR").expect("OUT_DIR not defined");
    let out_dir = Path::new(&out_dir_env);

    let mut files = vec![];

    for r#type in &types {
        let filename = out_dir.join(format!("{}.rs", r#type.name));

        files.push(filename.clone());

        let mut file = File::create(filename)?;

        let type_name = r#type.name;
        let type_description = mod_commented(r#type.description);
        let type_functions = r#type
            .functions
            .iter()
            .map(|func| {
                let func_name = &func.name;
                let func_description = commented(func.description);
                let func_log_level = &func.log_level;
                let func_db_access = &func.db_access;
                let versions = func
                    .versions
                    .iter()
                    .enumerate()
                    .map(|(i, version)| {
                        let version_flags_discrims = version
                            .flags
                            .iter()
                            .map(|f| format!("{}\n{}", commented(f.description), f.name))
                            .collect::<Vec<String>>()
                            .join(",\n");

                        let version_flags = formatdoc!(
                            r#"
                                pub enum Flags {{
                                    {version_flags_discrims}
                                }}
                            "#
                        );

                        let version_return = if let Some(ret) = &version.r#return {
                            formatdoc!(
                                r#"
                                    pub struct ReturnType {{
                                        {}
                                        pub {} : {},
                                        // Indicates the result of the operation
                                        pub return_status: StatusCode,
                                    }}
                                "#,
                                commented(ret.description),
                                ret.name,
                                ret.r#type
                            )
                        } else {
                            formatdoc!(
                                r#"
                                    pub struct ReturnType {{
                                        pub return_status: StatusCode,
                                    }}
                                "#
                            )
                        };

                        let version_func_description =
                            version.description.unwrap_or(&func_description);
                        let version_log_level = version.log_level.unwrap_or(*func_log_level);
                        let version_db_access = version.db_access.unwrap_or(*func_db_access);

                        let version_func_params = version
                            .parameters
                            .iter()
                            .map(|p| {
                                format!("{}\n{}: {}", commented(p.description), p.name, p.r#type)
                            })
                            .collect::<Vec<String>>()
                            .join(", ");

                        let version_func = formatdoc!(
                            r#"
                            {version_func_description}
                            pub fn call({version_func_params}) -> Result<ReturnType, Error> {{
                                Err(Error::NotImplemented)
                            }}
                            "#
                        );

                        formatdoc!(
                            r#"
                                pub mod version{} {{
                                    use crate::types::*;

                                    {version_return}
                                    {version_flags}
                                    {version_func}
                                }}
                            "#,
                            i
                        )
                    })
                    .collect::<Vec<String>>()
                    .join("\n\n");

                formatdoc!(
                    r#"
                        pub mod {func_name} {{
                            {versions}
                        }}
                    "#
                )
            })
            .collect::<Vec<String>>()
            .join("\n\n");

        writedoc!(
            file,
            r#"
                {type_description}

                pub mod {type_name} {{
                    {type_functions}
                }}
            "#
        )?;

        file.sync_data()?;
    }

    Command::new("rustfmt")
        .args(files)
        .spawn()?
        .wait_with_output()?;

    Ok(())
}