recipes/db/build.rs

182 lines
5.0 KiB
Rust

use std::fs;
use std::io::{BufWriter, Write};
use serde::Deserialize;
#[derive(Deserialize, Debug)]
pub struct Main {
ingredients: Option<Vec<Ingredient>>,
recipes: Option<Vec<Recipe>>,
}
#[derive(Deserialize, Debug)]
pub struct Ingredient {
key: String,
translates: IngredientTranslate,
}
#[derive(Deserialize, Debug)]
pub struct IngredientTranslate {
ru: String,
en: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Recipe {
key: String,
ingredients: Vec<RecipeIngredient>,
steps: u8,
translates: RecipeTranslates,
}
#[derive(Deserialize, Debug)]
pub struct RecipeIngredient {
key: String,
#[serde(flatten)]
measure: RecipeIngredientMeasure,
}
#[derive(Deserialize, Debug)]
pub enum RecipeIngredientMeasure {
#[serde(rename = "g")]
Gram(u32),
#[serde(rename = "kg")]
KiloGram(u32),
#[serde(rename = "ml")]
MilliLiter(u32),
#[serde(rename = "l")]
Liter(u32),
}
#[derive(Deserialize, Debug)]
pub struct RecipeTranslates {
ru: RecipeTranslate,
en: Option<RecipeTranslate>,
}
#[derive(Deserialize, Debug)]
pub struct RecipeTranslate {
name: String,
instructions: Vec<String>,
}
fn write_structs(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct Ingredient {{")?;
writeln!(file, " pub key: &'static str,")?;
writeln!(file, " translates: IngredientTranslate,")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct IngredientTranslate {{")?;
writeln!(file, " ru: &'static str,")?;
writeln!(file, " en: Option<&'static str>,")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct Recipe {{")?;
writeln!(file, " key: &'static str,")?;
writeln!(file, " ingredients: Vec<RecipeIngredient>,")?;
writeln!(file, " steps: u8,")?;
writeln!(file, " translates: RecipeTranslates,")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct RecipeIngredient {{")?;
writeln!(file, " key: &'static str,")?;
writeln!(file, " measure: RecipeIngredientMeasure,")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub enum RecipeIngredientMeasure {{")?;
writeln!(file, " Gram(u32),")?;
writeln!(file, " KiloGram(u32),")?;
writeln!(file, " MilliLiter(u32),")?;
writeln!(file, " Liter(u32),")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct RecipeTranslates {{")?;
writeln!(file, " ru: RecipeTranslate,")?;
writeln!(file, " en: Option<RecipeTranslate>,")?;
writeln!(file, "}}")?;
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct RecipeTranslate {{")?;
writeln!(file, " name: &'static str,")?;
writeln!(file, " instructions: Vec<&'static str>,")?;
writeln!(file, "}}")?;
Ok(())
}
fn write_ingredients(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
// fs::read_dir("data/ingredients")
let fruit = fs::read_to_string("data/ingredients/fruit.toml")?;
let cfg: Main = toml::from_str(&fruit).unwrap();
let mut ins: usize = 0;
writeln!(
file,
"pub const INGREDIENTS: [Ingredient; {}] = [",
cfg.ingredients
.as_ref()
.map(|i| i.len())
.unwrap_or_default()
)?;
ins += 1;
if let Some(ingredients) = cfg.ingredients {
for ingredient in ingredients {
writeln!(file, "{}Ingredient {{", indent(ins))?;
ins += 1;
writeln!(file, "{}key: {:?},", indent(ins), to_str(ingredient.key))?;
writeln!(file, "{}translates: IngredientTranslate {{", indent(ins))?;
ins += 1;
writeln!(
file,
"{}ru: {:?},",
indent(ins),
to_str(ingredient.translates.ru)
)?;
writeln!(
file,
"{}en: {:?},",
indent(ins),
ingredient.translates.en.map(to_str)
)?;
ins -= 1;
writeln!(file, "{}}}", indent(ins))?;
ins -= 1;
writeln!(file, "{}}},", indent(ins))?;
}
}
ins -= 1;
writeln!(file, "{}];", indent(ins))?;
Ok(())
}
fn gen_data_mod() -> Result<(), std::io::Error> {
let file = fs::File::create("src/data.rs")?;
let mut buf = BufWriter::new(file);
write_structs(&mut buf)?;
println!("cargo:rerun-if-changed=data");
write_ingredients(&mut buf)?;
Ok(())
}
fn indent(indent_size: usize) -> String {
std::iter::repeat(" ").take(indent_size * 4).collect()
}
fn to_str(string: String) -> &'static str {
Box::leak(string.into_boxed_str())
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
if let Err(e) = gen_data_mod() {
eprintln!("Error: {}", e);
}
}