recipes/db/build.rs

167 lines
4.1 KiB
Rust

use core::fmt;
use std::fs;
use std::io::{BufWriter, Write};
use serde::Deserialize;
fn main() {
println!("cargo:rerun-if-changed=data/*");
if let Err(e) = gen_data_mod() {
eprintln!("Error: {}", e);
}
}
fn gen_data_mod() -> Result<(), std::io::Error> {
let file = fs::File::create("src/data.rs")?;
let mut buf = BufWriter::new(file);
writeln!(buf, "use crate::types::*;\n")?;
println!("cargo:rerun-if-changed=data/ingredients/*.toml");
write_ingredients(&mut buf)?;
println!("cargo:rerun-if-changed=data/recipes/*.toml");
write_recipes(&mut buf)?;
Ok(())
}
#[derive(Deserialize, Debug)]
pub struct Main {
ingredients: Option<Vec<Ingredient>>,
recipes: Option<Vec<Recipe>>,
}
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
pub struct Ingredient {
key: String,
translates: IngredientTranslate,
}
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
pub struct IngredientTranslate {
rus: String,
eng: Option<String>,
}
#[derive(Deserialize)]
pub struct Recipe {
key: String,
ingredients: Vec<RecipeIngredient>,
steps: u8,
translates: RecipeTranslates,
}
impl fmt::Debug for Recipe {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Recipe")
.field("key", &self.key)
.field("steps", &self.steps)
.field("ingredients", &format_args!("vec!{:#?}", self.ingredients))
.field("translates", &self.translates)
.finish()
}
}
#[derive(Deserialize)]
pub struct RecipeIngredient {
key: String,
#[serde(flatten)]
measure: RecipeIngredientMeasure,
}
impl fmt::Debug for RecipeIngredient {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RecipeIngredient")
.field("key", &self.key)
.field("measure", &format_args!("Measure::{:?}", self.measure))
.finish()
}
}
#[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),
}
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
pub struct RecipeTranslates {
rus: RecipeTranslate,
eng: Option<RecipeTranslate>,
}
#[derive(Deserialize)]
pub struct RecipeTranslate {
name: String,
instructions: Vec<String>,
}
impl fmt::Debug for RecipeTranslate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RecipeTranslate")
.field("name", &self.name)
.field(
"instructions",
&format_args!("vec!{:#?}", self.instructions),
)
.finish()
}
}
fn write_ingredients(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
let ingredients = get_ingredient_configs()?;
writeln!(
file,
"pub const INGREDIENTS: [Ingredient; {}] = {:#?};\n",
ingredients.len(),
ingredients
)?;
Ok(())
}
fn get_ingredient_configs() -> Result<Vec<Ingredient>, std::io::Error> {
Ok(fs::read_dir("data/ingredients")?
.map(|res| res.and_then(|e| fs::read_to_string(e.path())))
.collect::<Result<Vec<_>, std::io::Error>>()?
.into_iter()
.map(|content| toml::from_str(&content).unwrap())
.filter_map(|cfg: Main| cfg.ingredients)
.flatten()
.collect::<Vec<Ingredient>>())
}
fn write_recipes(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
let recipes = get_recipe_configs()?;
writeln!(
file,
r#"lazy_static::lazy_static! {{
pub static ref RECIPES: [Recipe; {}] = {:#?};
}}"#,
recipes.len(),
recipes
)?;
Ok(())
}
fn get_recipe_configs() -> Result<Vec<Recipe>, std::io::Error> {
Ok(fs::read_dir("data/recipes")?
.map(|res| res.and_then(|e| fs::read_to_string(e.path())))
.collect::<Result<Vec<_>, std::io::Error>>()?
.into_iter()
.map(|content| toml::from_str(&content).unwrap())
.filter_map(|cfg: Main| cfg.recipes)
.flatten()
.collect::<Vec<Recipe>>())
}