update
This commit is contained in:
parent
0097705c82
commit
6148b1cddd
|
@ -1,9 +1,6 @@
|
|||
use rand::Rng;
|
||||
|
||||
use crate::types::{
|
||||
CustomUnit, Experience, ExportFormat, Ingestion,
|
||||
Unit,
|
||||
};
|
||||
use crate::types::{CustomUnit, Experience, ExportFormat, Ingestion, Unit};
|
||||
|
||||
pub type JournalType = Box<dyn Journal>;
|
||||
|
||||
|
@ -52,7 +49,7 @@ impl Journal for InMemJournal {
|
|||
fn first_experience_by_title(&self, title: &str) -> Option<&Experience> {
|
||||
self.experiences
|
||||
.values()
|
||||
.find(|&experience| &experience.title == title)
|
||||
.find(|&experience| experience.title == title)
|
||||
}
|
||||
|
||||
fn import_psychonaut(&mut self, data: psychonaut_journal_types::ExportData) {
|
||||
|
|
227
journal/src/types/dose_with_unit.rs
Normal file
227
journal/src/types/dose_with_unit.rs
Normal file
|
@ -0,0 +1,227 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use super::{Dose, Estimation, Unit};
|
||||
|
||||
pub fn format_dose(dose: &Dose, unit: &Unit) -> String {
|
||||
format!("{}", DoseWithUnitRefs { dose, unit })
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
pub struct DoseWithUnit {
|
||||
pub dose: Dose,
|
||||
pub unit: Unit,
|
||||
}
|
||||
pub(crate) struct DoseWithUnitRefs<'a> {
|
||||
pub dose: &'a Dose,
|
||||
pub unit: &'a Unit,
|
||||
}
|
||||
|
||||
impl Display for DoseWithUnit {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DoseWithUnitRefs {
|
||||
dose: &self.dose,
|
||||
unit: &self.unit
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DoseWithUnitRefs<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let dose = self.dose;
|
||||
let unit = self.unit;
|
||||
|
||||
match unit {
|
||||
Unit::Simple(unit) => {
|
||||
let is_unknown = dose.contains_unknown && dose.value == 0.0;
|
||||
let is_estimate = dose.estimation.is_estimate() && !is_unknown;
|
||||
|
||||
if is_estimate {
|
||||
f.write_str("~")?;
|
||||
}
|
||||
|
||||
if is_unknown {
|
||||
f.write_str("Unknown")?
|
||||
} else {
|
||||
let dose_rounded = (dose.value * 100.0).round() / 100.0;
|
||||
write!(f, "{}", dose_rounded)?;
|
||||
|
||||
if dose.contains_unknown {
|
||||
f.write_str("+Unknown")?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Estimation::StandardDeviation(deviation) = dose.estimation {
|
||||
write!(f, "±{}", (deviation.deviation * 100.0).round() / 100.0)?;
|
||||
}
|
||||
|
||||
f.write_str((" ".to_string() + unit).as_str())
|
||||
}
|
||||
Unit::Custom { id: _id, unit } => {
|
||||
let unit = unit.clone().unwrap();
|
||||
let unit_unit = Unit::Simple(unit.unit.clone());
|
||||
|
||||
let ingestion_dose = dose * &unit.dose;
|
||||
let ingestion_unit = Unit::Simple(unit.original_unit.clone());
|
||||
|
||||
// ingestion dose
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DoseWithUnitRefs {
|
||||
dose: &ingestion_dose,
|
||||
unit: &ingestion_unit
|
||||
}
|
||||
)?;
|
||||
|
||||
f.write_str(" (")?;
|
||||
|
||||
// dose per unit
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DoseWithUnitRefs {
|
||||
dose: &unit.dose,
|
||||
unit: &ingestion_unit
|
||||
}
|
||||
)?;
|
||||
|
||||
f.write_str(" * ")?;
|
||||
|
||||
// custom unit dose
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DoseWithUnitRefs {
|
||||
dose,
|
||||
unit: &unit_unit
|
||||
}
|
||||
)?;
|
||||
|
||||
f.write_str(")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::{AdministrationRoute, CustomUnit, StandardDeviation};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn format_dose() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: false,
|
||||
estimation: Estimation::Precise,
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "0 mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_dose_non_refs() {
|
||||
let result = format!(
|
||||
"{}",
|
||||
DoseWithUnit {
|
||||
dose: Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: false,
|
||||
estimation: Estimation::Precise,
|
||||
},
|
||||
unit: Unit::Simple("mg".to_string())
|
||||
}
|
||||
);
|
||||
assert_eq!(result, "0 mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_dose_estimate() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: false,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "~0 mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_dose_contains_unknown() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 10.0,
|
||||
contains_unknown: true,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "~10+Unknown mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_dose_standard_derivation() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: false,
|
||||
estimation: Estimation::StandardDeviation(StandardDeviation {
|
||||
expectation: 0.0,
|
||||
deviation: 10.0,
|
||||
}),
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "~0±10 mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_unknown_dose() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: true,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "Unknown mg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_unknown_dose_with_custom_unit() {
|
||||
let result = super::format_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: true,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
&Unit::Custom {
|
||||
id: 0,
|
||||
unit: Some(CustomUnit {
|
||||
name: "Beverage".to_string(),
|
||||
substance_name: "Caffeine".to_string(),
|
||||
unit: "sip".to_string(),
|
||||
original_unit: "mg".to_string(),
|
||||
dose: Dose {
|
||||
value: 10.0,
|
||||
contains_unknown: false,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
administration_route: AdministrationRoute::Oral,
|
||||
..CustomUnit::default()
|
||||
}),
|
||||
},
|
||||
);
|
||||
assert_eq!(result, "Unknown mg (~10 mg * Unknown sip)");
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
use std::ops::{Add, Mul};
|
||||
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
#[derive(Default)]
|
||||
#[derive(PartialEq, Debug, Copy, Clone, Default)]
|
||||
pub enum Estimation {
|
||||
#[default]
|
||||
Precise,
|
||||
Precise,
|
||||
Estimate,
|
||||
StandardDeviation(StandardDeviation),
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Default, Debug, Copy, Clone)]
|
||||
pub struct StandardDeviation {
|
||||
pub expectation: f64,
|
||||
|
|
|
@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
|
|||
|
||||
use super::from_unix_millis;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Default, Debug, Clone)]
|
||||
pub struct Experience {
|
||||
pub id: i64,
|
||||
pub title: String,
|
||||
|
|
|
@ -5,7 +5,7 @@ use super::{
|
|||
Unit,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(PartialEq, Default, Debug, Clone)]
|
||||
pub struct Ingestion {
|
||||
pub substance_name: String,
|
||||
pub ingestion_time: DateTime<Utc>,
|
||||
|
|
|
@ -5,6 +5,12 @@ pub use estimate::{Estimation, StandardDeviation};
|
|||
mod dose;
|
||||
pub use dose::Dose;
|
||||
|
||||
mod unit;
|
||||
pub use unit::Unit;
|
||||
|
||||
mod dose_with_unit;
|
||||
pub use dose_with_unit::{format_dose, DoseWithUnit};
|
||||
|
||||
mod consumer;
|
||||
pub use consumer::Consumer;
|
||||
|
||||
|
@ -23,9 +29,6 @@ pub use custom_unit::CustomUnit;
|
|||
mod export;
|
||||
pub use export::ExportFormat;
|
||||
|
||||
mod unit;
|
||||
pub use unit::Unit;
|
||||
|
||||
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
||||
|
||||
pub(crate) fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
||||
|
|
|
@ -5,3 +5,9 @@ pub enum Unit {
|
|||
Simple(String),
|
||||
Custom { id: i64, unit: Option<CustomUnit> },
|
||||
}
|
||||
|
||||
impl Default for Unit {
|
||||
fn default() -> Self {
|
||||
Unit::Simple("mg".to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use journal::{
|
||||
journal::JournalType,
|
||||
types::{Consumer, Experience},
|
||||
types::{format_dose, Consumer, Experience},
|
||||
};
|
||||
|
||||
use crate::formatting::{format_ingestion_dose, format_ingestion_roa, format_ingestion_time};
|
||||
use crate::formatting::{format_ingestion_roa, format_ingestion_time};
|
||||
|
||||
pub fn print_ingestion_log(
|
||||
journal: &JournalType,
|
||||
|
@ -34,7 +34,7 @@ pub fn print_ingestion_log(
|
|||
println!(
|
||||
"{}|{}|{}|{}|{}",
|
||||
ingestion.substance_name,
|
||||
format_ingestion_dose(&ingestion.dose, &unit),
|
||||
format_dose(&ingestion.dose, &unit),
|
||||
format_ingestion_roa(ingestion, &unit),
|
||||
ingestion.consumer,
|
||||
format_ingestion_time(ingestion)
|
||||
|
|
|
@ -1,60 +1,9 @@
|
|||
use journal::types::{Dose, Estimation, Experience, Ingestion, Unit};
|
||||
use journal::types::{Experience, Ingestion, Unit};
|
||||
|
||||
pub fn format_experience_title(experience: &Experience) -> String {
|
||||
format!("{}: {}", experience.title, experience.creation_time)
|
||||
}
|
||||
|
||||
pub fn format_ingestion_dose(dose: &Dose, unit: &Unit) -> String {
|
||||
if dose.value != 0.0 && !dose.contains_unknown {
|
||||
match unit {
|
||||
Unit::Simple(unit) => {
|
||||
let is_estimate = dose.estimation.is_estimate();
|
||||
|
||||
let estimate = if is_estimate { "~" } else { "" };
|
||||
let standard_deviation = {
|
||||
if let Estimation::StandardDeviation(deviation) = dose.estimation {
|
||||
format!("±{}", (deviation.deviation * 100.0).round() / 100.0)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
let unknown = if dose.contains_unknown {
|
||||
"+Unknown"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let dose = (dose.value * 100.0).round() / 100.0;
|
||||
|
||||
format!("{estimate}{dose}{standard_deviation}{unknown} {unit}")
|
||||
}
|
||||
Unit::Custom { id: _id, unit } => {
|
||||
let unit = unit.clone().unwrap();
|
||||
let unit_unit = Unit::Simple(unit.unit.clone());
|
||||
|
||||
let ingestion_dose = dose * &unit.dose;
|
||||
|
||||
let ingestion_unit = Unit::Simple(unit.original_unit.clone());
|
||||
|
||||
let ingestion_dose = format_ingestion_dose(&ingestion_dose, &ingestion_unit);
|
||||
|
||||
let dose_per_unit = format_ingestion_dose(&unit.dose, &ingestion_unit);
|
||||
|
||||
let custom_unit_dose = format_ingestion_dose(dose, &unit_unit);
|
||||
|
||||
format!("{ingestion_dose} ({dose_per_unit} * {custom_unit_dose})")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
format!(
|
||||
"Unknown {}",
|
||||
match unit {
|
||||
Unit::Simple(unit) => unit,
|
||||
Unit::Custom { id: _id, unit } => &unit.as_ref().unwrap().original_unit,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_ingestion_time(ingestion: &Ingestion) -> String {
|
||||
ingestion.ingestion_time.format("%a %I:%M %p").to_string()
|
||||
}
|
||||
|
@ -69,39 +18,57 @@ pub fn format_ingestion_roa(ingestion: &Ingestion, unit: &Unit) -> String {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use journal::types::CustomUnit;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use journal::types::{AdministrationRoute, CustomUnit};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn format_unknown_dose() {
|
||||
let result = format_ingestion_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: true,
|
||||
estimation: Estimation::Estimate,
|
||||
},
|
||||
&Unit::Simple("mg".to_string()),
|
||||
);
|
||||
assert_eq!(result, "Unknown mg");
|
||||
fn format_experience_title() {
|
||||
let result = super::format_experience_title(&Experience {
|
||||
title: "Title".to_string(),
|
||||
creation_time: Utc.timestamp_millis_opt(0).unwrap(),
|
||||
..Experience::default()
|
||||
});
|
||||
assert_eq!(result, "Title: 1970-01-01 00:00:00 UTC");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_unknown_dose_custom_unit() {
|
||||
let result = format_ingestion_dose(
|
||||
&Dose {
|
||||
value: 0.0,
|
||||
contains_unknown: true,
|
||||
estimation: Estimation::Estimate,
|
||||
fn format_ingestion_time() {
|
||||
let result = super::format_ingestion_time(&Ingestion {
|
||||
creation_time: Utc.timestamp_millis_opt(0).unwrap(),
|
||||
..Ingestion::default()
|
||||
});
|
||||
assert_eq!(result, "Thu 12:00 AM");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_ingestion_roa() {
|
||||
let result = super::format_ingestion_roa(
|
||||
&Ingestion {
|
||||
roa: AdministrationRoute::Oral,
|
||||
..Ingestion::default()
|
||||
},
|
||||
&Unit::default(),
|
||||
);
|
||||
assert_eq!(result, "Oral");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_ingestion_roa_with_custom_unit() {
|
||||
let result = super::format_ingestion_roa(
|
||||
&Ingestion {
|
||||
roa: AdministrationRoute::Oral,
|
||||
..Ingestion::default()
|
||||
},
|
||||
&Unit::Custom {
|
||||
id: 0,
|
||||
unit: Some(CustomUnit {
|
||||
original_unit: "mg".to_string(),
|
||||
name: "32mg/ml".to_string(),
|
||||
..CustomUnit::default()
|
||||
}),
|
||||
},
|
||||
);
|
||||
assert_eq!(result, "Unknown mg");
|
||||
assert_eq!(result, "Oral (32mg/ml)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
mod tests;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum AdministrationRoute {
|
||||
|
@ -119,3 +117,28 @@ pub struct ExportData {
|
|||
pub custom_substances: Vec<CustomSubstance>,
|
||||
pub custom_units: Vec<CustomUnit>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{AdministrationRoute::*, *};
|
||||
|
||||
#[test]
|
||||
fn default_administration_dose() {
|
||||
assert_eq!(AdministrationRoute::default(), AdministrationRoute::Oral);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn administration_dose_to_string() {
|
||||
assert_eq!(Oral.to_string(), "Oral");
|
||||
assert_eq!(Sublingual.to_string(), "Sublingual");
|
||||
assert_eq!(Buccal.to_string(), "Buccal");
|
||||
assert_eq!(Insufflated.to_string(), "Insufflated");
|
||||
assert_eq!(Rectal.to_string(), "Rectal");
|
||||
assert_eq!(Transdermal.to_string(), "Transdermal");
|
||||
assert_eq!(Subcutaneous.to_string(), "Subcutaneous");
|
||||
assert_eq!(Intramuscular.to_string(), "Intramuscular");
|
||||
assert_eq!(Intravenous.to_string(), "Intravenous");
|
||||
assert_eq!(Smoked.to_string(), "Smoked");
|
||||
assert_eq!(Inhaled.to_string(), "Inhaled");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::AdministrationRoute::{self, *};
|
||||
|
||||
#[test]
|
||||
fn default_administration_dose() {
|
||||
assert_eq!(AdministrationRoute::default(), AdministrationRoute::Oral);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn administration_dose_to_string() {
|
||||
assert_eq!(Oral.to_string(), "Oral");
|
||||
assert_eq!(Sublingual.to_string(), "Sublingual");
|
||||
assert_eq!(Buccal.to_string(), "Buccal");
|
||||
assert_eq!(Insufflated.to_string(), "Insufflated");
|
||||
assert_eq!(Rectal.to_string(), "Rectal");
|
||||
assert_eq!(Transdermal.to_string(), "Transdermal");
|
||||
assert_eq!(Subcutaneous.to_string(), "Subcutaneous");
|
||||
assert_eq!(Intramuscular.to_string(), "Intramuscular");
|
||||
assert_eq!(Intravenous.to_string(), "Intravenous");
|
||||
assert_eq!(Smoked.to_string(), "Smoked");
|
||||
assert_eq!(Inhaled.to_string(), "Inhaled");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue