diff --git a/Cargo.lock b/Cargo.lock index 93f7c0b..6b4d1d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,10 +6,17 @@ version = 3 name = "db" version = "0.1.0" dependencies = [ + "lazy_static", "serde", "toml", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "proc-macro2" version = "1.0.38" diff --git a/db/Cargo.toml b/db/Cargo.toml index 94560e9..d09f816 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -8,3 +8,6 @@ edition = "2021" [build-dependencies] serde = { version = "1.0.137", features = ["derive"] } toml = "0.5.9" + +[dependencies] +lazy_static = "1.4.0" diff --git a/db/build.rs b/db/build.rs index 7fc94bc..78364db 100644 --- a/db/build.rs +++ b/db/build.rs @@ -1,10 +1,11 @@ +use core::fmt; use std::fs; use std::io::{BufWriter, Write}; use serde::Deserialize; fn main() { - println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=data/*"); if let Err(e) = gen_data_mod() { eprintln!("Error: {}", e); } @@ -16,11 +17,14 @@ fn gen_data_mod() -> Result<(), std::io::Error> { write_structs(&mut buf)?; 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(()) } fn write_structs(file: &mut BufWriter) -> Result<(), std::io::Error> { - let structs = r#" + let structs = r#"#![allow(dead_code)] + #[derive(Debug)] pub struct Ingredient { pub key: &'static str, @@ -36,8 +40,8 @@ pub struct IngredientTranslate { #[derive(Debug)] pub struct Recipe { key: &'static str, - ingredients: Vec, steps: u8, + ingredients: Vec, translates: RecipeTranslates, } @@ -79,19 +83,21 @@ pub struct Main { recipes: Option>, } +#[allow(dead_code)] #[derive(Deserialize, Debug)] pub struct Ingredient { key: String, translates: IngredientTranslate, } +#[allow(dead_code)] #[derive(Deserialize, Debug)] pub struct IngredientTranslate { ru: String, en: Option, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize)] pub struct Recipe { key: String, ingredients: Vec, @@ -99,13 +105,36 @@ pub struct Recipe { translates: RecipeTranslates, } -#[derive(Deserialize, Debug)] +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!("RecipeIngredientMeasure::{:?}", self.measure), + ) + .finish() + } +} + #[derive(Deserialize, Debug)] pub enum RecipeIngredientMeasure { #[serde(rename = "g")] @@ -118,52 +147,44 @@ pub enum RecipeIngredientMeasure { Liter(u32), } +#[allow(dead_code)] #[derive(Deserialize, Debug)] pub struct RecipeTranslates { ru: RecipeTranslate, en: Option, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize)] pub struct RecipeTranslate { name: String, instructions: Vec, } +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) -> Result<(), std::io::Error> { let ingredients = get_ingredient_configs()?; writeln!( file, - "pub const INGREDIENTS: [Ingredient; {}] = [{}];", + "pub const INGREDIENTS: [Ingredient; {}] = {:#?};\n", ingredients.len(), ingredients - .into_iter() - .map(|i| to_ingredient_data_content(1, i)) - .collect::() )?; 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, std::io::Error> { Ok(fs::read_dir("data/ingredients")? .map(|res| res.and_then(|e| fs::read_to_string(e.path()))) @@ -175,10 +196,28 @@ fn get_ingredient_configs() -> Result, std::io::Error> { .collect::>()) } -fn indent(indent_size: usize) -> String { - std::iter::repeat(" ").take(indent_size * 4).collect() +fn write_recipes(file: &mut BufWriter) -> 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 to_str(string: String) -> &'static str { - Box::leak(string.into_boxed_str()) +fn get_recipe_configs() -> Result, std::io::Error> { + Ok(fs::read_dir("data/recipes")? + .map(|res| res.and_then(|e| fs::read_to_string(e.path()))) + .collect::, std::io::Error>>()? + .into_iter() + .map(|content| toml::from_str(&content).unwrap()) + .filter_map(|cfg: Main| cfg.recipes) + .flatten() + .collect::>()) } diff --git a/db/src/data.rs b/db/src/data.rs index 36d9c3f..8f65001 100644 --- a/db/src/data.rs +++ b/db/src/data.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #[derive(Debug)] pub struct Ingredient { @@ -14,8 +15,8 @@ pub struct IngredientTranslate { #[derive(Debug)] pub struct Recipe { key: &'static str, - ingredients: Vec, steps: u8, + ingredients: Vec, translates: RecipeTranslates, } @@ -50,87 +51,149 @@ pub const INGREDIENTS: [Ingredient; 11] = [ key: "water", translates: IngredientTranslate { ru: "вода", - en: Some("water"), + en: Some( + "water", + ), }, }, - Ingredient { key: "carrot", translates: IngredientTranslate { ru: "морковь", - en: Some("carrot"), + en: Some( + "carrot", + ), }, }, - Ingredient { key: "potato", translates: IngredientTranslate { ru: "картофель", - en: Some("potato"), + en: Some( + "potato", + ), }, }, - Ingredient { key: "wheat_flour", translates: IngredientTranslate { ru: "пшеничная мука", - en: Some("wheat flour"), + en: Some( + "wheat flour", + ), }, }, - Ingredient { key: "olive_oil", translates: IngredientTranslate { ru: "оливковое масло", - en: Some("olive oil"), + en: Some( + "olive oil", + ), }, }, - Ingredient { key: "dry_yeast", translates: IngredientTranslate { ru: "сухие дрожжи", - en: Some("dry yeast"), + en: Some( + "dry yeast", + ), }, }, - Ingredient { key: "apple", translates: IngredientTranslate { ru: "яблоко", - en: Some("apple"), + en: Some( + "apple", + ), }, }, - Ingredient { key: "banana", translates: IngredientTranslate { ru: "банан", - en: Some("banana"), + en: Some( + "banana", + ), }, }, - Ingredient { key: "orange", translates: IngredientTranslate { ru: "апельсин", - en: Some("orange"), + en: Some( + "orange", + ), }, }, - Ingredient { key: "salt", translates: IngredientTranslate { ru: "соль", - en: Some("salt"), + en: Some( + "salt", + ), }, }, - Ingredient { key: "sugar", translates: IngredientTranslate { ru: "сахар", - en: Some("sugar"), + en: Some( + "sugar", + ), }, }, ]; + +lazy_static::lazy_static! { +pub static ref RECIPES: [Recipe; 1] = [ + Recipe { + key: "thin_crispy_pizza_base", + steps: 7, + ingredients: vec![ + RecipeIngredient { + key: "salt", + measure: RecipeIngredientMeasure::Gram(5), + }, + RecipeIngredient { + key: "sugar", + measure: RecipeIngredientMeasure::Gram(4), + }, + RecipeIngredient { + key: "wheat_flour", + measure: RecipeIngredientMeasure::Gram(500), + }, + RecipeIngredient { + key: "dry_yeast", + measure: RecipeIngredientMeasure::Gram(7), + }, + RecipeIngredient { + key: "olive_oil", + measure: RecipeIngredientMeasure::MilliLiter(25), + }, + RecipeIngredient { + key: "water", + measure: RecipeIngredientMeasure::MilliLiter(250), + }, + ], + translates: RecipeTranslates { + ru: RecipeTranslate { + name: "Тонкая хрустящая основа для пиццы", + instructions: vec![ + "Растворить дрожжи в воде, подогретой до температуры тела.", + "Добавить соль, сахар, оливковое масло и хорошо перемешать до однородной консистенции.", + "Добавить муку и замесить тесто. Вымешивать не менее 15 минут.", + "Разделить тесто на 3 порции, каждую завернуть в пищевую плёнку и дать настояться около 30 минут.", + "Растянуть один кусок теста до тонкого состояния и аккуратно переложить на смазанный растительным маслом противень.", + "Смазать соусом, чтобы тесто не осталось жидким и чтобы начинка не скользила по нему, и поставить в предварительно разогретую до максимальной температуры (не меньше 250 градусов) на 5-10 минут. В результате тесто хорошо пропечется и станет хрустящим.", + "Теперь на основу можно выкладывать начинку на ваш вкус и запекать до момента, когда сыр растает.", + ], + }, + en: None, + }, + }, +]; +} diff --git a/db/src/main.rs b/db/src/main.rs index 279e23d..d809020 100644 --- a/db/src/main.rs +++ b/db/src/main.rs @@ -3,10 +3,10 @@ mod data; fn main() { println!("Hello, world!"); - dbg!(data::INGREDIENTS - .into_iter() - .filter(|i| i.key == "banana") - .collect::>()); + let banana = data::INGREDIENTS.into_iter().find(|i| i.key == "banana"); + dbg!(banana); + + dbg!(data::RECIPES.iter().collect::>()); // let cfg: config::Main = toml::from_str(include_str!("../data/ingredients/fruit.toml")).unwrap(); // let cfg: config::Main = toml::from_str(include_str!("../data/recipes/pizza.toml")).unwrap();