this codebase redefines spaghetti holy fuck

This commit is contained in:
xqtc 2024-10-13 23:22:12 +02:00
parent 8447e89f19
commit ab8ac79434
11 changed files with 270 additions and 24964 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
.idea

35
Cargo.lock generated
View file

@ -187,6 +187,15 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
@ -400,6 +409,12 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.70"
@ -450,10 +465,12 @@ dependencies = [
"bincode",
"chrono",
"clap",
"clap_complete",
"color-eyre",
"inquire",
"lazy_static",
"serde",
"serde_json",
"strum",
"strum_macros",
"toml",
@ -588,6 +605,12 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -614,6 +637,18 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"

View file

@ -11,7 +11,11 @@ color-eyre = "0.6.3"
inquire = "0.7.5"
lazy_static = "1.5.0"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
strum = { version = "0.26.3", features = ["derive"] }
strum_macros = "0.26.4"
toml = "0.8.19"
uuid = { version = "1.10.0", features = ["serde", "v4"] }
[build-dependencies]
clap_complete = "4.5.33"

Binary file not shown.

View file

@ -39,4 +39,5 @@ lazy_static! {
format!("{}/substances.bin", LOCAL_PATH.to_string()).to_string();
pub static ref INGESTIONS_FILE: String =
format!("{}/ingestions.bin", LOCAL_PATH.to_string()).to_string();
// pub static ref DRUGS: crate::drug_parser::Drugs = drug_parser::parse_drugs_json("drugs.json").unwrap();
}

View file

@ -1,30 +1,41 @@
use crate::ingestions_util::{
ensure_ingestion_files, get_dose_unit, get_ingestion_confirmation, get_ingestion_method,
get_substance, get_user_datetime,
get_substance, get_user_date, get_user_time,
};
use chrono::NaiveDateTime;
use chrono::{NaiveDate, NaiveTime, Utc};
use inquire;
use serde::{self, Deserialize, Serialize};
use std::cmp::PartialEq;
use std::collections::HashMap;
use std::fmt::Formatter;
use std::process::exit;
use uuid::Uuid;
use crate::config::INGESTIONS_FILE;
use crate::substances::Substance;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Ingestion {
pub substance: String,
pub substance: Substance,
pub dose: Dose,
pub ingestion_method: IngestionMethod,
pub time: NaiveDateTime,
pub time: NaiveTime,
pub date: NaiveDate,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
impl std::fmt::Display for Ingestion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {} {} {}{}", self.date, self.time.format("%H:%M"), self.substance.name, self.dose.value, self.dose.unit)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub struct Dose {
pub unit: String,
pub value: f64,
}
#[derive(Serialize, Deserialize, Debug, strum::Display, strum::EnumIter)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, strum::Display, strum::EnumIter)]
#[strum(serialize_all = "snake_case")]
pub enum DoseUnit {
Ug,
@ -33,7 +44,7 @@ pub enum DoseUnit {
Ml,
}
#[derive(Serialize, Deserialize, Debug, Clone, strum::Display, strum::EnumIter)]
#[derive(Serialize, Deserialize, Debug, Clone, Eq, strum::Display, strum::EnumIter, PartialEq)]
pub enum IngestionMethod {
Oral,
Sublingual,
@ -55,7 +66,9 @@ pub fn add_ingestion() {
let ingestion_method = get_ingestion_method();
let time: NaiveDateTime = get_user_datetime();
let current_datetime = Utc::now().naive_utc();
let date: NaiveDate = get_user_date(current_datetime);
let time: NaiveTime = get_user_time(current_datetime);
let dose_num: f64 = inquire::prompt_f64("Enter the amount consumed:").unwrap();
let dose_unit: DoseUnit = get_dose_unit();
@ -68,6 +81,7 @@ pub fn add_ingestion() {
substance,
dose,
ingestion_method,
date,
time,
};
@ -83,11 +97,11 @@ pub fn add_ingestion() {
pub fn list_ingestions() -> Result<(), std::io::Error> {
let ing_read = std::fs::read(INGESTIONS_FILE.to_string()).unwrap();
let ing_dec: HashMap<Uuid, Ingestion> = bincode::deserialize(&ing_read).unwrap();
for (id, ingestion) in ing_dec.clone().into_iter() {
let ing_des: HashMap<Uuid, Ingestion> = bincode::deserialize(&ing_read).unwrap();
for (id, ingestion) in ing_des.clone().into_iter() {
println!(
"Substance: {} ({})\nDose: {}{}\nTime: {}\nUUID: {:?}\n",
ingestion.substance,
"Substance: {} ({})\nDose: {} {}\nTime: {}\nUUID: {:?}\n",
ingestion.substance.name,
ingestion.ingestion_method,
ingestion.dose.value,
ingestion.dose.unit,
@ -99,6 +113,137 @@ pub fn list_ingestions() -> Result<(), std::io::Error> {
Ok(())
}
pub fn edit_ingestion() -> Result<(), std::io::Error> {
let ing_des = ensure_ingestion_files();
if ing_des.is_empty() {
eprintln!("No ingestions to edit!");
exit(1);
}
let mut ingest_sel_vec_id: Vec<Uuid> = Vec::new();
let mut ingest_sel_vec_ing: Vec<Ingestion> = Vec::new();
for ingestion in ing_des.clone().into_iter() {
ingest_sel_vec_id.push(ingestion.0);
ingest_sel_vec_ing.push(ingestion.1);
}
let ingest_select = inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing).prompt().unwrap();
let ing_id = ing_des.iter()
.map(|(key, &ref val)| if val.substance.name == ingest_select.substance.name && val.substance.substance_class == ingest_select.substance.substance_class && val.date == ingest_select.date && val.time == ingest_select.time { key.clone() } else { unreachable!() }).collect::<Vec<Uuid>>();
let edit_select = inquire::MultiSelect::new("What do you want to edit?", vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"]).prompt().unwrap();
for edit in edit_select {
match edit {
"Substance" => {
let substance = get_substance();
let ingestion = Ingestion {
substance,
dose: ingest_select.dose.clone(),
ingestion_method: ingest_select.ingestion_method.clone(),
time: ingest_select.time,
date: ingest_select.date,
};
let confirm = get_ingestion_confirmation(ingestion.clone());
if confirm {
let mut ing_des = ensure_ingestion_files();
ing_des.insert(ing_id[0], ingestion.clone());
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else {
edit_ingestion();
}
}
"Dose" => {
let dose_num: f64 = inquire::prompt_f64("Enter the amount consumed:").unwrap();
let dose_unit: DoseUnit = get_dose_unit();
let dose = Dose {
unit: dose_unit.to_string(),
value: dose_num,
};
let ingestion = Ingestion {
substance: ingest_select.substance.clone(),
dose,
ingestion_method: ingest_select.ingestion_method.clone(),
time: ingest_select.time,
date: ingest_select.date,
};
let confirm = get_ingestion_confirmation(ingestion.clone());
if confirm {
let mut ing_des = ensure_ingestion_files();
ing_des.insert(ing_id[0], ingestion.clone());
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else {
edit_ingestion();
}
}
"Ingestion Method" => {
let ingestion_method = get_ingestion_method();
let ingestion = Ingestion {
substance: ingest_select.substance.clone(),
dose: ingest_select.dose.clone(),
ingestion_method,
time: ingest_select.time,
date: ingest_select.date,
};
let confirm = get_ingestion_confirmation(ingestion.clone());
if confirm {
let mut ing_des = ensure_ingestion_files();
ing_des.insert(ing_id[0], ingestion.clone());
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else {
edit_ingestion();
}
}
"Time" => {
let time: NaiveTime = get_user_time(Utc::now().naive_utc());
let ingestion = Ingestion {
substance: ingest_select.substance.clone(),
dose: ingest_select.dose.clone(),
ingestion_method: ingest_select.ingestion_method.clone(),
time,
date: ingest_select.date,
};
let confirm = get_ingestion_confirmation(ingestion.clone());
if confirm {
let mut ing_des = ensure_ingestion_files();
ing_des.insert(ing_id[0], ingestion.clone());
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else {
edit_ingestion();
}
}
"Date" => {
let date: NaiveDate = get_user_date(Utc::now().naive_utc());
let ingestion = Ingestion {
substance: ingest_select.substance.clone(),
dose: ingest_select.dose.clone(),
ingestion_method: ingest_select.ingestion_method.clone(),
time: ingest_select.time,
date,
};
let confirm = get_ingestion_confirmation(ingestion.clone());
if confirm {
let mut ing_des = ensure_ingestion_files();
ing_des.insert(ing_id[0], ingestion.clone());
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else {
edit_ingestion();
}
}
_ => {}
}
}
Ok(())
}
pub fn create_ingestions_file() -> Result<(), std::io::Error> {
let hash: HashMap<Uuid, Ingestion> = HashMap::new();
let hash_ser = bincode::serialize(&hash).unwrap();

View file

@ -1,7 +1,8 @@
use crate::config::INGESTIONS_FILE;
use crate::ingestions::{DoseUnit, Ingestion, IngestionMethod};
use crate::substances::Substance;
use crate::util::path_exists;
use chrono::Utc;
use chrono::NaiveDateTime;
use inquire;
use std::{collections::HashMap, process::exit};
use strum::IntoEnumIterator;
@ -10,8 +11,8 @@ use uuid::Uuid;
pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
let ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>;
if path_exists(INGESTIONS_FILE.to_string()) {
let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).unwrap();
ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap();
let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).expect("Could not deserialize ingestions file. If you are tech-savvy try fixing it with a hex editor.");
} else {
std::fs::File::create(INGESTIONS_FILE.to_string()).unwrap();
ingesstions_bytes_loaded_des = HashMap::new();
@ -22,21 +23,39 @@ pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
ingesstions_bytes_loaded_des
}
pub fn get_user_datetime() -> chrono::NaiveDateTime {
let current_time = Utc::now().naive_utc();
let date_time: chrono::NaiveDateTime = inquire::CustomType::<chrono::NaiveDateTime>::new(
"Enter the date and time (YYYY-MM-DD HH:MM):",
pub fn get_user_date(current: NaiveDateTime) -> chrono::NaiveDate {
let current_time = current.time();
let current_date = current.date();
let date: chrono::NaiveDate = inquire::CustomType::<chrono::NaiveDate>::new(
"Enter the date (YYYY-MM-DD):",
)
.with_placeholder("YYYY-MM-DD HH:MM")
.with_default(current_time)
.with_placeholder("YYYY-MM-DD")
.with_default(current_date)
.with_parser(&|input| {
chrono::NaiveDateTime::parse_from_str(input, "%Y-%m-%d %H:%M").map_err(|_| ())
chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
})
.with_error_message("Please enter a valid date and time in the format YYYY-MM-DD HH:MM.")
.with_help_message("Use the format YYYY-MM-DD HH:MM")
.with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
.with_help_message("Use the format YYYY-MM-DD")
.prompt()
.unwrap();
date_time
date
}
pub fn get_user_time(current: NaiveDateTime) -> chrono::NaiveTime {
let current_time = current.time();
let time: chrono::NaiveTime = inquire::CustomType::<chrono::NaiveTime>::new(
"Enter the time (HH:MM):",
)
.with_placeholder("HH:MM")
.with_default(current_time)
.with_parser(&|input| {
chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ())
})
.with_error_message("Please enter a valid time in the format HH:MM.")
.with_help_message("Use the format HH:MM")
.prompt()
.unwrap();
time
}
pub fn get_dose_unit() -> DoseUnit {
@ -49,15 +68,30 @@ pub fn get_dose_unit() -> DoseUnit {
dose_unit
}
pub fn get_substance() -> String {
pub fn get_substance() -> Substance {
let substances = crate::substance_util::substances_to_vec();
if substances.is_empty() {
eprintln!("Add a substance before you log an ingestions");
exit(1)
}
let substance = inquire::Select::new("What did yout ingest?", substances)
let substance_select = inquire::Select::new("What did yout ingest?", substances)
.prompt()
.unwrap();
let substance_file: HashMap<Uuid, Substance> = crate::substance_util::ensure_substance_file();
let substances: Vec<Substance> = substance_file
.into_iter()
.filter_map(|(_, s)| if s.name == substance_select { Some(s) } else { None })
.collect();
if substances.len() != 1 {
eprintln!("Substance not found or multiple substances with the same name.");
exit(1);
}
let substance = substances.into_iter().next().unwrap();
dbg!(&substance);
substance
}
@ -74,7 +108,7 @@ pub fn get_ingestion_method() -> IngestionMethod {
pub fn get_ingestion_confirmation(ingestion: Ingestion) -> bool {
println!(
"Substance: {} ({})\nDose: {}{}\nTime: {}\n",
ingestion.substance,
ingestion.substance.name,
ingestion.ingestion_method,
ingestion.dose.value,
ingestion.dose.unit,

View file

@ -11,6 +11,8 @@ mod ingestions_util;
mod substance_util;
mod substances;
// mod drug_parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
@ -53,7 +55,7 @@ fn main() {
match &cli.command {
Some(Commands::AddIngestion) => ingestions::add_ingestion(),
Some(Commands::EditIngestion) => {}
Some(Commands::EditIngestion) => {ingestions::edit_ingestion().unwrap()}
Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(),
Some(Commands::RemoveIngestion) => {}
Some(Commands::AddSubstance) => substances::add_substance().unwrap(),

View file

@ -6,7 +6,7 @@ use uuid::Uuid;
use crate::config::SUBSTANCES_FILE;
use crate::substance_util::{ensure_substance_file, get_substance_class, substances_to_vec};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Substance {
pub name: String,
pub substance_class: SubstanceClass,
@ -25,6 +25,11 @@ pub enum SubstanceClass {
Neurotransmitter,
}
impl PartialEq for SubstanceClass {
fn eq(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
}
pub fn add_substance() -> Result<(), std::io::Error> {
let mut substances_bytes_loaded_des: HashMap<Uuid, Substance> = ensure_substance_file();
let name = inquire::prompt_text("What is the substances name?").unwrap();

Binary file not shown.

File diff suppressed because it is too large Load diff