mcversion-enum-rs 0.1.0

Exhaustive enum of Minecraft versions
use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use chrono::Utc;
use serde::Deserialize;

#[derive(Deserialize)]
struct VersionCollection {
    versions: Vec<Version>
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct Version {
    id: String,
    release_time: chrono::DateTime<Utc>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    let mut col = reqwest::get("https://launchermeta.mojang.com/mc/game/version_manifest.json")
        .await?
        .json::<VersionCollection>()
        .await?
        .versions;

    col.sort_by_key(|x| x.release_time);

    let out_dir = std::env::var("OUT_DIR")?;
    let dest_path = std::path::Path::new(&out_dir).join("gen.rs");
    let f = File::options().create(true).write(true).append(false).open(dest_path)?;    let mut bw = BufWriter::new(f);
    use std::io::Write;

    writeln!(&mut bw, "#[non_exhaustive]")?;
    writeln!(&mut bw, "#[allow(non_camel_case_types)]")?;
    writeln!(&mut bw, "#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]")?;
    writeln!(&mut bw, "pub enum MinecraftVersion {{")?;
    let make = |s: &String| s.replace(['.', '-', ' '], "_");
    let s = col
        .iter()
        .map(|x|
            format!("    _{v},\n", v = make(&x.id))
        )
        .collect::<Vec<_>>()
        .join("");
    write!(&mut bw, "{}", s)?;
    writeln!(&mut bw, "}}")?;

    writeln!(&mut bw)?;

    writeln!(&mut bw, "impl core::fmt::Display for MinecraftVersion {{")?;
    writeln!(&mut bw, "    #[allow(clippy::too_many_lines)]")?;
    writeln!(&mut bw, "    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {{")?;
    writeln!(&mut bw, "        let s = match self {{")?;
    let s = col
        .iter()
        .map(|x| format!("            Self::_{case} => \"{value}\", \n", case = make(&x.id), value = &x.id))
        .collect::<Vec<_>>()
        .join("");
    write!(&mut bw, "{}", s)?;
    writeln!(&mut bw, "        }};")?;
    writeln!(&mut bw, "    ")?;
    writeln!(&mut bw, "    f.write_str(s)")?;
    writeln!(&mut bw, "    }}")?;
    writeln!(&mut bw, "}}")?;

    writeln!(&mut bw)?;

    writeln!(&mut bw, "impl core::str::FromStr for MinecraftVersion {{")?;
    writeln!(&mut bw, "    type Err = ();")?;
    writeln!(&mut bw, "    #[allow(clippy::too_many_lines)]")?;
    writeln!(&mut bw, "    fn from_str(s: &str) -> Result<Self, Self::Err> {{")?;
    writeln!(&mut bw, "        match s {{")?;

    let s = col
        .iter()
        .map(|x| format!("            \"{ver}\" => Ok(Self::_{variant}),\n", ver = &x.id, variant = make(&x.id)))
        .collect::<Vec<_>>()
        .join("");

    write!(&mut bw, "{}", s)?;
    write!(&mut bw, "            _ => Err(()),")?;
    writeln!(&mut bw, "        }}")?;
    writeln!(&mut bw, "    }}")?;
    writeln!(&mut bw, "}}")?;

    Ok(())
}