update
This commit is contained in:
parent
114b1d1813
commit
12b76f3a90
|
@ -1,2 +1,4 @@
|
||||||
hard_tabs = true
|
hard_tabs = true
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
|
unstable_features = true
|
||||||
|
imports_granularity = "Crate"
|
195
Cargo.lock
generated
195
Cargo.lock
generated
|
@ -53,7 +53,7 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -63,7 +63,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -72,12 +72,6 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.16.0"
|
||||||
|
@ -172,54 +166,6 @@ version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "csv"
|
|
||||||
version = "1.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
|
|
||||||
dependencies = [
|
|
||||||
"csv-core",
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "csv-core"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-next"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"dirs-sys-next",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-sys-next"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"redox_users",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encode_unicode"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -237,12 +183,6 @@ version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.61"
|
version = "0.1.61"
|
||||||
|
@ -266,17 +206,6 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
|
@ -308,36 +237,17 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.162"
|
version = "0.2.162"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
|
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libredox"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
|
@ -369,20 +279,6 @@ dependencies = [
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prettytable-rs"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a"
|
|
||||||
dependencies = [
|
|
||||||
"csv",
|
|
||||||
"encode_unicode",
|
|
||||||
"is-terminal",
|
|
||||||
"lazy_static",
|
|
||||||
"term",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.89"
|
version = "1.0.89"
|
||||||
|
@ -399,8 +295,6 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"journal",
|
"journal",
|
||||||
"log",
|
|
||||||
"prettytable-rs",
|
|
||||||
"psychonaut_journal_types",
|
"psychonaut_journal_types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -452,23 +346,6 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_users"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"libredox",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -530,49 +407,12 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "term"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
|
|
||||||
dependencies = [
|
|
||||||
"dirs-next",
|
|
||||||
"rustversion",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.13"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -640,28 +480,6 @@ version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
@ -671,15 +489,6 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
use crate::types::doses::{CustomUnitDose, StandardDose};
|
|
||||||
|
|
||||||
pub fn calulate_custom_unit_dose(
|
|
||||||
dose: &CustomUnitDose,
|
|
||||||
custom_unit_dose: &CustomUnitDose,
|
|
||||||
) -> StandardDose {
|
|
||||||
let dose: StandardDose = dose.clone().into();
|
|
||||||
let custom_unit_dose: StandardDose = custom_unit_dose.clone().into();
|
|
||||||
|
|
||||||
custom_unit_dose * dose
|
|
||||||
}
|
|
|
@ -2,8 +2,8 @@ use chrono::{DateTime, TimeZone, Utc};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
doses::{CustomUnitDose, Dose, StandardDose, UnknownDose},
|
Consumer, CustomUnit, Dose, Estimation, Experience, ExportFormat, Ingestion, StandardDeviation,
|
||||||
Consumer, CustomUnit, Estimation, Experience, ExportFormat, Ingestion,
|
Unit,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type JournalType = Box<dyn Journal>;
|
pub type JournalType = Box<dyn Journal>;
|
||||||
|
@ -14,7 +14,7 @@ pub trait Journal {
|
||||||
fn get_experience_ingestions(&self, id: i64) -> Option<&Vec<Ingestion>>;
|
fn get_experience_ingestions(&self, id: i64) -> Option<&Vec<Ingestion>>;
|
||||||
|
|
||||||
fn first_experience_by_title(&self, title: &str) -> Option<&Experience>;
|
fn first_experience_by_title(&self, title: &str) -> Option<&Experience>;
|
||||||
fn maybe_custom_unit(&self, ingestion: &Ingestion) -> Option<&CustomUnit>;
|
fn resolve_unit(&self, unit: &Unit) -> Unit;
|
||||||
|
|
||||||
fn import_psychonaut(&mut self, data: psychonaut_journal_types::ExportData);
|
fn import_psychonaut(&mut self, data: psychonaut_journal_types::ExportData);
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,19 @@ impl Journal for InMemJournal {
|
||||||
self.ingestions.get(&id)
|
self.ingestions.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_custom_unit(&self, ingestion: &Ingestion) -> Option<&CustomUnit> {
|
fn resolve_unit(&self, unit: &Unit) -> Unit {
|
||||||
match &ingestion.dose {
|
match unit {
|
||||||
Dose::CustomUnit(dose) => self.get_custom_unit(dose.custom_unit_id),
|
Unit::Simple(_) => unit.clone(),
|
||||||
_ => None,
|
Unit::Custom { id, unit } => match unit {
|
||||||
|
Some(unit) => Unit::Custom {
|
||||||
|
id: *id,
|
||||||
|
unit: Some(unit.clone()),
|
||||||
|
},
|
||||||
|
None => Unit::Custom {
|
||||||
|
id: *id,
|
||||||
|
unit: self.get_custom_unit(*id).cloned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,101 +57,19 @@ impl Journal for InMemJournal {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_psychonaut(&mut self, data: psychonaut_journal_types::ExportData) {
|
fn import_psychonaut(&mut self, data: psychonaut_journal_types::ExportData) {
|
||||||
fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
|
||||||
Utc.timestamp_millis_opt(time as i64).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
for custom_unit in data.custom_units.into_iter() {
|
for custom_unit in data.custom_units.into_iter() {
|
||||||
let estimation = if custom_unit.is_estimate {
|
self.custom_units
|
||||||
if let Some(standard_deviation) = custom_unit.estimate_standard_deviation {
|
.insert(custom_unit.id, CustomUnit::from(custom_unit));
|
||||||
Estimation::StandardDeviation(standard_deviation)
|
|
||||||
} else {
|
|
||||||
Estimation::Estimate
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Estimation::Precise
|
|
||||||
};
|
|
||||||
|
|
||||||
let dose = CustomUnitDose {
|
|
||||||
dose: custom_unit.dose,
|
|
||||||
unit: custom_unit.unit,
|
|
||||||
original_unit: custom_unit.original_unit,
|
|
||||||
custom_unit_id: custom_unit.id,
|
|
||||||
estimation,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.custom_units.insert(
|
|
||||||
custom_unit.id,
|
|
||||||
CustomUnit {
|
|
||||||
id: custom_unit.id,
|
|
||||||
name: custom_unit.name,
|
|
||||||
substance_name: custom_unit.substance_name,
|
|
||||||
|
|
||||||
administration_route: custom_unit.administration_route,
|
|
||||||
dose,
|
|
||||||
|
|
||||||
creation_time: from_unix_millis(custom_unit.creation_time),
|
|
||||||
is_archived: custom_unit.is_archived,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for experience in data.experiences.into_iter() {
|
for experience in data.experiences.into_iter() {
|
||||||
let experience_id = rng.gen::<i64>();
|
let experience_id = rng.gen::<i64>();
|
||||||
|
|
||||||
let mut ingestions: Vec<Ingestion> = Vec::new();
|
let mut ingestions: Vec<Ingestion> = Vec::new();
|
||||||
for ingestion in experience.ingestions.into_iter() {
|
for ingestion in experience.ingestions.iter() {
|
||||||
let estimation = if !ingestion.is_estimate {
|
ingestions.push(Ingestion::from(ingestion.clone()))
|
||||||
Estimation::Precise
|
|
||||||
} else if let Some(standard_deviation) = ingestion.estimate_standard_deviation {
|
|
||||||
Estimation::StandardDeviation(standard_deviation)
|
|
||||||
} else {
|
|
||||||
Estimation::Estimate
|
|
||||||
};
|
|
||||||
|
|
||||||
let dose = if let Some(dose) = ingestion.dose {
|
|
||||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
|
||||||
let custom_unit = self
|
|
||||||
.custom_units
|
|
||||||
.get(&custom_unit_id)
|
|
||||||
.expect("custom unit not found");
|
|
||||||
|
|
||||||
Dose::CustomUnit(CustomUnitDose {
|
|
||||||
dose,
|
|
||||||
unit: custom_unit.dose.unit.clone(),
|
|
||||||
original_unit: custom_unit.dose.original_unit.clone(),
|
|
||||||
estimation,
|
|
||||||
custom_unit_id,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Dose::Standard(StandardDose {
|
|
||||||
dose,
|
|
||||||
unit: ingestion.unit,
|
|
||||||
estimation,
|
|
||||||
contains_unknown: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Dose::Unknown(UnknownDose {
|
|
||||||
unit: ingestion.unit,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
ingestions.push(Ingestion {
|
|
||||||
substance_name: ingestion.substance_name,
|
|
||||||
ingestion_time: from_unix_millis(ingestion.ingestion_time),
|
|
||||||
creation_time: from_unix_millis(ingestion.creation_time),
|
|
||||||
dose,
|
|
||||||
roa: ingestion.roa,
|
|
||||||
consumer: match ingestion.consumer_name {
|
|
||||||
Some(name) => Consumer::Named(name),
|
|
||||||
None => Consumer::Default,
|
|
||||||
},
|
|
||||||
notes: ingestion.notes,
|
|
||||||
stomach_fullness: ingestion.stomach_fullness,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ingestions.insert(experience_id, ingestions);
|
self.ingestions.insert(experience_id, ingestions);
|
||||||
|
@ -151,10 +78,7 @@ impl Journal for InMemJournal {
|
||||||
experience_id,
|
experience_id,
|
||||||
Experience {
|
Experience {
|
||||||
id: experience_id,
|
id: experience_id,
|
||||||
title: experience.title,
|
..Experience::from(experience)
|
||||||
text: experience.text,
|
|
||||||
creation_time: from_unix_millis(experience.creation_time),
|
|
||||||
modified_time: from_unix_millis(experience.modified_time),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
pub mod helpers;
|
|
||||||
pub mod journal;
|
pub mod journal;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub enum Consumer {
|
pub enum Consumer {
|
||||||
|
@ -6,23 +6,49 @@ pub enum Consumer {
|
||||||
Named(String),
|
Named(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Consumer {
|
impl Default for Consumer {
|
||||||
type Err = core::convert::Infallible;
|
fn default() -> Self {
|
||||||
|
Self::Default
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
if s == "default" {
|
|
||||||
Ok(Consumer::Default)
|
|
||||||
} else {
|
|
||||||
Ok(Consumer::Named(s.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Consumer {
|
impl Display for Consumer {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Consumer::Default => f.write_str("default"),
|
Self::Default => f.write_str("default"),
|
||||||
Consumer::Named(name) => f.write_str(name),
|
Self::Named(name) => f.write_str(name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Consumer {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
if value == "default" {
|
||||||
|
Self::Default
|
||||||
|
} else {
|
||||||
|
Self::Named(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Consumer::{self, *};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default() {
|
||||||
|
assert_eq!(Consumer::default(), Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_string() {
|
||||||
|
assert_eq!(Default.to_string(), "default");
|
||||||
|
assert_eq!(Consumer::from("name").to_string(), "name");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_string() {
|
||||||
|
assert_eq!(Consumer::from("default"), Default);
|
||||||
|
assert_eq!(Consumer::from("name"), Named("name".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,102 @@
|
||||||
use crate::types::{doses::CustomUnitDose, AdministrationRoute};
|
use super::{from_unix_millis, AdministrationRoute, Dose, Estimation, StandardDeviation};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Default, PartialEq, Debug, Clone)]
|
||||||
pub struct CustomUnit {
|
pub struct CustomUnit {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub substance_name: String,
|
pub substance_name: String,
|
||||||
|
pub unit: String,
|
||||||
|
pub original_unit: String,
|
||||||
|
|
||||||
|
pub dose: Option<Dose>,
|
||||||
pub administration_route: AdministrationRoute,
|
pub administration_route: AdministrationRoute,
|
||||||
pub dose: CustomUnitDose,
|
|
||||||
|
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
pub is_archived: bool,
|
pub is_archived: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<psychonaut_journal_types::CustomUnit> for CustomUnit {
|
||||||
|
fn from(custom_unit: psychonaut_journal_types::CustomUnit) -> Self {
|
||||||
|
CustomUnit {
|
||||||
|
id: custom_unit.id,
|
||||||
|
name: custom_unit.name,
|
||||||
|
substance_name: custom_unit.substance_name,
|
||||||
|
unit: custom_unit.unit,
|
||||||
|
original_unit: custom_unit.original_unit,
|
||||||
|
|
||||||
|
dose: match custom_unit.dose {
|
||||||
|
Some(dose) => Some(Dose {
|
||||||
|
value: dose,
|
||||||
|
contains_unknown: false,
|
||||||
|
estimation: {
|
||||||
|
if custom_unit.is_estimate {
|
||||||
|
if let Some(deviation) = custom_unit.estimate_standard_deviation {
|
||||||
|
Estimation::StandardDeviation(StandardDeviation {
|
||||||
|
expectation: custom_unit.dose.unwrap_or_default(),
|
||||||
|
deviation,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Estimation::Estimate
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Estimation::Precise
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
|
||||||
|
administration_route: custom_unit.administration_route,
|
||||||
|
|
||||||
|
creation_time: from_unix_millis(custom_unit.creation_time),
|
||||||
|
is_archived: custom_unit.is_archived,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::{from_unix_millis, Dose, StandardDeviation};
|
||||||
|
|
||||||
|
use super::{AdministrationRoute, CustomUnit};
|
||||||
|
use psychonaut_journal_types::CustomUnit as PsychonautCustomUnit;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion() {
|
||||||
|
assert_eq!(
|
||||||
|
CustomUnit::from(PsychonautCustomUnit {
|
||||||
|
id: 0,
|
||||||
|
substance_name: "Caffeine".to_string(),
|
||||||
|
name: "Beverage".to_string(),
|
||||||
|
creation_time: 0,
|
||||||
|
administration_route: AdministrationRoute::Oral,
|
||||||
|
dose: Some(10.0),
|
||||||
|
unit: "sip".to_string(),
|
||||||
|
original_unit: "mg".to_string(),
|
||||||
|
is_estimate: true,
|
||||||
|
estimate_standard_deviation: Some(10.0),
|
||||||
|
is_archived: false
|
||||||
|
}),
|
||||||
|
CustomUnit {
|
||||||
|
id: 0,
|
||||||
|
name: "Beverage".to_string(),
|
||||||
|
substance_name: "Caffeine".to_string(),
|
||||||
|
unit: "sip".to_string(),
|
||||||
|
original_unit: "mg".to_string(),
|
||||||
|
dose: Some(Dose {
|
||||||
|
value: 10.0,
|
||||||
|
contains_unknown: false,
|
||||||
|
estimation: crate::types::Estimation::StandardDeviation(StandardDeviation {
|
||||||
|
expectation: 10.0,
|
||||||
|
deviation: 10.0
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
administration_route: AdministrationRoute::Oral,
|
||||||
|
creation_time: from_unix_millis(0),
|
||||||
|
is_archived: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
229
journal/src/types/dose.rs
Normal file
229
journal/src/types/dose.rs
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
|
use super::Estimation;
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, Clone)]
|
||||||
|
pub struct Dose {
|
||||||
|
pub value: f64,
|
||||||
|
pub contains_unknown: bool,
|
||||||
|
pub estimation: Estimation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Dose {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
self + &rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for &Dose {
|
||||||
|
type Output = Dose;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
self.clone() + rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Dose> for &Dose {
|
||||||
|
type Output = Dose;
|
||||||
|
|
||||||
|
fn add(self, lhs: Dose) -> Self::Output {
|
||||||
|
lhs + self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<&Dose> for Dose {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: &Self) -> Self::Output {
|
||||||
|
let contains_unknown = self.contains_unknown || rhs.contains_unknown;
|
||||||
|
let estimation = match self.estimation + &rhs.estimation {
|
||||||
|
Estimation::Precise => {
|
||||||
|
if contains_unknown {
|
||||||
|
Estimation::Estimate
|
||||||
|
} else {
|
||||||
|
Estimation::Precise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value => value,
|
||||||
|
};
|
||||||
|
|
||||||
|
Dose {
|
||||||
|
value: self.value + rhs.value,
|
||||||
|
contains_unknown,
|
||||||
|
estimation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Dose {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
self * &rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for &Dose {
|
||||||
|
type Output = Dose;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
self.clone() * rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Dose> for &Dose {
|
||||||
|
type Output = Dose;
|
||||||
|
|
||||||
|
fn mul(self, lhs: Dose) -> Self::Output {
|
||||||
|
lhs * self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<&Dose> for Dose {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: &Self) -> Self::Output {
|
||||||
|
let contains_unknown = self.contains_unknown || rhs.contains_unknown;
|
||||||
|
let estimation = match self.estimation * &rhs.estimation {
|
||||||
|
Estimation::Precise => {
|
||||||
|
if contains_unknown {
|
||||||
|
Estimation::Estimate
|
||||||
|
} else {
|
||||||
|
Estimation::Precise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value => value,
|
||||||
|
};
|
||||||
|
|
||||||
|
Dose {
|
||||||
|
value: self.value * rhs.value,
|
||||||
|
contains_unknown,
|
||||||
|
estimation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{Dose, Estimation};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
let lhs = Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
let rhs = Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
let result = Dose {
|
||||||
|
value: 20.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(lhs.clone() + rhs.clone(), result);
|
||||||
|
assert_eq!(lhs.clone() + &rhs.clone(), result);
|
||||||
|
assert_eq!(&lhs.clone() + rhs.clone(), result);
|
||||||
|
assert_eq!(&lhs.clone() + &rhs.clone(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_with_estimate() {
|
||||||
|
assert_eq!(
|
||||||
|
Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
} + Dose {
|
||||||
|
value: 10.0,
|
||||||
|
estimation: Estimation::Estimate,
|
||||||
|
..Dose::default()
|
||||||
|
},
|
||||||
|
Dose {
|
||||||
|
value: 20.0,
|
||||||
|
estimation: Estimation::Estimate,
|
||||||
|
..Dose::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_with_unknown() {
|
||||||
|
assert_eq!(
|
||||||
|
Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
} + Dose {
|
||||||
|
value: 10.0,
|
||||||
|
contains_unknown: true,
|
||||||
|
..Dose::default()
|
||||||
|
},
|
||||||
|
Dose {
|
||||||
|
value: 20.0,
|
||||||
|
contains_unknown: true,
|
||||||
|
estimation: Estimation::Estimate
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul() {
|
||||||
|
let lhs = Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
let rhs = Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
let result = Dose {
|
||||||
|
value: 100.0,
|
||||||
|
..Dose::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(lhs.clone() * rhs.clone(), result);
|
||||||
|
assert_eq!(lhs.clone() * &rhs.clone(), result);
|
||||||
|
assert_eq!(&lhs.clone() * rhs.clone(), result);
|
||||||
|
assert_eq!(&lhs.clone() * &rhs.clone(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_with_estimate() {
|
||||||
|
assert_eq!(
|
||||||
|
Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
} * Dose {
|
||||||
|
value: 10.0,
|
||||||
|
estimation: Estimation::Estimate,
|
||||||
|
..Dose::default()
|
||||||
|
},
|
||||||
|
Dose {
|
||||||
|
value: 100.0,
|
||||||
|
estimation: Estimation::Estimate,
|
||||||
|
..Dose::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_with_unknown() {
|
||||||
|
assert_eq!(
|
||||||
|
Dose {
|
||||||
|
value: 10.0,
|
||||||
|
..Dose::default()
|
||||||
|
} * Dose {
|
||||||
|
value: 10.0,
|
||||||
|
contains_unknown: true,
|
||||||
|
..Dose::default()
|
||||||
|
},
|
||||||
|
Dose {
|
||||||
|
value: 100.0,
|
||||||
|
contains_unknown: true,
|
||||||
|
estimation: Estimation::Estimate
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
use std::ops::{Add, Mul};
|
|
||||||
|
|
||||||
use crate::types::Estimation;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Dose {
|
|
||||||
Unknown(UnknownDose),
|
|
||||||
Standard(StandardDose),
|
|
||||||
CustomUnit(CustomUnitDose),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct UnknownDose {
|
|
||||||
pub unit: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct StandardDose {
|
|
||||||
pub dose: f64,
|
|
||||||
pub unit: String,
|
|
||||||
pub contains_unknown: bool,
|
|
||||||
pub estimation: Estimation,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CustomUnitDose {
|
|
||||||
pub dose: f64,
|
|
||||||
pub unit: String,
|
|
||||||
pub original_unit: String,
|
|
||||||
pub estimation: Estimation,
|
|
||||||
pub custom_unit_id: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for StandardDose {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
StandardDose {
|
|
||||||
dose: self.dose + rhs.dose,
|
|
||||||
unit: self.unit,
|
|
||||||
contains_unknown: self.contains_unknown || rhs.contains_unknown,
|
|
||||||
estimation: self.estimation + rhs.estimation,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul for StandardDose {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
|
||||||
StandardDose {
|
|
||||||
dose: self.dose * rhs.dose,
|
|
||||||
unit: self.unit,
|
|
||||||
contains_unknown: self.contains_unknown || rhs.contains_unknown,
|
|
||||||
estimation: {
|
|
||||||
let estimation = self.estimation + rhs.estimation;
|
|
||||||
if let Estimation::StandardDeviation(deviation) = estimation {
|
|
||||||
Estimation::StandardDeviation(deviation * rhs.dose)
|
|
||||||
} else {
|
|
||||||
estimation
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CustomUnitDose> for StandardDose {
|
|
||||||
fn from(value: CustomUnitDose) -> StandardDose {
|
|
||||||
StandardDose {
|
|
||||||
dose: value.dose,
|
|
||||||
unit: value.original_unit,
|
|
||||||
contains_unknown: false,
|
|
||||||
estimation: value.estimation,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,19 @@ use std::ops::{Add, Mul};
|
||||||
pub enum Estimation {
|
pub enum Estimation {
|
||||||
Precise,
|
Precise,
|
||||||
Estimate,
|
Estimate,
|
||||||
StandardDeviation(f64),
|
StandardDeviation(StandardDeviation),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Estimation {
|
||||||
|
fn default() -> Self {
|
||||||
|
Estimation::Precise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Default, Debug, Copy, Clone)]
|
||||||
|
pub struct StandardDeviation {
|
||||||
|
pub expectation: f64,
|
||||||
|
pub deviation: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Estimation {
|
impl Estimation {
|
||||||
|
@ -19,16 +31,22 @@ impl Estimation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Estimation {
|
impl Add<&Estimation> for Estimation {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
fn add(self, rhs: &Self) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Estimation::StandardDeviation(x), Estimation::StandardDeviation(y)) => {
|
(Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => {
|
||||||
Estimation::StandardDeviation(x + y)
|
Estimation::StandardDeviation(StandardDeviation {
|
||||||
|
expectation: lhs.expectation + rhs.expectation,
|
||||||
|
deviation: lhs.deviation + rhs.deviation,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
(Estimation::StandardDeviation(x), _) | (_, Estimation::StandardDeviation(x)) => {
|
(Estimation::StandardDeviation(deviation), _) => {
|
||||||
Estimation::StandardDeviation(x)
|
Estimation::StandardDeviation(deviation)
|
||||||
|
}
|
||||||
|
(_, Estimation::StandardDeviation(deviation)) => {
|
||||||
|
Estimation::StandardDeviation(deviation.clone())
|
||||||
}
|
}
|
||||||
(Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate,
|
(Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate,
|
||||||
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
||||||
|
@ -36,19 +54,124 @@ impl Add for Estimation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul for Estimation {
|
impl Mul<&Estimation> for Estimation {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
fn mul(self, rhs: &Self) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Estimation::StandardDeviation(x), Estimation::StandardDeviation(y)) => {
|
(Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => {
|
||||||
Estimation::StandardDeviation(x * y)
|
let lhs_sum = lhs.deviation.powi(2) + lhs.expectation.powi(2);
|
||||||
|
let rhs_sum = rhs.deviation.powi(2) + rhs.expectation.powi(2);
|
||||||
|
|
||||||
|
let expectations = lhs.expectation.powi(2) * rhs.expectation.powi(2);
|
||||||
|
|
||||||
|
let product_variance = (lhs_sum * rhs_sum) - expectations;
|
||||||
|
|
||||||
|
if product_variance > 0.0000001 {
|
||||||
|
let deviation = product_variance.sqrt();
|
||||||
|
let expectation = lhs.expectation * rhs.expectation;
|
||||||
|
|
||||||
|
Estimation::StandardDeviation(StandardDeviation {
|
||||||
|
expectation,
|
||||||
|
deviation: deviation.round(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Estimation::Estimate
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(Estimation::StandardDeviation(x), _) | (_, Estimation::StandardDeviation(x)) => {
|
(Estimation::StandardDeviation(deviation), _) => {
|
||||||
Estimation::StandardDeviation(x)
|
Estimation::StandardDeviation(deviation)
|
||||||
|
}
|
||||||
|
(_, Estimation::StandardDeviation(deviation)) => {
|
||||||
|
Estimation::StandardDeviation(deviation.clone())
|
||||||
}
|
}
|
||||||
(Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate,
|
(Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate,
|
||||||
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{Estimation::*, StandardDeviation as Deviation};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is() {
|
||||||
|
let deviation = StandardDeviation(Deviation::default());
|
||||||
|
|
||||||
|
assert_eq!(Precise.is_precise(), true);
|
||||||
|
assert_eq!(Precise.is_estimate(), false);
|
||||||
|
assert_eq!(Precise.is_standard_deviation(), false);
|
||||||
|
|
||||||
|
assert_eq!(Estimate.is_precise(), false);
|
||||||
|
assert_eq!(Estimate.is_estimate(), true);
|
||||||
|
assert_eq!(Estimate.is_standard_deviation(), false);
|
||||||
|
|
||||||
|
assert_eq!(deviation.is_precise(), false);
|
||||||
|
assert_eq!(deviation.is_estimate(), true);
|
||||||
|
assert_eq!(deviation.is_standard_deviation(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
let deviation = StandardDeviation(Deviation {
|
||||||
|
expectation: 10.0,
|
||||||
|
deviation: 10.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(Precise + &Precise, Precise);
|
||||||
|
assert_eq!(Precise + &Estimate, Estimate);
|
||||||
|
assert_eq!(Precise + &deviation, deviation);
|
||||||
|
|
||||||
|
assert_eq!(Estimate + &Precise, Estimate);
|
||||||
|
assert_eq!(Estimate + &Estimate, Estimate);
|
||||||
|
assert_eq!(Estimate + &deviation, deviation);
|
||||||
|
|
||||||
|
assert_eq!(deviation + &Precise, deviation);
|
||||||
|
assert_eq!(deviation + &Estimate, deviation);
|
||||||
|
assert_eq!(
|
||||||
|
deviation + &deviation,
|
||||||
|
StandardDeviation(Deviation {
|
||||||
|
expectation: 20.0,
|
||||||
|
deviation: 20.0,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul() {
|
||||||
|
let deviation = StandardDeviation(Deviation {
|
||||||
|
expectation: 10.0,
|
||||||
|
deviation: 10.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(Precise * &Precise, Precise);
|
||||||
|
assert_eq!(Precise * &Estimate, Estimate);
|
||||||
|
assert_eq!(Precise * &deviation, deviation);
|
||||||
|
|
||||||
|
assert_eq!(Estimate * &Precise, Estimate);
|
||||||
|
assert_eq!(Estimate * &Estimate, Estimate);
|
||||||
|
assert_eq!(Estimate * &deviation, deviation);
|
||||||
|
|
||||||
|
assert_eq!(deviation * &Precise, deviation);
|
||||||
|
assert_eq!(deviation * &Estimate, deviation);
|
||||||
|
assert_eq!(
|
||||||
|
deviation * &deviation,
|
||||||
|
StandardDeviation(Deviation {
|
||||||
|
expectation: 100.0,
|
||||||
|
deviation: 173.0,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
StandardDeviation(Deviation {
|
||||||
|
expectation: 100.0,
|
||||||
|
deviation: 0.0,
|
||||||
|
}) * &StandardDeviation(Deviation {
|
||||||
|
expectation: 100.0,
|
||||||
|
deviation: 0.0,
|
||||||
|
}),
|
||||||
|
Estimate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
use super::from_unix_millis;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub struct Experience {
|
pub struct Experience {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -8,3 +10,43 @@ pub struct Experience {
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
pub modified_time: DateTime<Utc>,
|
pub modified_time: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<psychonaut_journal_types::Experience> for Experience {
|
||||||
|
fn from(experience: psychonaut_journal_types::Experience) -> Self {
|
||||||
|
Experience {
|
||||||
|
id: 0,
|
||||||
|
title: experience.title,
|
||||||
|
text: experience.text,
|
||||||
|
creation_time: from_unix_millis(experience.creation_time),
|
||||||
|
modified_time: from_unix_millis(experience.modified_time),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::from_unix_millis;
|
||||||
|
|
||||||
|
use super::Experience;
|
||||||
|
use psychonaut_journal_types::Experience as PsychonautExperience;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion() {
|
||||||
|
assert_eq!(
|
||||||
|
Experience::from(PsychonautExperience {
|
||||||
|
title: "Experience".to_string(),
|
||||||
|
text: "Some Text".to_string(),
|
||||||
|
creation_time: 0,
|
||||||
|
modified_time: 0,
|
||||||
|
ingestions: vec![]
|
||||||
|
}),
|
||||||
|
Experience {
|
||||||
|
id: 0,
|
||||||
|
title: "Experience".to_string(),
|
||||||
|
text: "Some Text".to_string(),
|
||||||
|
creation_time: from_unix_millis(0),
|
||||||
|
modified_time: from_unix_millis(0)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::types::{CustomUnit, Experience, Ingestion};
|
use super::{CustomUnit, Experience, Ingestion};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct ExportFormat {
|
pub struct ExportFormat {
|
||||||
|
|
|
@ -1,15 +1,107 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use crate::types::{doses::Dose, AdministrationRoute, Consumer};
|
use super::{
|
||||||
|
dose::Dose, from_unix_millis, AdministrationRoute, Consumer, Estimation, StandardDeviation,
|
||||||
|
Unit,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub struct Ingestion {
|
pub struct Ingestion {
|
||||||
pub substance_name: String,
|
pub substance_name: String,
|
||||||
pub ingestion_time: DateTime<Utc>,
|
pub ingestion_time: DateTime<Utc>,
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
pub dose: Dose,
|
pub dose: Option<Dose>,
|
||||||
|
pub unit: Unit,
|
||||||
pub roa: AdministrationRoute,
|
pub roa: AdministrationRoute,
|
||||||
pub consumer: Consumer,
|
pub consumer: Consumer,
|
||||||
pub notes: String,
|
pub notes: String,
|
||||||
pub stomach_fullness: Option<String>,
|
pub stomach_fullness: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<psychonaut_journal_types::Ingestion> for Ingestion {
|
||||||
|
fn from(ingestion: psychonaut_journal_types::Ingestion) -> Self {
|
||||||
|
Ingestion {
|
||||||
|
substance_name: ingestion.substance_name,
|
||||||
|
ingestion_time: from_unix_millis(ingestion.ingestion_time),
|
||||||
|
creation_time: from_unix_millis(ingestion.creation_time),
|
||||||
|
|
||||||
|
dose: match ingestion.dose {
|
||||||
|
Some(value) => Some(Dose {
|
||||||
|
value,
|
||||||
|
contains_unknown: false,
|
||||||
|
estimation: {
|
||||||
|
if !ingestion.is_estimate {
|
||||||
|
Estimation::Precise
|
||||||
|
} else if let Some(deviation) = ingestion.estimate_standard_deviation {
|
||||||
|
Estimation::StandardDeviation(StandardDeviation {
|
||||||
|
expectation: ingestion.dose.unwrap_or_default(),
|
||||||
|
deviation,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Estimation::Estimate
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
|
||||||
|
unit: match ingestion.custom_unit_id {
|
||||||
|
Some(id) => Unit::Custom { id, unit: None },
|
||||||
|
None => Unit::Simple(ingestion.unit),
|
||||||
|
},
|
||||||
|
|
||||||
|
roa: ingestion.roa,
|
||||||
|
|
||||||
|
consumer: match ingestion.consumer_name {
|
||||||
|
Some(name) => Consumer::Named(name),
|
||||||
|
None => Consumer::Default,
|
||||||
|
},
|
||||||
|
|
||||||
|
notes: ingestion.notes,
|
||||||
|
stomach_fullness: ingestion.stomach_fullness,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::{from_unix_millis, AdministrationRoute, Consumer, Dose, Estimation, Unit};
|
||||||
|
|
||||||
|
use super::Ingestion;
|
||||||
|
use psychonaut_journal_types::Ingestion as PsychonautIngestion;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion() {
|
||||||
|
assert_eq!(
|
||||||
|
Ingestion::from(PsychonautIngestion {
|
||||||
|
substance_name: "Caffeine".to_string(),
|
||||||
|
ingestion_time: 0,
|
||||||
|
creation_time: 0,
|
||||||
|
dose: Some(10.0),
|
||||||
|
unit: "mg".to_string(),
|
||||||
|
is_estimate: false,
|
||||||
|
estimate_standard_deviation: None,
|
||||||
|
custom_unit_id: None,
|
||||||
|
roa: AdministrationRoute::Oral,
|
||||||
|
consumer_name: None,
|
||||||
|
notes: "".to_string(),
|
||||||
|
stomach_fullness: None,
|
||||||
|
}),
|
||||||
|
Ingestion {
|
||||||
|
substance_name: "Caffeine".to_string(),
|
||||||
|
ingestion_time: from_unix_millis(0),
|
||||||
|
creation_time: from_unix_millis(0),
|
||||||
|
dose: Some(Dose {
|
||||||
|
value: 10.0,
|
||||||
|
contains_unknown: false,
|
||||||
|
estimation: Estimation::Precise
|
||||||
|
}),
|
||||||
|
unit: Unit::Simple("mg".to_string()),
|
||||||
|
roa: AdministrationRoute::Oral,
|
||||||
|
consumer: Consumer::Default,
|
||||||
|
notes: "".to_string(),
|
||||||
|
stomach_fullness: None
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
mod estimate;
|
mod estimate;
|
||||||
pub use estimate::Estimation;
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
pub use estimate::{Estimation, StandardDeviation};
|
||||||
|
|
||||||
pub mod doses;
|
mod dose;
|
||||||
|
pub use dose::Dose;
|
||||||
|
|
||||||
mod consumer;
|
mod consumer;
|
||||||
pub use consumer::Consumer;
|
pub use consumer::Consumer;
|
||||||
|
@ -21,4 +23,11 @@ pub use custom_unit::CustomUnit;
|
||||||
mod export;
|
mod export;
|
||||||
pub use export::ExportFormat;
|
pub use export::ExportFormat;
|
||||||
|
|
||||||
|
mod unit;
|
||||||
|
pub use unit::Unit;
|
||||||
|
|
||||||
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
||||||
|
|
||||||
|
pub(crate) fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
||||||
|
Utc.timestamp_millis_opt(time as i64).unwrap()
|
||||||
|
}
|
||||||
|
|
7
journal/src/types/unit.rs
Normal file
7
journal/src/types/unit.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use super::CustomUnit;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub enum Unit {
|
||||||
|
Simple(String),
|
||||||
|
Custom { id: i64, unit: Option<CustomUnit> },
|
||||||
|
}
|
|
@ -13,8 +13,8 @@ psychonaut_journal_types = { path = "../psychonaut_journal_types" }
|
||||||
|
|
||||||
chrono = { version = "0.4.38", features = ["serde"] }
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
clap = { version = "4.5.21", features = ["derive", "env"] }
|
clap = { version = "4.5.21", features = ["derive", "env"] }
|
||||||
log = { version = "0.4.22", features = ["std", "serde"] }
|
#log = { version = "0.4.22", features = ["std", "serde"] }
|
||||||
prettytable-rs = "0.10.0"
|
#prettytable-rs = "0.10.0"
|
||||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
||||||
serde_json = "1.0.132"
|
serde_json = "1.0.132"
|
||||||
#serde_with = "3.11.0"
|
#serde_with = "3.11.0"
|
||||||
|
|
|
@ -28,5 +28,5 @@ pub struct Args {
|
||||||
pub command: Commands,
|
pub command: Commands,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub journal_location: Option<JournalLocationArgs>,
|
pub journal_location: JournalLocationArgs,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use journal::types::Consumer;
|
use journal::types::Consumer;
|
||||||
|
|
||||||
use crate::args::Args;
|
use crate::{
|
||||||
use crate::display::print_ingestion_log;
|
args::Args, display::print_ingestion_log, formatting::format_experience_title,
|
||||||
use crate::formatting::format_experience_title;
|
utils::load_journal,
|
||||||
use crate::utils::load_journal;
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, clap::Args)]
|
#[derive(Debug, Clone, clap::Args)]
|
||||||
#[group(requires = "journal_location")]
|
#[group(requires = "journal_location")]
|
||||||
|
@ -23,12 +21,12 @@ pub fn parse_consumer_filter(consumer_filter: Option<Vec<String>>) -> Option<Vec
|
||||||
Some(consumer_filter) => {
|
Some(consumer_filter) => {
|
||||||
let mut consumers: Vec<Consumer> = Vec::new();
|
let mut consumers: Vec<Consumer> = Vec::new();
|
||||||
for consumer in consumer_filter.into_iter() {
|
for consumer in consumer_filter.into_iter() {
|
||||||
let mut consumer_name = consumer.as_str();
|
let mut consumer = consumer;
|
||||||
if consumer_name.is_empty() {
|
if consumer.is_empty() {
|
||||||
consumer_name = "default";
|
consumer = "default".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
consumers.push(Consumer::from_str(consumer_name).unwrap());
|
consumers.push(Consumer::from(consumer));
|
||||||
}
|
}
|
||||||
Some(consumers)
|
Some(consumers)
|
||||||
}
|
}
|
||||||
|
@ -43,8 +41,6 @@ pub fn print_experience(
|
||||||
let journal = load_journal(
|
let journal = load_journal(
|
||||||
&global_args
|
&global_args
|
||||||
.journal_location
|
.journal_location
|
||||||
.clone()
|
|
||||||
.unwrap()
|
|
||||||
.psychonaut_export_file
|
.psychonaut_export_file
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
|
@ -28,14 +28,14 @@ pub fn print_ingestion_log(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let custom_unit = journal.maybe_custom_unit(ingestion);
|
let unit = journal.resolve_unit(&ingestion.unit);
|
||||||
// println!("{:#?} {:#?}", &ingestion, &custom_unit);
|
// println!("{:#?} {:#?}", &ingestion, &custom_unit);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{}|{}|{}|{}|{}",
|
"{}|{}|{}|{}|{}",
|
||||||
ingestion.substance_name,
|
ingestion.substance_name,
|
||||||
format_ingestion_dose(&ingestion.dose, custom_unit.map(|f| &f.dose)),
|
format_ingestion_dose(ingestion.dose.as_ref(), &unit),
|
||||||
format_ingestion_roa(ingestion, custom_unit),
|
format_ingestion_roa(ingestion, &unit),
|
||||||
ingestion.consumer,
|
ingestion.consumer,
|
||||||
format_ingestion_time(ingestion)
|
format_ingestion_time(ingestion)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,58 +1,59 @@
|
||||||
use journal::{
|
use journal::types::{Dose, Estimation, Experience, Ingestion, Unit};
|
||||||
helpers::calulate_custom_unit_dose,
|
|
||||||
types::{
|
|
||||||
doses::{CustomUnitDose, Dose, StandardDose},
|
|
||||||
CustomUnit, Estimation, Experience, Ingestion,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn format_experience_title(experience: &Experience) -> String {
|
pub fn format_experience_title(experience: &Experience) -> String {
|
||||||
format!("{}: {}", experience.title, experience.creation_time)
|
format!("{}: {}", experience.title, experience.creation_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_ingestion_dose(dose: &Dose, custom_unit_dose: Option<&CustomUnitDose>) -> String {
|
pub fn format_ingestion_dose(dose: Option<&Dose>, unit: &Unit) -> String {
|
||||||
match dose {
|
match dose {
|
||||||
Dose::Unknown(dose) => format!("Unknown {}", dose.unit),
|
Some(dose) => match unit {
|
||||||
Dose::Standard(dose) => {
|
Unit::Simple(unit) => {
|
||||||
let is_estimate = dose.estimation.is_estimate();
|
let is_estimate = dose.estimation.is_estimate();
|
||||||
|
|
||||||
let estimate = if is_estimate { "~" } else { "" };
|
let estimate = if is_estimate { "~" } else { "" };
|
||||||
let standard_deviation = {
|
let standard_deviation = {
|
||||||
if let Estimation::StandardDeviation(standard_deviation) = dose.estimation {
|
if let Estimation::StandardDeviation(deviation) = dose.estimation {
|
||||||
format!("±{}", (standard_deviation * 100.0).round() / 100.0)
|
format!("±{}", (deviation.deviation * 100.0).round() / 100.0)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let unknown = if dose.contains_unknown {
|
||||||
|
"+Unknown"
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
""
|
||||||
}
|
};
|
||||||
};
|
let dose = (dose.value * 100.0).round() / 100.0;
|
||||||
let dose_value = (dose.dose * 100.0).round() / 100.0;
|
|
||||||
let unit = dose.unit.clone();
|
|
||||||
|
|
||||||
format!("{estimate}{dose_value}{standard_deviation} {unit}")
|
format!("{estimate}{dose}{standard_deviation}{unknown} {unit}")
|
||||||
}
|
}
|
||||||
Dose::CustomUnit(dose) => {
|
Unit::Custom { id: _id, unit } => {
|
||||||
let custom_unit_dose = custom_unit_dose.expect("custom unit dose required");
|
let unit = unit.clone().unwrap();
|
||||||
|
let unit_unit = Unit::Simple(unit.unit.clone());
|
||||||
|
|
||||||
let ingestion_dose = calulate_custom_unit_dose(dose, custom_unit_dose);
|
let ingestion_dose = match &unit.dose {
|
||||||
|
Some(unit_dose) => dose * unit_dose,
|
||||||
|
None => dose.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let ingestion_dose = format_ingestion_dose(&Dose::Standard(ingestion_dose), None);
|
let ingestion_unit = Unit::Simple(unit.original_unit.clone());
|
||||||
|
|
||||||
let dose_per_unit = format_ingestion_dose(
|
let ingestion_dose = format_ingestion_dose(Some(&ingestion_dose), &ingestion_unit);
|
||||||
&Dose::Standard(StandardDose::from(custom_unit_dose.clone())),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let custom_unit_dose = format_ingestion_dose(
|
let dose_per_unit = format_ingestion_dose(unit.dose.as_ref(), &ingestion_unit);
|
||||||
&Dose::Standard(StandardDose {
|
|
||||||
dose: dose.dose,
|
|
||||||
unit: custom_unit_dose.unit.clone(),
|
|
||||||
contains_unknown: false,
|
|
||||||
estimation: dose.estimation,
|
|
||||||
}),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
format!("{ingestion_dose} ({dose_per_unit} * {custom_unit_dose})")
|
let custom_unit_dose = format_ingestion_dose(Some(&dose), &unit_unit);
|
||||||
}
|
|
||||||
|
format!("{ingestion_dose} ({dose_per_unit} * {custom_unit_dose})")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => format!(
|
||||||
|
"Unknown {}",
|
||||||
|
match unit {
|
||||||
|
Unit::Simple(unit) => unit,
|
||||||
|
Unit::Custom { id: _id, unit } => &unit.as_ref().unwrap().original_unit,
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +61,38 @@ pub fn format_ingestion_time(ingestion: &Ingestion) -> String {
|
||||||
ingestion.ingestion_time.format("%a %I:%M %p").to_string()
|
ingestion.ingestion_time.format("%a %I:%M %p").to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_ingestion_roa(ingestion: &Ingestion, custom_unit: Option<&CustomUnit>) -> String {
|
pub fn format_ingestion_roa(ingestion: &Ingestion, unit: &Unit) -> String {
|
||||||
if let Some(custom_unit) = custom_unit {
|
if let Unit::Custom { id: _id, unit } = unit {
|
||||||
format!("{:?} ({})", ingestion.roa, custom_unit.name)
|
format!("{:?} ({})", ingestion.roa, &unit.as_ref().unwrap().name)
|
||||||
} else {
|
} else {
|
||||||
format!("{:?}", ingestion.roa)
|
format!("{:?}", ingestion.roa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use journal::types::CustomUnit;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_unknown_dose() {
|
||||||
|
let result = format_ingestion_dose(None, &Unit::Simple("mg".to_string()));
|
||||||
|
assert_eq!(result, "Unknown mg");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_unknown_dose_custom_unit() {
|
||||||
|
let result = format_ingestion_dose(
|
||||||
|
None,
|
||||||
|
&Unit::Custom {
|
||||||
|
id: 0,
|
||||||
|
unit: Some(CustomUnit {
|
||||||
|
original_unit: "mg".to_string(),
|
||||||
|
..CustomUnit::default()
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(result, "Unknown mg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,4 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::{Debug, Display};
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
/// Some of the fields are renamed to make more clear what it is
|
mod tests;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
pub enum AdministrationRoute {
|
pub enum AdministrationRoute {
|
||||||
Oral,
|
Oral,
|
||||||
|
@ -20,9 +19,27 @@ pub enum AdministrationRoute {
|
||||||
Inhaled,
|
Inhaled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for AdministrationRoute {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Oral
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for AdministrationRoute {
|
impl Display for AdministrationRoute {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{:?}", self)
|
match *self {
|
||||||
|
Self::Oral => f.write_str("Oral"),
|
||||||
|
Self::Sublingual => f.write_str("Sublingual"),
|
||||||
|
Self::Buccal => f.write_str("Buccal"),
|
||||||
|
Self::Insufflated => f.write_str("Insufflated"),
|
||||||
|
Self::Rectal => f.write_str("Rectal"),
|
||||||
|
Self::Transdermal => f.write_str("Transdermal"),
|
||||||
|
Self::Subcutaneous => f.write_str("Subcutaneous"),
|
||||||
|
Self::Intramuscular => f.write_str("Intramuscular"),
|
||||||
|
Self::Intravenous => f.write_str("Intravenous"),
|
||||||
|
Self::Smoked => f.write_str("Smoked"),
|
||||||
|
Self::Inhaled => f.write_str("Inhaled"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +102,7 @@ pub struct CustomUnit {
|
||||||
#[serde(rename = "creationDate")]
|
#[serde(rename = "creationDate")]
|
||||||
pub creation_time: u64,
|
pub creation_time: u64,
|
||||||
pub administration_route: AdministrationRoute,
|
pub administration_route: AdministrationRoute,
|
||||||
pub dose: f64,
|
pub dose: Option<f64>,
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
pub original_unit: String,
|
pub original_unit: String,
|
||||||
pub is_estimate: bool,
|
pub is_estimate: bool,
|
||||||
|
|
24
psychonaut_journal_types/src/tests.rs
Normal file
24
psychonaut_journal_types/src/tests.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#[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