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]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
|
@ -373,12 +382,21 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"journal",
|
||||||
"log",
|
"log",
|
||||||
"prettytable-rs",
|
"prettytable-rs",
|
||||||
|
"psychonaut_journal_types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psychonaut_journal_types"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
|
@ -433,9 +451,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.132"
|
version = "1.0.133"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
30
Cargo.toml
30
Cargo.toml
|
@ -1,24 +1,8 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "psychonaut_journal_cli"
|
resolver = "2"
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
members = [
|
||||||
name = "journal-cli"
|
"psychonaut_journal_types",
|
||||||
path = "journal_cli/src/main.rs"
|
"journal",
|
||||||
|
"journal_cli"
|
||||||
[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"
|
|
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]
|
[dependencies]
|
||||||
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
serde = { version = "1.0.215", features = ["std", "derive", "serde_derive"] }
|
||||||
chrono = { version = "0.4.38", features = ["serde"] }
|
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};
|
use crate::types::{CustomUnit, Estimation, IngestionDose, StandardIngestionDose};
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_standard_deviation(
|
fn add_standard_deviation(
|
||||||
expectation_x: f64,
|
expectation_x: f64,
|
||||||
|
@ -41,69 +25,48 @@ fn add_standard_deviation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ingestion_contains_estimate(ingestion: &Ingestion, custom_units: &CustomUnitsType) -> bool {
|
pub fn canonical_dose(dose: &IngestionDose, custom_unit: Option<&CustomUnit>) -> IngestionDose {
|
||||||
if ingestion.is_estimate {
|
if let IngestionDose::Custom(dose) = dose {
|
||||||
return true;
|
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 estimation = match (&dose.estimation, &custom_unit_dose.estimation) {
|
||||||
let custom_unit = custom_units
|
(
|
||||||
.get_by_id(custom_unit_id)
|
&Estimation::StandardDeviation(dose_standard_deviation),
|
||||||
.expect("Custom Unit could not be found");
|
&Estimation::StandardDeviation(custom_unit_standard_deviation),
|
||||||
|
) => {
|
||||||
custom_unit.is_estimate
|
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 {
|
} else {
|
||||||
false
|
Estimation::Estimate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(&Estimation::StandardDeviation(dose_standard_deviation), _) => {
|
||||||
pub fn ingestion_standard_deviation(
|
Estimation::StandardDeviation(dose_standard_deviation)
|
||||||
ingestion: &Ingestion,
|
|
||||||
custom_units: &CustomUnitsType,
|
|
||||||
) -> Option<f64> {
|
|
||||||
if ingestion.dose.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
(_, &Estimation::StandardDeviation(custom_unit_standard_deviation)) => {
|
||||||
if !ingestion_contains_estimate(ingestion, custom_units) {
|
Estimation::StandardDeviation(custom_unit_standard_deviation)
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
(Estimation::Precise, Estimation::Precise) => Estimation::Precise,
|
||||||
if let Some(custom_unit_id) = ingestion.custom_unit_id {
|
_ => Estimation::Estimate,
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ingestion.estimate_standard_deviation.is_none() {
|
IngestionDose::Standard(StandardIngestionDose {
|
||||||
return custom_unit.estimate_standard_deviation;
|
dose: dose.dose * custom_unit_dose.dose,
|
||||||
}
|
unit: custom_unit.original_unit.clone(),
|
||||||
|
estimation,
|
||||||
return add_standard_deviation(
|
})
|
||||||
ingestion.dose.unwrap(),
|
|
||||||
ingestion.estimate_standard_deviation.unwrap(),
|
|
||||||
custom_unit.dose,
|
|
||||||
custom_unit.estimate_standard_deviation.unwrap(),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return ingestion.estimate_standard_deviation;
|
dose.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ingestion_unit(
|
pub fn canonical_unit(dose: &IngestionDose, custom_unit: Option<&CustomUnit>) -> String {
|
||||||
ingestion: &Ingestion,
|
canonical_dose(dose, custom_unit).unit()
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,95 +1,177 @@
|
||||||
use chrono::serde::ts_milliseconds;
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use chrono::{DateTime, Utc};
|
use std::collections::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use std::fmt::{Debug, Display};
|
||||||
use std::fmt::Debug;
|
use std::str::FromStr;
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
|
||||||
pub enum AdministrationRoute {
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
Oral,
|
pub enum Estimation {
|
||||||
Sublingual,
|
Precise,
|
||||||
Buccal,
|
Estimate,
|
||||||
Insufflated,
|
StandardDeviation(f64),
|
||||||
Rectal,
|
|
||||||
Transdermal,
|
|
||||||
Subcutaneous,
|
|
||||||
Intramuscular,
|
|
||||||
Intravenous,
|
|
||||||
Smoked,
|
|
||||||
Inhaled,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AdministrationRoute {
|
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(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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{:?}", self)
|
match self {
|
||||||
|
Consumer::Default => f.write_str("default"),
|
||||||
|
Consumer::Named(name) => f.write_str(name),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Ingestion {
|
pub struct Ingestion {
|
||||||
pub substance_name: String,
|
pub substance_name: String,
|
||||||
#[serde(with = "ts_milliseconds", rename = "time")]
|
|
||||||
pub ingestion_time: DateTime<Utc>,
|
pub ingestion_time: DateTime<Utc>,
|
||||||
#[serde(with = "ts_milliseconds", rename = "creationDate")]
|
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
pub dose: Option<f64>,
|
pub dose: IngestionDose,
|
||||||
#[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 roa: AdministrationRoute,
|
pub roa: AdministrationRoute,
|
||||||
pub consumer_name: Option<String>,
|
pub consumer: Consumer,
|
||||||
pub notes: String,
|
pub notes: String,
|
||||||
pub stomach_fullness: Option<String>,
|
pub stomach_fullness: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct CustomSubstance {
|
pub struct CustomSubstance {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub units: String,
|
pub units: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Experience {
|
pub struct Experience {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
#[serde(with = "ts_milliseconds", rename = "creationDate")]
|
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
#[serde(with = "ts_milliseconds", rename = "sortDate")]
|
|
||||||
pub modified_time: DateTime<Utc>,
|
pub modified_time: DateTime<Utc>,
|
||||||
pub ingestions: Vec<Ingestion>,
|
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 {
|
pub administration_route: AdministrationRoute,
|
||||||
fn filter_by_title(&self, title: &String) -> Vec<Experience>;
|
pub dose: StandardIngestionDose,
|
||||||
fn get_by_title(&self, title: &String) -> Option<Experience>;
|
pub original_unit: String,
|
||||||
|
|
||||||
|
pub creation_time: DateTime<Utc>,
|
||||||
|
pub is_archived: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Experiences for ExperiencesType {
|
#[derive(Debug, Default, Clone)]
|
||||||
fn filter_by_title(&self, title: &String) -> Vec<Experience> {
|
pub struct Journal {
|
||||||
self.iter()
|
pub experiences: Vec<Experience>,
|
||||||
.filter_map(|experience| {
|
//pub substance_colours: HashMap<String, String>,
|
||||||
if &experience.title == title {
|
//pub custom_substances: HashMap<String, CustomSubstance>,
|
||||||
Some(experience.clone())
|
pub custom_units: HashMap<i64, CustomUnit>,
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.collect()
|
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 {
|
if &experience.title == title {
|
||||||
return Some(experience.clone());
|
return Some(experience.clone());
|
||||||
}
|
}
|
||||||
|
@ -97,56 +179,116 @@ impl Experiences for ExperiencesType {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
let mut journal = Journal::default();
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SubstanceCompanion {
|
for custom_unit in data.custom_units.into_iter() {
|
||||||
pub substance_name: String,
|
journal.custom_units.insert(
|
||||||
pub color: String,
|
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,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
for experience in data.experiences.into_iter() {
|
||||||
#[serde(rename_all = "camelCase")]
|
let mut ingestions: Vec<Ingestion> = Vec::new();
|
||||||
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>;
|
for ingestion in experience.ingestions.into_iter() {
|
||||||
|
fn ingestion_estimation(
|
||||||
pub trait CustomUnits {
|
ingestion: &psychonaut_journal_types::Ingestion,
|
||||||
fn get_by_id(&self, id: i64) -> Option<CustomUnit>;
|
) -> Estimation {
|
||||||
}
|
if !ingestion.is_estimate {
|
||||||
|
Estimation::Precise
|
||||||
impl CustomUnits for CustomUnitsType {
|
} else if let Some(standard_deviation) = ingestion.estimate_standard_deviation {
|
||||||
fn get_by_id(&self, id: i64) -> Option<CustomUnit> {
|
Estimation::StandardDeviation(standard_deviation)
|
||||||
for custom_unit in self.iter() {
|
} else {
|
||||||
if custom_unit.id == id {
|
Estimation::Estimate
|
||||||
return Some(custom_unit.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
journal.experiences.push(Experience {
|
||||||
#[serde(rename_all = "camelCase")]
|
title: experience.title,
|
||||||
pub struct ExportData {
|
text: experience.text,
|
||||||
pub experiences: ExperiencesType,
|
creation_time: from_unix_millis(experience.creation_time),
|
||||||
pub substance_companions: Vec<SubstanceCompanion>,
|
modified_time: from_unix_millis(experience.modified_time),
|
||||||
pub custom_substances: Vec<CustomSubstance>,
|
ingestions,
|
||||||
pub custom_units: CustomUnitsType,
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
journal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
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)]
|
#[derive(Debug, Clone, Subcommand)]
|
||||||
#[clap(rename_all = "camelCase")]
|
#[clap(rename_all = "camelCase")]
|
||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
PrintExperience(crate::commands::print_experience::PrintExperienceArgs)
|
PrintExperience(crate::commands::print_experience::PrintExperienceArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
|
|
@ -1,44 +1,62 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use journal::types::Consumer;
|
||||||
|
|
||||||
use crate::args::Args;
|
use crate::args::Args;
|
||||||
use crate::utils::{
|
use crate::display::print_ingestion_log;
|
||||||
format_ingestion_dose, format_ingestion_roa, format_ingestion_time, load_export_data,
|
use crate::formatting::format_experience_title;
|
||||||
};
|
use crate::utils::load_journal;
|
||||||
|
|
||||||
use journal;
|
|
||||||
|
|
||||||
use journal::types::Experiences;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, clap::Args)]
|
#[derive(Debug, Clone, clap::Args)]
|
||||||
pub struct PrintExperienceArgs {
|
pub struct PrintExperienceArgs {
|
||||||
pub experience_title: String,
|
pub experience_title: String,
|
||||||
#[clap(long, env = "EXPORT_FILE")]
|
#[clap(long, env = "EXPORT_FILE")]
|
||||||
pub export_file: String,
|
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(
|
pub fn print_experience(
|
||||||
_global_args: &Args,
|
_global_args: &Args,
|
||||||
args: &PrintExperienceArgs,
|
args: &PrintExperienceArgs,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> 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
|
let experience = journal
|
||||||
.experiences
|
.first_experience_by_title(&args.experience_title)
|
||||||
.get_by_title(&args.experience_title)
|
|
||||||
.expect("could not find experience");
|
.expect("could not find experience");
|
||||||
|
|
||||||
for ingestion in experience.ingestions.iter() {
|
println!("{}", format_experience_title(&experience));
|
||||||
println!(
|
|
||||||
"{}|{}|{}|{}|{}",
|
let substance_filter = args.substance_filter.clone();
|
||||||
ingestion.substance_name,
|
let consumer_filter = parse_consumer_filter(args.consumer_filter.clone());
|
||||||
format_ingestion_dose(&ingestion, &export_data.custom_units),
|
|
||||||
format_ingestion_roa(&ingestion, &export_data.custom_units),
|
print_ingestion_log(
|
||||||
ingestion
|
&journal,
|
||||||
.consumer_name
|
&experience,
|
||||||
.clone()
|
substance_filter.as_ref(),
|
||||||
.or(Some("default".to_string()))
|
consumer_filter.as_ref(),
|
||||||
.unwrap(),
|
);
|
||||||
format_ingestion_time(&ingestion)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
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,20 +1,24 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use commands::print_experience::print_experience;
|
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
pub mod display;
|
||||||
|
pub mod formatting;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
use commands::print_experience::print_experience;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let args = args::Args::parse();
|
let args = args::Args::parse();
|
||||||
|
|
||||||
let command = args.command.to_owned();
|
let command = args.command.to_owned();
|
||||||
|
|
||||||
//println!("{:#?}", args);
|
println!("{:#?}", args);
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
args::Commands::PrintExperience(print_experience_args) =>
|
args::Commands::PrintExperience(print_experience_args) => {
|
||||||
print_experience(&args, &print_experience_args)?,
|
print_experience(&args, &print_experience_args)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,137 +1,14 @@
|
||||||
use journal::{
|
use journal::types::Journal;
|
||||||
helpers::{
|
use psychonaut_journal_types::ExportData;
|
||||||
ingestion_contains_estimate, ingestion_dose, ingestion_standard_deviation, ingestion_unit,
|
|
||||||
},
|
|
||||||
types::{CustomUnits, CustomUnitsType, Experience, ExportData, Ingestion},
|
|
||||||
};
|
|
||||||
use std::fs::File;
|
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 file = File::open(filename)?;
|
||||||
|
|
||||||
let export_data: ExportData = serde_json::from_reader(file)?;
|
let export_data: ExportData = serde_json::from_reader(file)?;
|
||||||
|
|
||||||
// export_data
|
let journal = Journal::import(export_data);
|
||||||
// .experiences
|
|
||||||
// .sort_by(|a, b| a.modified_time.cmp(&b.modified_time));
|
|
||||||
|
|
||||||
//for experience in export_data.experiences.iter_mut() {
|
Ok(journal)
|
||||||
// experience
|
|
||||||
// .ingestions
|
|
||||||
// .sort_by(|a, b| a.ingestion_time.cmp(&b.ingestion_time));
|
|
||||||
//}
|
|
||||||
|
|
||||||
Ok(export_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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]
|
[package]
|
||||||
name = "journal"
|
name = "psychonaut_journal_types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,9 @@ pub struct Experience {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
#[serde(rename = "creationDate")]
|
#[serde(rename = "creationDate")]
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: u64,
|
||||||
#[serde(rename = "sortDate")]
|
#[serde(rename = "sortDate")]
|
||||||
pub modified_time: DateTime<Utc>,
|
pub modified_time: u64,
|
||||||
pub ingestions: Vec<Ingestion>,
|
pub ingestions: Vec<Ingestion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ pub struct CustomUnit {
|
||||||
pub substance_name: String,
|
pub substance_name: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(rename = "creationDate")]
|
#[serde(rename = "creationDate")]
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: u64,
|
||||||
pub administration_route: AdministrationRoute,
|
pub administration_route: AdministrationRoute,
|
||||||
pub dose: f64,
|
pub dose: f64,
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
|
@ -97,8 +97,8 @@ pub struct CustomUnit {
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ExportData {
|
pub struct ExportData {
|
||||||
pub experiences: Vec<Experiences>,
|
pub experiences: Vec<Experience>,
|
||||||
pub substance_companions: Vec<SubstanceCompanion>,
|
pub substance_companions: Vec<SubstanceCompanion>,
|
||||||
pub custom_substances: Vec<CustomSubstance>,
|
pub custom_substances: Vec<CustomSubstance>,
|
||||||
pub custom_units: Vec<CustomUnits>,
|
pub custom_units: Vec<CustomUnit>,
|
||||||
}
|
}
|
Loading…
Reference in a new issue