update
This commit is contained in:
parent
4b7244e4b3
commit
e034d2387b
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -279,9 +279,18 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
checksum = "7a73e9fe3c49d7afb2ace819fa181a287ce54a0983eda4e0eb05c22f82ffe534"
|
||||
|
||||
[[package]]
|
||||
name = "journal"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"psychonaut_journal_types",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
|
@ -373,12 +382,21 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"journal",
|
||||
"log",
|
||||
"prettytable-rs",
|
||||
"psychonaut_journal_types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psychonaut_journal_types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
|
@ -433,9 +451,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.132"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
|
30
Cargo.toml
30
Cargo.toml
|
@ -1,24 +1,8 @@
|
|||
[package]
|
||||
name = "psychonaut_journal_cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
[[bin]]
|
||||
name = "journal-cli"
|
||||
path = "journal_cli/src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "journal"
|
||||
path = "journal/src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
clap = { version = "4.5.21", features = ["derive", "env"] }
|
||||
log = { version = "0.4.22", features = ["std", "serde"] }
|
||||
prettytable-rs = "0.10.0"
|
||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
||||
serde_json = "1.0.132"
|
||||
#serde_with = "3.11.0"
|
||||
#string-error = "0.1.0"
|
||||
#termcolor = "1.4.1"
|
||||
#thiserror = "2.0.3"
|
||||
members = [
|
||||
"psychonaut_journal_types",
|
||||
"journal",
|
||||
"journal_cli"
|
||||
]
|
330
journal/Cargo.lock
generated
Normal file
330
journal/Cargo.lock
generated
Normal file
|
@ -0,0 +1,330 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "journal"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"psychonaut_journal_types",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psychonaut_journal_types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|
@ -6,4 +6,4 @@ edition = "2021"
|
|||
[dependencies]
|
||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
chrono-tz = { version = "0.10.0", features = ["serde"] }
|
||||
psychonaut_journal_types = { path = "../psychonaut_journal_types" }
|
|
@ -1,20 +1,4 @@
|
|||
use crate::types::{CustomUnits, CustomUnitsType, Ingestion};
|
||||
|
||||
pub fn ingestion_dose(ingestion: &Ingestion, custom_units: &CustomUnitsType) -> Option<f64> {
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
if let Some(ingestion_dose) = ingestion.dose {
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("Custom Unit could not be found");
|
||||
|
||||
Some(ingestion_dose * custom_unit.dose)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
ingestion.dose
|
||||
}
|
||||
}
|
||||
use crate::types::{CustomUnit, Estimation, IngestionDose, StandardIngestionDose};
|
||||
|
||||
fn add_standard_deviation(
|
||||
expectation_x: f64,
|
||||
|
@ -41,69 +25,48 @@ fn add_standard_deviation(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ingestion_contains_estimate(ingestion: &Ingestion, custom_units: &CustomUnitsType) -> bool {
|
||||
if ingestion.is_estimate {
|
||||
return true;
|
||||
}
|
||||
pub fn canonical_dose(dose: &IngestionDose, custom_unit: Option<&CustomUnit>) -> IngestionDose {
|
||||
if let IngestionDose::Custom(dose) = dose {
|
||||
let custom_unit = custom_unit.expect("custom unit not provided when dose is type custom");
|
||||
let custom_unit_dose = &custom_unit.dose;
|
||||
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("Custom Unit could not be found");
|
||||
|
||||
custom_unit.is_estimate
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ingestion_standard_deviation(
|
||||
ingestion: &Ingestion,
|
||||
custom_units: &CustomUnitsType,
|
||||
) -> Option<f64> {
|
||||
if ingestion.dose.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !ingestion_contains_estimate(ingestion, custom_units) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("Custom Unit could not be found");
|
||||
|
||||
if custom_unit.estimate_standard_deviation.is_none() {
|
||||
return ingestion.estimate_standard_deviation;
|
||||
let estimation = match (&dose.estimation, &custom_unit_dose.estimation) {
|
||||
(
|
||||
&Estimation::StandardDeviation(dose_standard_deviation),
|
||||
&Estimation::StandardDeviation(custom_unit_standard_deviation),
|
||||
) => {
|
||||
let result = add_standard_deviation(
|
||||
dose.dose,
|
||||
dose_standard_deviation,
|
||||
custom_unit_dose.dose,
|
||||
custom_unit_standard_deviation,
|
||||
);
|
||||
if let Some(result) = result {
|
||||
Estimation::StandardDeviation(result)
|
||||
} else {
|
||||
Estimation::Estimate
|
||||
}
|
||||
}
|
||||
(&Estimation::StandardDeviation(dose_standard_deviation), _) => {
|
||||
Estimation::StandardDeviation(dose_standard_deviation)
|
||||
}
|
||||
(_, &Estimation::StandardDeviation(custom_unit_standard_deviation)) => {
|
||||
Estimation::StandardDeviation(custom_unit_standard_deviation)
|
||||
}
|
||||
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
||||
_ => Estimation::Estimate,
|
||||
};
|
||||
|
||||
if ingestion.estimate_standard_deviation.is_none() {
|
||||
return custom_unit.estimate_standard_deviation;
|
||||
}
|
||||
|
||||
return add_standard_deviation(
|
||||
ingestion.dose.unwrap(),
|
||||
ingestion.estimate_standard_deviation.unwrap(),
|
||||
custom_unit.dose,
|
||||
custom_unit.estimate_standard_deviation.unwrap(),
|
||||
);
|
||||
IngestionDose::Standard(StandardIngestionDose {
|
||||
dose: dose.dose * custom_unit_dose.dose,
|
||||
unit: custom_unit.original_unit.clone(),
|
||||
estimation,
|
||||
})
|
||||
} else {
|
||||
return ingestion.estimate_standard_deviation;
|
||||
dose.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ingestion_unit(
|
||||
ingestion: &Ingestion,
|
||||
custom_units: &CustomUnitsType,
|
||||
) -> String {
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("Custom Unit could not be found");
|
||||
|
||||
custom_unit.original_unit.clone()
|
||||
} else {
|
||||
ingestion.unit.clone()
|
||||
}
|
||||
pub fn canonical_unit(dose: &IngestionDose, custom_unit: Option<&CustomUnit>) -> String {
|
||||
canonical_dose(dose, custom_unit).unit()
|
||||
}
|
|
@ -1,95 +1,177 @@
|
|||
use chrono::serde::ts_milliseconds;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Display;
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum AdministrationRoute {
|
||||
Oral,
|
||||
Sublingual,
|
||||
Buccal,
|
||||
Insufflated,
|
||||
Rectal,
|
||||
Transdermal,
|
||||
Subcutaneous,
|
||||
Intramuscular,
|
||||
Intravenous,
|
||||
Smoked,
|
||||
Inhaled,
|
||||
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Estimation {
|
||||
Precise,
|
||||
Estimate,
|
||||
StandardDeviation(f64),
|
||||
}
|
||||
|
||||
impl Display for AdministrationRoute {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
impl Estimation {
|
||||
pub fn is_precise(&self) -> bool {
|
||||
matches!(self, Estimation::Precise)
|
||||
}
|
||||
pub fn is_estimate(&self) -> bool {
|
||||
!matches!(self, Estimation::Precise)
|
||||
}
|
||||
pub fn is_standard_deviation(&self) -> bool {
|
||||
matches!(self, Estimation::StandardDeviation(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnknownIngestionDose {
|
||||
pub unit: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandardIngestionDose {
|
||||
pub dose: f64,
|
||||
pub unit: String,
|
||||
pub estimation: Estimation,
|
||||
}
|
||||
|
||||
impl StandardIngestionDose {
|
||||
pub fn is_estimate(&self) -> bool {
|
||||
self.estimation.is_estimate()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomIngestionDose {
|
||||
pub dose: f64,
|
||||
pub unit: String,
|
||||
pub original_unit: String,
|
||||
pub estimation: Estimation,
|
||||
pub custom_unit_id: i64,
|
||||
}
|
||||
|
||||
impl CustomIngestionDose {
|
||||
pub fn is_estimate(&self) -> bool {
|
||||
self.estimation.is_estimate()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IngestionDose {
|
||||
Unknown(UnknownIngestionDose),
|
||||
Standard(StandardIngestionDose),
|
||||
Custom(CustomIngestionDose),
|
||||
}
|
||||
|
||||
impl IngestionDose {
|
||||
pub fn is_estimate(&self) -> bool {
|
||||
match self {
|
||||
IngestionDose::Unknown(_) => false,
|
||||
IngestionDose::Standard(dose) => dose.is_estimate(),
|
||||
IngestionDose::Custom(dose) => dose.is_estimate(),
|
||||
}
|
||||
}
|
||||
pub fn unit(&self) -> String {
|
||||
match self {
|
||||
IngestionDose::Unknown(dose) => dose.unit.clone(),
|
||||
IngestionDose::Standard(dose) => dose.unit.clone(),
|
||||
IngestionDose::Custom(dose) => dose.unit.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Consumer {
|
||||
Default,
|
||||
Named(String),
|
||||
}
|
||||
|
||||
impl FromStr for Consumer {
|
||||
type Err = core::convert::Infallible;
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Consumer::Default => f.write_str("default"),
|
||||
Consumer::Named(name) => f.write_str(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ingestion {
|
||||
pub substance_name: String,
|
||||
#[serde(with = "ts_milliseconds", rename = "time")]
|
||||
pub ingestion_time: DateTime<Utc>,
|
||||
#[serde(with = "ts_milliseconds", rename = "creationDate")]
|
||||
pub creation_time: DateTime<Utc>,
|
||||
pub dose: Option<f64>,
|
||||
#[serde(rename = "units")]
|
||||
pub unit: String,
|
||||
#[serde(rename = "isDoseAnEstimate")]
|
||||
pub is_estimate: bool,
|
||||
#[serde(rename = "estimatedDoseStandardDeviation")]
|
||||
pub estimate_standard_deviation: Option<f64>,
|
||||
pub custom_unit_id: Option<i64>,
|
||||
#[serde(rename = "administrationRoute")]
|
||||
pub dose: IngestionDose,
|
||||
pub roa: AdministrationRoute,
|
||||
pub consumer_name: Option<String>,
|
||||
pub consumer: Consumer,
|
||||
pub notes: String,
|
||||
pub stomach_fullness: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomSubstance {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub units: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Experience {
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
#[serde(with = "ts_milliseconds", rename = "creationDate")]
|
||||
pub creation_time: DateTime<Utc>,
|
||||
#[serde(with = "ts_milliseconds", rename = "sortDate")]
|
||||
pub modified_time: DateTime<Utc>,
|
||||
pub ingestions: Vec<Ingestion>,
|
||||
}
|
||||
|
||||
pub type ExperiencesType = Vec<Experience>;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomUnit {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub substance_name: String,
|
||||
|
||||
pub trait Experiences {
|
||||
fn filter_by_title(&self, title: &String) -> Vec<Experience>;
|
||||
fn get_by_title(&self, title: &String) -> Option<Experience>;
|
||||
pub administration_route: AdministrationRoute,
|
||||
pub dose: StandardIngestionDose,
|
||||
pub original_unit: String,
|
||||
|
||||
pub creation_time: DateTime<Utc>,
|
||||
pub is_archived: bool,
|
||||
}
|
||||
|
||||
impl Experiences for ExperiencesType {
|
||||
fn filter_by_title(&self, title: &String) -> Vec<Experience> {
|
||||
self.iter()
|
||||
.filter_map(|experience| {
|
||||
if &experience.title == title {
|
||||
Some(experience.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Journal {
|
||||
pub experiences: Vec<Experience>,
|
||||
//pub substance_colours: HashMap<String, String>,
|
||||
//pub custom_substances: HashMap<String, CustomSubstance>,
|
||||
pub custom_units: HashMap<i64, CustomUnit>,
|
||||
}
|
||||
|
||||
impl Journal {
|
||||
pub fn get_custom_unit(&self, id: i64) -> Option<CustomUnit> {
|
||||
self.custom_units.get(&id).cloned()
|
||||
}
|
||||
fn get_by_title(&self, title: &String) -> Option<Experience> {
|
||||
for experience in self.iter() {
|
||||
|
||||
pub fn maybe_get_custom_unit_for(&self, ingestion: &Ingestion) -> Option<CustomUnit> {
|
||||
match &ingestion.dose {
|
||||
IngestionDose::Custom(dose) => self.get_custom_unit(dose.custom_unit_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_experience_by_title(&self, title: &String) -> Option<Experience> {
|
||||
for experience in self.experiences.iter() {
|
||||
if &experience.title == title {
|
||||
return Some(experience.clone());
|
||||
}
|
||||
|
@ -97,56 +179,116 @@ impl Experiences for ExperiencesType {
|
|||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SubstanceCompanion {
|
||||
pub substance_name: String,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CustomUnit {
|
||||
pub id: i64,
|
||||
pub substance_name: String,
|
||||
pub name: String,
|
||||
#[serde(with = "ts_milliseconds", rename = "creationDate")]
|
||||
pub creation_time: DateTime<Utc>,
|
||||
pub administration_route: AdministrationRoute,
|
||||
pub dose: f64,
|
||||
pub unit: String,
|
||||
pub original_unit: String,
|
||||
pub is_estimate: bool,
|
||||
#[serde(rename = "estimatedDoseStandardDeviation")]
|
||||
pub estimate_standard_deviation: Option<f64>,
|
||||
pub is_archived: bool,
|
||||
}
|
||||
|
||||
pub type CustomUnitsType = Vec<CustomUnit>;
|
||||
|
||||
pub trait CustomUnits {
|
||||
fn get_by_id(&self, id: i64) -> Option<CustomUnit>;
|
||||
}
|
||||
|
||||
impl CustomUnits for CustomUnitsType {
|
||||
fn get_by_id(&self, id: i64) -> Option<CustomUnit> {
|
||||
for custom_unit in self.iter() {
|
||||
if custom_unit.id == id {
|
||||
return Some(custom_unit.clone());
|
||||
}
|
||||
pub fn import(data: psychonaut_journal_types::ExportData) -> Self {
|
||||
fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
||||
Utc.timestamp_millis_opt(time as i64).unwrap()
|
||||
}
|
||||
|
||||
None
|
||||
let mut journal = Journal::default();
|
||||
|
||||
for custom_unit in data.custom_units.into_iter() {
|
||||
journal.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: StandardIngestionDose {
|
||||
dose: custom_unit.dose,
|
||||
unit: custom_unit.unit,
|
||||
estimation: if custom_unit.is_estimate {
|
||||
if let Some(standard_deviation) =
|
||||
custom_unit.estimate_standard_deviation
|
||||
{
|
||||
Estimation::StandardDeviation(standard_deviation)
|
||||
} else {
|
||||
Estimation::Estimate
|
||||
}
|
||||
} else {
|
||||
Estimation::Precise
|
||||
},
|
||||
},
|
||||
|
||||
original_unit: custom_unit.original_unit,
|
||||
|
||||
creation_time: from_unix_millis(custom_unit.creation_time),
|
||||
is_archived: custom_unit.is_archived,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
for experience in data.experiences.into_iter() {
|
||||
let mut ingestions: Vec<Ingestion> = Vec::new();
|
||||
|
||||
for ingestion in experience.ingestions.into_iter() {
|
||||
fn ingestion_estimation(
|
||||
ingestion: &psychonaut_journal_types::Ingestion,
|
||||
) -> Estimation {
|
||||
if !ingestion.is_estimate {
|
||||
Estimation::Precise
|
||||
} else if let Some(standard_deviation) = ingestion.estimate_standard_deviation {
|
||||
Estimation::StandardDeviation(standard_deviation)
|
||||
} else {
|
||||
Estimation::Estimate
|
||||
}
|
||||
}
|
||||
|
||||
let estimation = ingestion_estimation(&ingestion);
|
||||
|
||||
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: {
|
||||
if let Some(dose) = ingestion.dose {
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
IngestionDose::Custom(CustomIngestionDose {
|
||||
dose,
|
||||
unit: ingestion.unit.clone(),
|
||||
original_unit: journal
|
||||
.custom_units
|
||||
.get(&custom_unit_id)
|
||||
.expect("custom unit not found")
|
||||
.original_unit
|
||||
.clone(),
|
||||
estimation,
|
||||
custom_unit_id,
|
||||
})
|
||||
} else {
|
||||
IngestionDose::Standard(StandardIngestionDose {
|
||||
dose,
|
||||
unit: ingestion.unit,
|
||||
estimation,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
IngestionDose::Unknown(UnknownIngestionDose {
|
||||
unit: 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,
|
||||
})
|
||||
}
|
||||
|
||||
journal.experiences.push(Experience {
|
||||
title: experience.title,
|
||||
text: experience.text,
|
||||
creation_time: from_unix_millis(experience.creation_time),
|
||||
modified_time: from_unix_millis(experience.modified_time),
|
||||
ingestions,
|
||||
});
|
||||
}
|
||||
|
||||
journal
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExportData {
|
||||
pub experiences: ExperiencesType,
|
||||
pub substance_companions: Vec<SubstanceCompanion>,
|
||||
pub custom_substances: Vec<CustomSubstance>,
|
||||
pub custom_units: CustomUnitsType,
|
||||
}
|
||||
|
|
23
journal_cli/Cargo.toml
Normal file
23
journal_cli/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "psychonaut_journal_cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "journal-cli"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
journal = { path = "../journal" }
|
||||
psychonaut_journal_types = { path = "../psychonaut_journal_types" }
|
||||
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
clap = { version = "4.5.21", features = ["derive", "env"] }
|
||||
log = { version = "0.4.22", features = ["std", "serde"] }
|
||||
prettytable-rs = "0.10.0"
|
||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
||||
serde_json = "1.0.132"
|
||||
#serde_with = "3.11.0"
|
||||
#string-error = "0.1.0"
|
||||
#termcolor = "1.4.1"
|
||||
#thiserror = "2.0.3"
|
|
@ -3,7 +3,7 @@ use clap::{Parser, Subcommand};
|
|||
#[derive(Debug, Clone, Subcommand)]
|
||||
#[clap(rename_all = "camelCase")]
|
||||
pub enum Commands {
|
||||
PrintExperience(crate::commands::print_experience::PrintExperienceArgs)
|
||||
PrintExperience(crate::commands::print_experience::PrintExperienceArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
|
|
@ -1,44 +1,62 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use journal::types::Consumer;
|
||||
|
||||
use crate::args::Args;
|
||||
use crate::utils::{
|
||||
format_ingestion_dose, format_ingestion_roa, format_ingestion_time, load_export_data,
|
||||
};
|
||||
|
||||
use journal;
|
||||
|
||||
use journal::types::Experiences;
|
||||
use crate::display::print_ingestion_log;
|
||||
use crate::formatting::format_experience_title;
|
||||
use crate::utils::load_journal;
|
||||
|
||||
#[derive(Debug, Clone, clap::Args)]
|
||||
pub struct PrintExperienceArgs {
|
||||
pub experience_title: String,
|
||||
#[clap(long, env = "EXPORT_FILE")]
|
||||
pub export_file: String,
|
||||
#[clap(long)]
|
||||
pub substance_filter: Option<Vec<String>>,
|
||||
#[clap(long, value_delimiter = ',')]
|
||||
pub consumer_filter: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub fn parse_consumer_filter(consumer_filter: Option<Vec<String>>) -> Option<Vec<Consumer>> {
|
||||
match consumer_filter {
|
||||
Some(consumer_filter) => {
|
||||
let mut consumers: Vec<Consumer> = Vec::new();
|
||||
for consumer in consumer_filter.into_iter() {
|
||||
let mut consumer_name = consumer.as_str();
|
||||
if consumer_name.is_empty() {
|
||||
consumer_name = "default";
|
||||
}
|
||||
|
||||
consumers.push(Consumer::from_str(consumer_name).unwrap());
|
||||
}
|
||||
Some(consumers)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_experience(
|
||||
_global_args: &Args,
|
||||
args: &PrintExperienceArgs,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let export_data = load_export_data(&args.export_file).expect("could not load export data");
|
||||
let journal = load_journal(&args.export_file).expect("could not load export data");
|
||||
|
||||
let experience = export_data
|
||||
.experiences
|
||||
.get_by_title(&args.experience_title)
|
||||
let experience = journal
|
||||
.first_experience_by_title(&args.experience_title)
|
||||
.expect("could not find experience");
|
||||
|
||||
for ingestion in experience.ingestions.iter() {
|
||||
println!(
|
||||
"{}|{}|{}|{}|{}",
|
||||
ingestion.substance_name,
|
||||
format_ingestion_dose(&ingestion, &export_data.custom_units),
|
||||
format_ingestion_roa(&ingestion, &export_data.custom_units),
|
||||
ingestion
|
||||
.consumer_name
|
||||
.clone()
|
||||
.or(Some("default".to_string()))
|
||||
.unwrap(),
|
||||
format_ingestion_time(&ingestion)
|
||||
)
|
||||
}
|
||||
println!("{}", format_experience_title(&experience));
|
||||
|
||||
let substance_filter = args.substance_filter.clone();
|
||||
let consumer_filter = parse_consumer_filter(args.consumer_filter.clone());
|
||||
|
||||
print_ingestion_log(
|
||||
&journal,
|
||||
&experience,
|
||||
substance_filter.as_ref(),
|
||||
consumer_filter.as_ref(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
35
journal_cli/src/display.rs
Normal file
35
journal_cli/src/display.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use journal::types::{Consumer, Experience, Journal};
|
||||
|
||||
use crate::formatting::{format_ingestion_dose, format_ingestion_roa, format_ingestion_time};
|
||||
|
||||
pub fn print_ingestion_log(
|
||||
journal: &Journal,
|
||||
experience: &Experience,
|
||||
substance_filter: Option<&Vec<String>>,
|
||||
consumer_filter: Option<&Vec<Consumer>>,
|
||||
) {
|
||||
for ingestion in experience.ingestions.iter() {
|
||||
if let Some(substance_filter) = substance_filter {
|
||||
if !substance_filter.contains(&ingestion.substance_name) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(consumer_filter) = consumer_filter {
|
||||
if !consumer_filter.contains(&ingestion.consumer) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let custom_unit = journal.maybe_get_custom_unit_for(ingestion);
|
||||
|
||||
println!(
|
||||
"{}|{}|{}|{}|{}",
|
||||
ingestion.substance_name,
|
||||
format_ingestion_dose(&ingestion.dose, custom_unit.as_ref()),
|
||||
format_ingestion_roa(ingestion, custom_unit.as_ref()),
|
||||
ingestion.consumer,
|
||||
format_ingestion_time(ingestion)
|
||||
)
|
||||
}
|
||||
}
|
75
journal_cli/src/formatting.rs
Normal file
75
journal_cli/src/formatting.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use journal::{
|
||||
helpers::canonical_dose,
|
||||
types::{CustomUnit, Experience, Ingestion, IngestionDose, StandardIngestionDose},
|
||||
};
|
||||
|
||||
pub fn format_experience_title(experience: &Experience) -> String {
|
||||
format!("{}: {}", experience.title, experience.creation_time)
|
||||
}
|
||||
|
||||
pub fn format_ingestion_dose(dose: &IngestionDose, custom_unit: Option<&CustomUnit>) -> String {
|
||||
match dose {
|
||||
IngestionDose::Unknown(dose) => format!("Unknown {}", dose.unit),
|
||||
IngestionDose::Standard(dose) => {
|
||||
let is_estimate = match dose.estimation {
|
||||
journal::types::Estimation::Precise => false,
|
||||
journal::types::Estimation::Estimate
|
||||
| journal::types::Estimation::StandardDeviation(_) => true,
|
||||
};
|
||||
|
||||
let estimate = if is_estimate { "~" } else { "" };
|
||||
let standard_deviation =
|
||||
if let journal::types::Estimation::StandardDeviation(standard_deviation) =
|
||||
dose.estimation
|
||||
{
|
||||
format!("±{}", (standard_deviation * 100.0).round() / 100.0)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let dose_value = (dose.dose * 100.0).round() / 100.0;
|
||||
let unit = dose.unit.clone();
|
||||
|
||||
format!("{estimate}{dose_value}{standard_deviation} {unit}")
|
||||
}
|
||||
IngestionDose::Custom(dose) => {
|
||||
let custom_unit: &CustomUnit = custom_unit.expect("custom unit required for dose type");
|
||||
|
||||
let canonical_dose =
|
||||
canonical_dose(&IngestionDose::Custom(dose.clone()), Some(custom_unit));
|
||||
|
||||
let canonical_dose = format_ingestion_dose(&canonical_dose, None);
|
||||
|
||||
let custom_unit_dose_per = format_ingestion_dose(
|
||||
&IngestionDose::Standard(StandardIngestionDose {
|
||||
dose: custom_unit.dose.dose,
|
||||
unit: custom_unit.original_unit.clone(),
|
||||
estimation: custom_unit.dose.estimation.clone(),
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
let custom_unit_dose = format_ingestion_dose(
|
||||
&IngestionDose::Standard(StandardIngestionDose {
|
||||
dose: dose.dose,
|
||||
unit: custom_unit.dose.unit.clone(),
|
||||
estimation: custom_unit.dose.estimation.clone(),
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
format!("{canonical_dose} ({custom_unit_dose_per} * {custom_unit_dose})")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_ingestion_time(ingestion: &Ingestion) -> String {
|
||||
ingestion.ingestion_time.format("%a %I:%M %p").to_string()
|
||||
}
|
||||
|
||||
pub fn format_ingestion_roa(ingestion: &Ingestion, custom_unit: Option<&CustomUnit>) -> String {
|
||||
if let Some(custom_unit) = custom_unit {
|
||||
format!("{:?} ({})", ingestion.roa, custom_unit.name)
|
||||
} else {
|
||||
format!("{:?}", ingestion.roa)
|
||||
}
|
||||
}
|
|
@ -1,21 +1,25 @@
|
|||
use clap::Parser;
|
||||
use commands::print_experience::print_experience;
|
||||
|
||||
pub mod args;
|
||||
pub mod commands;
|
||||
pub mod display;
|
||||
pub mod formatting;
|
||||
pub mod utils;
|
||||
|
||||
use commands::print_experience::print_experience;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = args::Args::parse();
|
||||
|
||||
let command = args.command.to_owned();
|
||||
let command = args.command.to_owned();
|
||||
|
||||
//println!("{:#?}", args);
|
||||
println!("{:#?}", args);
|
||||
|
||||
match command {
|
||||
args::Commands::PrintExperience(print_experience_args) =>
|
||||
print_experience(&args, &print_experience_args)?,
|
||||
}
|
||||
match command {
|
||||
args::Commands::PrintExperience(print_experience_args) => {
|
||||
print_experience(&args, &print_experience_args)?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,137 +1,14 @@
|
|||
use journal::{
|
||||
helpers::{
|
||||
ingestion_contains_estimate, ingestion_dose, ingestion_standard_deviation, ingestion_unit,
|
||||
},
|
||||
types::{CustomUnits, CustomUnitsType, Experience, ExportData, Ingestion},
|
||||
};
|
||||
use journal::types::Journal;
|
||||
use psychonaut_journal_types::ExportData;
|
||||
use std::fs::File;
|
||||
|
||||
pub fn load_export_data(filename: &String) -> Result<ExportData, Box<dyn std::error::Error>> {
|
||||
pub fn load_journal(filename: &String) -> Result<Journal, Box<dyn std::error::Error>> {
|
||||
let file = File::open(filename)?;
|
||||
|
||||
let export_data: ExportData = serde_json::from_reader(file)?;
|
||||
|
||||
// export_data
|
||||
// .experiences
|
||||
// .sort_by(|a, b| a.modified_time.cmp(&b.modified_time));
|
||||
let journal = Journal::import(export_data);
|
||||
|
||||
//for experience in export_data.experiences.iter_mut() {
|
||||
// experience
|
||||
// .ingestions
|
||||
// .sort_by(|a, b| a.ingestion_time.cmp(&b.ingestion_time));
|
||||
//}
|
||||
|
||||
Ok(export_data)
|
||||
Ok(journal)
|
||||
}
|
||||
|
||||
pub fn format_experience_title(experience: &Experience) -> String {
|
||||
format!("{}: {}", experience.title, experience.creation_time)
|
||||
}
|
||||
|
||||
pub fn format_dose(
|
||||
dose: Option<f64>,
|
||||
unit: &String,
|
||||
estimate: bool,
|
||||
standard_deviation: Option<f64>,
|
||||
) -> String {
|
||||
if let Some(dose) = dose {
|
||||
let estimate = if estimate { "~" } else { "" };
|
||||
let standard_deviation = if let Some(standard_deviation) = standard_deviation {
|
||||
format!("±{}", (standard_deviation * 100.0).round() / 100.0)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let dose = (dose * 100.0).round() / 100.0;
|
||||
|
||||
format!("{estimate}{dose}{standard_deviation} {unit}")
|
||||
} else {
|
||||
format!("Unknown {unit}")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_ingestion_dose(ingestion: &Ingestion, custom_units: &CustomUnitsType) -> String {
|
||||
let dose = ingestion_dose(ingestion, custom_units);
|
||||
let unit = ingestion_unit(ingestion, custom_units);
|
||||
let standard_deviation = ingestion_standard_deviation(ingestion, custom_units);
|
||||
|
||||
if let Some(dose) = dose {
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
let estimate = if ingestion_contains_estimate(&ingestion, &custom_units) {
|
||||
"~"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("custom unit not found");
|
||||
|
||||
let canonical_dose =
|
||||
format_dose(Some(dose), &unit, ingestion.is_estimate, standard_deviation);
|
||||
|
||||
let custom_unit_dose_per = format_dose(
|
||||
Some(custom_unit.dose),
|
||||
&custom_unit.original_unit,
|
||||
custom_unit.is_estimate,
|
||||
custom_unit.estimate_standard_deviation,
|
||||
);
|
||||
|
||||
let custom_unit_dose = format_dose(
|
||||
ingestion.dose,
|
||||
&custom_unit.unit,
|
||||
ingestion.is_estimate,
|
||||
ingestion.estimate_standard_deviation,
|
||||
);
|
||||
|
||||
format!("{estimate}{canonical_dose} ({custom_unit_dose_per} * {custom_unit_dose})")
|
||||
} else {
|
||||
format_dose(Some(dose), &unit, ingestion.is_estimate, standard_deviation)
|
||||
}
|
||||
} else {
|
||||
"Unknown".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_ingestion_time(ingestion: &Ingestion) -> String {
|
||||
ingestion.ingestion_time.format("%a %I:%M %p").to_string()
|
||||
}
|
||||
|
||||
pub fn format_ingestion_roa(ingestion: &Ingestion, custom_units: &CustomUnitsType) -> String {
|
||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
||||
let custom_unit = custom_units
|
||||
.get_by_id(custom_unit_id)
|
||||
.expect("custom unit not found");
|
||||
|
||||
format!("{:?} ({})", ingestion.roa, custom_unit.name)
|
||||
} else {
|
||||
format!("{:?}", ingestion.roa)
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
def formatIngestionROA($customUnits; $substitutions):
|
||||
. as $ingestion |
|
||||
$ingestion.administrationRoute as $roa |
|
||||
|
||||
|
||||
$ingestion.customUnitId as $customUnitId |
|
||||
|
||||
if
|
||||
$customUnitId == null
|
||||
then
|
||||
$roaText
|
||||
else
|
||||
$customUnits | map(select(.id == $customUnitId))[0] as $customUnit |
|
||||
"\($roaText) (\($customUnit.name))"
|
||||
end;
|
||||
|
||||
def formatIngestionROA($customUnits): formatIngestionROA($customUnits; {});
|
||||
|
||||
def formatIngestionInfo:
|
||||
. as $ingestionInfo |
|
||||
formatDose(.dose; .unit; .isEstimate; .standardDeviation);
|
||||
|
||||
*/
|
||||
|
|
65
psychonaut_journal_types/Cargo.lock
generated
Normal file
65
psychonaut_journal_types/Cargo.lock
generated
Normal file
|
@ -0,0 +1,65 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psychonaut_journal_types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "journal"
|
||||
name = "psychonaut_journal_types"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
|
|
@ -63,9 +63,9 @@ pub struct Experience {
|
|||
pub title: String,
|
||||
pub text: String,
|
||||
#[serde(rename = "creationDate")]
|
||||
pub creation_time: DateTime<Utc>,
|
||||
pub creation_time: u64,
|
||||
#[serde(rename = "sortDate")]
|
||||
pub modified_time: DateTime<Utc>,
|
||||
pub modified_time: u64,
|
||||
pub ingestions: Vec<Ingestion>,
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ pub struct CustomUnit {
|
|||
pub substance_name: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "creationDate")]
|
||||
pub creation_time: DateTime<Utc>,
|
||||
pub creation_time: u64,
|
||||
pub administration_route: AdministrationRoute,
|
||||
pub dose: f64,
|
||||
pub unit: String,
|
||||
|
@ -97,8 +97,8 @@ pub struct CustomUnit {
|
|||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExportData {
|
||||
pub experiences: Vec<Experiences>,
|
||||
pub experiences: Vec<Experience>,
|
||||
pub substance_companions: Vec<SubstanceCompanion>,
|
||||
pub custom_substances: Vec<CustomSubstance>,
|
||||
pub custom_units: Vec<CustomUnits>,
|
||||
pub custom_units: Vec<CustomUnit>,
|
||||
}
|
Loading…
Reference in a new issue