db: use debug instead of rewrite structs

This commit is contained in:
Dmitriy Pleshevskiy 2022-05-08 23:53:40 +03:00
parent 4d13485253
commit 24e5f28e66
5 changed files with 170 additions and 58 deletions

7
Cargo.lock generated
View File

@ -6,10 +6,17 @@ version = 3
name = "db" name = "db"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"lazy_static",
"serde", "serde",
"toml", "toml",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.38" version = "1.0.38"

View File

@ -8,3 +8,6 @@ edition = "2021"
[build-dependencies] [build-dependencies]
serde = { version = "1.0.137", features = ["derive"] } serde = { version = "1.0.137", features = ["derive"] }
toml = "0.5.9" toml = "0.5.9"
[dependencies]
lazy_static = "1.4.0"

View File

@ -1,10 +1,11 @@
use core::fmt;
use std::fs; use std::fs;
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write};
use serde::Deserialize; use serde::Deserialize;
fn main() { fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=data/*");
if let Err(e) = gen_data_mod() { if let Err(e) = gen_data_mod() {
eprintln!("Error: {}", e); eprintln!("Error: {}", e);
} }
@ -16,11 +17,14 @@ fn gen_data_mod() -> Result<(), std::io::Error> {
write_structs(&mut buf)?; write_structs(&mut buf)?;
println!("cargo:rerun-if-changed=data/ingredients/*.toml"); println!("cargo:rerun-if-changed=data/ingredients/*.toml");
write_ingredients(&mut buf)?; write_ingredients(&mut buf)?;
println!("cargo:rerun-if-changed=data/recipes/*.toml");
write_recipes(&mut buf)?;
Ok(()) Ok(())
} }
fn write_structs(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> { fn write_structs(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
let structs = r#" let structs = r#"#![allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct Ingredient { pub struct Ingredient {
pub key: &'static str, pub key: &'static str,
@ -36,8 +40,8 @@ pub struct IngredientTranslate {
#[derive(Debug)] #[derive(Debug)]
pub struct Recipe { pub struct Recipe {
key: &'static str, key: &'static str,
ingredients: Vec<RecipeIngredient>,
steps: u8, steps: u8,
ingredients: Vec<RecipeIngredient>,
translates: RecipeTranslates, translates: RecipeTranslates,
} }
@ -79,19 +83,21 @@ pub struct Main {
recipes: Option<Vec<Recipe>>, recipes: Option<Vec<Recipe>>,
} }
#[allow(dead_code)]
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct Ingredient { pub struct Ingredient {
key: String, key: String,
translates: IngredientTranslate, translates: IngredientTranslate,
} }
#[allow(dead_code)]
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct IngredientTranslate { pub struct IngredientTranslate {
ru: String, ru: String,
en: Option<String>, en: Option<String>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize)]
pub struct Recipe { pub struct Recipe {
key: String, key: String,
ingredients: Vec<RecipeIngredient>, ingredients: Vec<RecipeIngredient>,
@ -99,13 +105,36 @@ pub struct Recipe {
translates: RecipeTranslates, 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 { pub struct RecipeIngredient {
key: String, key: String,
#[serde(flatten)] #[serde(flatten)]
measure: RecipeIngredientMeasure, 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)] #[derive(Deserialize, Debug)]
pub enum RecipeIngredientMeasure { pub enum RecipeIngredientMeasure {
#[serde(rename = "g")] #[serde(rename = "g")]
@ -118,52 +147,44 @@ pub enum RecipeIngredientMeasure {
Liter(u32), Liter(u32),
} }
#[allow(dead_code)]
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct RecipeTranslates { pub struct RecipeTranslates {
ru: RecipeTranslate, ru: RecipeTranslate,
en: Option<RecipeTranslate>, en: Option<RecipeTranslate>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize)]
pub struct RecipeTranslate { pub struct RecipeTranslate {
name: String, name: String,
instructions: Vec<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> { fn write_ingredients(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
let ingredients = get_ingredient_configs()?; let ingredients = get_ingredient_configs()?;
writeln!( writeln!(
file, file,
"pub const INGREDIENTS: [Ingredient; {}] = [{}];", "pub const INGREDIENTS: [Ingredient; {}] = {:#?};\n",
ingredients.len(), ingredients.len(),
ingredients ingredients
.into_iter()
.map(|i| to_ingredient_data_content(1, i))
.collect::<String>()
)?; )?;
Ok(()) 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> { fn get_ingredient_configs() -> Result<Vec<Ingredient>, std::io::Error> {
Ok(fs::read_dir("data/ingredients")? Ok(fs::read_dir("data/ingredients")?
.map(|res| res.and_then(|e| fs::read_to_string(e.path()))) .map(|res| res.and_then(|e| fs::read_to_string(e.path())))
@ -175,10 +196,28 @@ fn get_ingredient_configs() -> Result<Vec<Ingredient>, std::io::Error> {
.collect::<Vec<Ingredient>>()) .collect::<Vec<Ingredient>>())
} }
fn indent(indent_size: usize) -> String { fn write_recipes(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
std::iter::repeat(" ").take(indent_size * 4).collect() 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 { fn get_recipe_configs() -> Result<Vec<Recipe>, std::io::Error> {
Box::leak(string.into_boxed_str()) 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>>())
} }

View File

@ -1,3 +1,4 @@
#![allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct Ingredient { pub struct Ingredient {
@ -14,8 +15,8 @@ pub struct IngredientTranslate {
#[derive(Debug)] #[derive(Debug)]
pub struct Recipe { pub struct Recipe {
key: &'static str, key: &'static str,
ingredients: Vec<RecipeIngredient>,
steps: u8, steps: u8,
ingredients: Vec<RecipeIngredient>,
translates: RecipeTranslates, translates: RecipeTranslates,
} }
@ -50,87 +51,149 @@ pub const INGREDIENTS: [Ingredient; 11] = [
key: "water", key: "water",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "вода", ru: "вода",
en: Some("water"), en: Some(
"water",
),
}, },
}, },
Ingredient { Ingredient {
key: "carrot", key: "carrot",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "морковь", ru: "морковь",
en: Some("carrot"), en: Some(
"carrot",
),
}, },
}, },
Ingredient { Ingredient {
key: "potato", key: "potato",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "картофель", ru: "картофель",
en: Some("potato"), en: Some(
"potato",
),
}, },
}, },
Ingredient { Ingredient {
key: "wheat_flour", key: "wheat_flour",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "пшеничная мука", ru: "пшеничная мука",
en: Some("wheat flour"), en: Some(
"wheat flour",
),
}, },
}, },
Ingredient { Ingredient {
key: "olive_oil", key: "olive_oil",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "оливковое масло", ru: "оливковое масло",
en: Some("olive oil"), en: Some(
"olive oil",
),
}, },
}, },
Ingredient { Ingredient {
key: "dry_yeast", key: "dry_yeast",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "сухие дрожжи", ru: "сухие дрожжи",
en: Some("dry yeast"), en: Some(
"dry yeast",
),
}, },
}, },
Ingredient { Ingredient {
key: "apple", key: "apple",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "яблоко", ru: "яблоко",
en: Some("apple"), en: Some(
"apple",
),
}, },
}, },
Ingredient { Ingredient {
key: "banana", key: "banana",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "банан", ru: "банан",
en: Some("banana"), en: Some(
"banana",
),
}, },
}, },
Ingredient { Ingredient {
key: "orange", key: "orange",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "апельсин", ru: "апельсин",
en: Some("orange"), en: Some(
"orange",
),
}, },
}, },
Ingredient { Ingredient {
key: "salt", key: "salt",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "соль", ru: "соль",
en: Some("salt"), en: Some(
"salt",
),
}, },
}, },
Ingredient { Ingredient {
key: "sugar", key: "sugar",
translates: IngredientTranslate { translates: IngredientTranslate {
ru: "сахар", 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,
},
},
];
}

View File

@ -3,10 +3,10 @@ mod data;
fn main() { fn main() {
println!("Hello, world!"); println!("Hello, world!");
dbg!(data::INGREDIENTS let banana = data::INGREDIENTS.into_iter().find(|i| i.key == "banana");
.into_iter() dbg!(banana);
.filter(|i| i.key == "banana")
.collect::<Vec<data::Ingredient>>()); dbg!(data::RECIPES.iter().collect::<Vec<_>>());
// let cfg: config::Main = toml::from_str(include_str!("../data/ingredients/fruit.toml")).unwrap(); // 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(); // let cfg: config::Main = toml::from_str(include_str!("../data/recipes/pizza.toml")).unwrap();