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"
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"

View File

@ -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"

View File

@ -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<fs::File>) -> 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<RecipeIngredient>,
steps: u8,
ingredients: Vec<RecipeIngredient>,
translates: RecipeTranslates,
}
@ -79,19 +83,21 @@ pub struct Main {
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 {
ru: String,
en: Option<String>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize)]
pub struct Recipe {
key: String,
ingredients: Vec<RecipeIngredient>,
@ -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<RecipeTranslate>,
}
#[derive(Deserialize, Debug)]
#[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; {}] = [{}];",
"pub const INGREDIENTS: [Ingredient; {}] = {:#?};\n",
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())))
@ -175,10 +196,28 @@ fn get_ingredient_configs() -> Result<Vec<Ingredient>, std::io::Error> {
.collect::<Vec<Ingredient>>())
}
fn indent(indent_size: usize) -> String {
std::iter::repeat(" ").take(indent_size * 4).collect()
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 to_str(string: String) -> &'static str {
Box::leak(string.into_boxed_str())
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>>())
}

View File

@ -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<RecipeIngredient>,
steps: u8,
ingredients: Vec<RecipeIngredient>,
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,
},
},
];
}

View File

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