185 lines
4.0 KiB
Rust
185 lines
4.0 KiB
Rust
use std::fs;
|
|
use std::io::{BufWriter, Write};
|
|
|
|
use serde::Deserialize;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
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);
|
|
write_structs(&mut buf)?;
|
|
println!("cargo:rerun-if-changed=data/ingredients/*.toml");
|
|
write_ingredients(&mut buf)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn write_structs(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
|
|
let structs = r#"
|
|
#[derive(Debug)]
|
|
pub struct Ingredient {
|
|
pub key: &'static str,
|
|
pub translates: IngredientTranslate,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct IngredientTranslate {
|
|
pub ru: &'static str,
|
|
pub en: Option<&'static str>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Recipe {
|
|
key: &'static str,
|
|
ingredients: Vec<RecipeIngredient>,
|
|
steps: u8,
|
|
translates: RecipeTranslates,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RecipeIngredient {
|
|
key: &'static str,
|
|
measure: RecipeIngredientMeasure,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum RecipeIngredientMeasure {
|
|
Gram(u32),
|
|
KiloGram(u32),
|
|
MilliLiter(u32),
|
|
Liter(u32),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RecipeTranslates {
|
|
ru: RecipeTranslate,
|
|
en: Option<RecipeTranslate>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RecipeTranslate {
|
|
name: &'static str,
|
|
instructions: Vec<&'static str>,
|
|
}
|
|
"#;
|
|
|
|
writeln!(file, "{}", structs)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[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_ingredients(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
|
|
let ingredients = get_ingredient_configs()?;
|
|
|
|
writeln!(
|
|
file,
|
|
"pub const INGREDIENTS: [Ingredient; {}] = [{}];",
|
|
ingredients.len(),
|
|
ingredients
|
|
.into_iter()
|
|
.map(|i| to_ingredient_data_content(1, i))
|
|
.collect::<String>()
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn to_ingredient_data_content(indent_size: usize, ingredient: Ingredient) -> String {
|
|
format!(
|
|
r#"
|
|
{i}Ingredient {{
|
|
{i} key: {key:?},
|
|
{i} translates: IngredientTranslate {{
|
|
{i} ru: {tr_ru:?},
|
|
{i} en: {tr_en:?},
|
|
{i} }},
|
|
{i}}},
|
|
"#,
|
|
i = indent(indent_size),
|
|
key = to_str(ingredient.key),
|
|
tr_ru = to_str(ingredient.translates.ru),
|
|
tr_en = ingredient.translates.en.map(to_str),
|
|
)
|
|
}
|
|
|
|
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 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())
|
|
}
|