Remaining subcommands for substances

This commit is contained in:
xqtc 2024-10-12 01:09:44 +02:00
parent 51ad2bf67e
commit 8447e89f19
7 changed files with 189 additions and 80 deletions

View file

@ -3,8 +3,6 @@ use serde::Deserialize;
use std::fs; use std::fs;
use std::process::exit; use std::process::exit;
use crate::substances;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Config { pub struct Config {
pub save_dir: String, pub save_dir: String,

View file

@ -1,16 +1,14 @@
use crate::ingestions_util::{ use crate::ingestions_util::{
self, ensure_ingestion_files, get_dose_unit, get_ingestion_confirmation, get_ingestion_method, ensure_ingestion_files, get_dose_unit, get_ingestion_confirmation, get_ingestion_method,
get_substance, get_user_datetime, get_substance, get_user_datetime,
}; };
use chrono::{NaiveDateTime, Utc}; use chrono::NaiveDateTime;
use color_eyre::Section;
use inquire; use inquire;
use serde::{self, Deserialize, Serialize}; use serde::{self, Deserialize, Serialize};
use std::{collections::HashMap, process::exit}; use std::collections::HashMap;
use strum::{EnumIter, IntoEnumIterator};
use uuid::Uuid; use uuid::Uuid;
use crate::{config::INGESTIONS_FILE, substances::Substance}; use crate::config::INGESTIONS_FILE;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Ingestion { pub struct Ingestion {
@ -77,7 +75,7 @@ pub fn add_ingestion() {
if confirm { if confirm {
ingesstions_bytes_loaded_des.insert(Uuid::new_v4(), ingestion.clone()); ingesstions_bytes_loaded_des.insert(Uuid::new_v4(), ingestion.clone());
let ingestion_ser = bincode::serialize(&ingesstions_bytes_loaded_des).unwrap(); let ingestion_ser = bincode::serialize(&ingesstions_bytes_loaded_des).unwrap();
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser); std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
} else { } else {
add_ingestion(); add_ingestion();
} }

View file

@ -1,16 +1,15 @@
use crate::config::INGESTIONS_FILE;
use crate::ingestions::{DoseUnit, Ingestion, IngestionMethod}; use crate::ingestions::{DoseUnit, Ingestion, IngestionMethod};
use crate::{config::INGESTIONS_FILE, substances::Substance}; use crate::util::path_exists;
use chrono::{NaiveDateTime, Utc}; use chrono::Utc;
use color_eyre::Section;
use inquire; use inquire;
use serde::{self, Deserialize, Serialize};
use std::{collections::HashMap, process::exit}; use std::{collections::HashMap, process::exit};
use strum::{EnumIter, IntoEnumIterator}; use strum::IntoEnumIterator;
use uuid::Uuid; use uuid::Uuid;
pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> { pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
let mut ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>; let ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>;
if crate::substances::path_exists(INGESTIONS_FILE.to_string()) { if path_exists(INGESTIONS_FILE.to_string()) {
let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).unwrap(); let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).unwrap();
ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap(); ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap();
} else { } else {
@ -51,7 +50,7 @@ pub fn get_dose_unit() -> DoseUnit {
} }
pub fn get_substance() -> String { pub fn get_substance() -> String {
let substances = crate::substances::substances_to_vec(); let substances = crate::substance_util::substances_to_vec();
if substances.is_empty() { if substances.is_empty() {
eprintln!("Add a substance before you log an ingestions"); eprintln!("Add a substance before you log an ingestions");
exit(1) exit(1)

View file

@ -4,9 +4,11 @@ use clap::{Parser, Subcommand};
use config::{INGESTIONS_FILE, LOCAL_PATH, SUBSTANCES_FILE}; use config::{INGESTIONS_FILE, LOCAL_PATH, SUBSTANCES_FILE};
mod config; mod config;
mod util;
mod ingestions; mod ingestions;
mod ingestions_util; mod ingestions_util;
mod substance_util;
mod substances; mod substances;
#[derive(Parser)] #[derive(Parser)]
@ -55,15 +57,15 @@ fn main() {
Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(), Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(),
Some(Commands::RemoveIngestion) => {} Some(Commands::RemoveIngestion) => {}
Some(Commands::AddSubstance) => substances::add_substance().unwrap(), Some(Commands::AddSubstance) => substances::add_substance().unwrap(),
Some(Commands::EditSubstance) => {} Some(Commands::EditSubstance) => substances::edit_substance().unwrap(),
Some(Commands::ListSubstances) => substances::list_substances().unwrap(), Some(Commands::ListSubstances) => substances::list_substances().unwrap(),
Some(Commands::RemoveSubstance) => {} Some(Commands::RemoveSubstance) => substances::remove_substance().unwrap(),
None => {} None => {}
} }
} }
fn ensure_files() { fn ensure_files() {
if !substances::path_exists(LOCAL_PATH.to_string()) { if !util::path_exists(LOCAL_PATH.to_string()) {
match std::fs::create_dir(LOCAL_PATH.to_string()) { match std::fs::create_dir(LOCAL_PATH.to_string()) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -72,8 +74,8 @@ fn ensure_files() {
} }
} }
} }
if !substances::path_exists(SUBSTANCES_FILE.to_string()) { if !util::path_exists(SUBSTANCES_FILE.to_string()) {
match substances::create_substances_file() { match substance_util::create_substances_file() {
Ok(_) => { Ok(_) => {
println!( println!(
"Created substances file at {:?}", "Created substances file at {:?}",
@ -86,7 +88,7 @@ fn ensure_files() {
} }
}; };
} }
if !substances::path_exists(INGESTIONS_FILE.to_string()) { if !util::path_exists(INGESTIONS_FILE.to_string()) {
match ingestions::create_ingestions_file() { match ingestions::create_ingestions_file() {
Ok(_) => { Ok(_) => {
println!( println!(

50
src/substance_util.rs Normal file
View file

@ -0,0 +1,50 @@
use std::collections::HashMap;
use uuid::Uuid;
use crate::substances::SubstanceClass;
use crate::util::path_exists;
use crate::{config::SUBSTANCES_FILE, substances::Substance};
pub fn ensure_substance_file() -> HashMap<Uuid, Substance> {
let substances_bytes_loaded_des: HashMap<Uuid, Substance>;
if path_exists(SUBSTANCES_FILE.to_string()) {
let substances_bytes_loaded = std::fs::read(SUBSTANCES_FILE.to_string()).unwrap();
substances_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap();
} else {
std::fs::File::create(SUBSTANCES_FILE.to_string()).unwrap();
substances_bytes_loaded_des = HashMap::new();
}
substances_bytes_loaded_des
}
pub fn get_substance_class(msg: &str, variants: Vec<SubstanceClass>) -> SubstanceClass {
let class = inquire::Select::new(msg, variants).prompt().unwrap();
class
}
pub fn substances_to_vec() -> Vec<String> {
let sub_read_res = std::fs::read(SUBSTANCES_FILE.to_string());
let sub_read = match sub_read_res {
Ok(sub_contents) => sub_contents,
Err(_) => {
println!("Error! Substance file does not exist. Creating file...");
let hash: HashMap<Uuid, Substance> = HashMap::new();
let hash_ser = bincode::serialize(&hash).unwrap();
std::fs::write(SUBSTANCES_FILE.to_string(), hash_ser).unwrap();
let ret: Vec<u8> = vec![];
ret
}
};
let sub_dec: HashMap<Uuid, Substance> = bincode::deserialize(&sub_read).unwrap();
let mut sub_vec: Vec<String> = vec![];
for (_id, substance) in sub_dec.clone().into_iter() {
sub_vec.push(substance.name);
}
sub_vec
}
pub fn create_substances_file() -> Result<(), std::io::Error> {
let hash: HashMap<Uuid, Substance> = HashMap::new();
let hash_ser = bincode::serialize(&hash).unwrap();
std::fs::write(SUBSTANCES_FILE.to_string(), hash_ser)
}

View file

@ -1,18 +1,19 @@
use serde::{self, Deserialize, Serialize}; use serde::{self, Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use strum::{EnumIter, IntoEnumIterator}; use strum::IntoEnumIterator;
use uuid::Uuid; use uuid::Uuid;
use crate::config::SUBSTANCES_FILE; 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)]
pub struct Substance { pub struct Substance {
name: String, pub name: String,
class: SubstanceClass, pub substance_class: SubstanceClass,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Copy, strum::Display, strum::EnumIter)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, strum::Display, strum::EnumIter)]
enum SubstanceClass { pub enum SubstanceClass {
Stimulant, Stimulant,
Depressant, Depressant,
Psychedelic, Psychedelic,
@ -24,44 +25,18 @@ enum SubstanceClass {
Neurotransmitter, Neurotransmitter,
} }
impl SubstanceClass {
fn to_string(&self) -> String {
match self {
Self::Stimulant => "Stimulant".to_string(),
Self::Depressant => "Depressant".to_string(),
Self::Psychedelic => "Psychedelic".to_string(),
Self::Dissociative => "Dissociative".to_string(),
Self::Cannabinoid => "Cannabinoid".to_string(),
Self::Entheogen => "Entheogen".to_string(),
Self::Deliriant => "Deliriant".to_string(),
Self::Empathogen => "Empathogen".to_string(),
Self::Neurotransmitter => "Neurotransmitter".to_string(),
}
}
}
pub fn path_exists(path: String) -> bool {
std::fs::metadata(path).is_ok()
}
pub fn add_substance() -> Result<(), std::io::Error> { pub fn add_substance() -> Result<(), std::io::Error> {
let mut substances_bytes_loaded_des: HashMap<Uuid, Substance>; let mut substances_bytes_loaded_des: HashMap<Uuid, Substance> = ensure_substance_file();
if path_exists(SUBSTANCES_FILE.to_string()) {
let substances_bytes_loaded = std::fs::read(SUBSTANCES_FILE.to_string()).unwrap();
substances_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap();
} else {
std::fs::File::create(SUBSTANCES_FILE.to_string()).unwrap();
substances_bytes_loaded_des = HashMap::new();
}
let name = inquire::prompt_text("What is the substances name?").unwrap(); let name = inquire::prompt_text("What is the substances name?").unwrap();
if !substances_bytes_loaded_des.values().any(|x| x.name == name) { if !substances_bytes_loaded_des.values().any(|x| x.name == name) {
let class_variants = SubstanceClass::iter().collect::<Vec<_>>(); let class_variants = SubstanceClass::iter().collect::<Vec<_>>();
let class_select = inquire::Select::new("What type of substance is this?", class_variants) let substance_class =
.prompt() get_substance_class("What type of substance is this?", class_variants);
.unwrap();
let substance = Substance { let substance = Substance {
name, name,
class: class_select, substance_class,
}; };
let subs_hash = substances_bytes_loaded_des.insert(Uuid::new_v4(), substance); substances_bytes_loaded_des.insert(Uuid::new_v4(), substance);
let sub_enc = bincode::serialize(&substances_bytes_loaded_des).unwrap(); let sub_enc = bincode::serialize(&substances_bytes_loaded_des).unwrap();
match std::fs::write(SUBSTANCES_FILE.to_string(), sub_enc) { match std::fs::write(SUBSTANCES_FILE.to_string(), sub_enc) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
@ -79,36 +54,120 @@ pub fn list_substances() -> Result<(), std::io::Error> {
for (id, substance) in sub_dec.clone().into_iter() { for (id, substance) in sub_dec.clone().into_iter() {
println!( println!(
"Name: {}\nClass: {:?}\nUUID: {:?}\n", "Name: {}\nClass: {:?}\nUUID: {:?}\n",
substance.name, substance.class, id substance.name, substance.substance_class, id
); );
} }
Ok(()) Ok(())
} }
pub fn substances_to_vec() -> Vec<String> { pub fn remove_substance() -> Result<(), std::io::Error> {
let sub_read_res = std::fs::read(SUBSTANCES_FILE.to_string()); let sub_read = std::fs::read(SUBSTANCES_FILE.to_string()).unwrap();
let sub_read = match sub_read_res { let mut sub_dec: HashMap<Uuid, Substance> = bincode::deserialize(&sub_read).unwrap();
Ok(sub_contents) => sub_contents,
Err(_) => { let substances = substances_to_vec();
println!("Error! Substance file does not exist. Creating file..."); let substances_select =
let hash: HashMap<Uuid, Substance> = HashMap::new(); inquire::MultiSelect::new("Which substance do you want to remove?", substances)
let hash_ser = bincode::serialize(&hash).unwrap(); .prompt()
std::fs::write(SUBSTANCES_FILE.to_string(), hash_ser).unwrap(); .unwrap();
let ret: Vec<u8> = vec![]; dbg!(&substances_select);
ret for name in substances_select {
let confirm = inquire::prompt_confirmation(format!(
"Are you sure you want to remove '{}'? [y/N]",
name
))
.unwrap();
if confirm {
// Clone to avoid immutable borrow
let sub_dec_clone = sub_dec.clone();
let uuid =
sub_dec_clone
.iter()
.find_map(|(id, val)| if val.name == name { Some(id) } else { None });
if uuid.is_some() {
let _ = sub_dec
.remove(uuid.expect("Fatal error. Couldn't find substance UUID in HashMap."));
} }
};
let sub_dec: HashMap<Uuid, Substance> = bincode::deserialize(&sub_read).unwrap();
let mut sub_vec: Vec<String> = vec![];
for (id, substance) in sub_dec.clone().into_iter() {
sub_vec.push(substance.name);
} }
sub_vec
} }
pub fn create_substances_file() -> Result<(), std::io::Error> { let sub_enc = bincode::serialize(&sub_dec).unwrap();
let hash: HashMap<Uuid, Substance> = HashMap::new(); match std::fs::write(SUBSTANCES_FILE.to_string(), sub_enc) {
let hash_ser = bincode::serialize(&hash).unwrap(); Ok(_) => Ok(()),
std::fs::write(SUBSTANCES_FILE.to_string(), hash_ser) Err(e) => Err(e),
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, strum::Display, strum::EnumIter)]
pub enum SubstanceEditOptions {
Name,
Class,
}
pub fn edit_substance() -> Result<(), std::io::Error> {
let sub_read = std::fs::read(SUBSTANCES_FILE.to_string()).unwrap();
let mut sub_dec: HashMap<Uuid, Substance> = bincode::deserialize(&sub_read).unwrap();
let substances = substances_to_vec();
let substance_name = inquire::Select::new("Which substance do you want to edit?", substances)
.prompt()
.unwrap();
dbg!(&substance_name);
let sub_dec_clone = sub_dec.clone();
let uuid_opt = sub_dec_clone.iter().find_map(|(id, val)| {
if val.name == substance_name {
Some(id)
} else {
None
}
});
if uuid_opt.is_some() {
let uuid = uuid_opt.clone().unwrap().to_owned();
let _ = sub_dec
.remove(uuid_opt.expect("Fatal error. Couldn't find substance UUID in HashMap."));
let edit_select = inquire::Select::new(
format!("[{}] What do you want to edit?", substance_name).as_str(),
SubstanceEditOptions::iter().collect::<Vec<_>>(),
)
.prompt()
.unwrap();
match edit_select {
SubstanceEditOptions::Name => {
let name_updated = inquire::prompt_text("What should the new name be?").unwrap();
let class = match sub_dec_clone
.get(uuid_opt.expect("Fatal error. Couldn't find substance UUID in HashMap."))
{
Some(class) => class.substance_class,
None => {
panic!("Fatal error. Couldn't find substance UUID in HashMap.")
}
};
dbg!(&class);
let substance = Substance {
name: name_updated,
substance_class: class,
};
sub_dec.insert(uuid, substance);
}
SubstanceEditOptions::Class => {
let class_variants = SubstanceClass::iter().collect::<Vec<_>>();
let substance_class = get_substance_class(
format!(
"[{}] What should the new substance class be?",
substance_name
)
.as_str(),
class_variants,
);
let substance = Substance {
name: substance_name,
substance_class,
};
sub_dec.insert(uuid, substance);
}
}
let sub_enc = bincode::serialize(&sub_dec).unwrap();
std::fs::write(SUBSTANCES_FILE.to_string(), sub_enc).unwrap();
}
Ok(())
} }

3
src/util.rs Normal file
View file

@ -0,0 +1,3 @@
pub fn path_exists(path: String) -> bool {
std::fs::metadata(path).is_ok()
}