diff --git a/Cargo.lock b/Cargo.lock index 7854549..4e6dd10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -740,6 +740,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "dimensioned" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b0a86c5d31c93238ff4b694fa31f3acdf67440770dc314c57d90e433914397" +dependencies = [ + "generic-array 0.14.7", + "num-traits", + "typenum", +] + [[package]] name = "displaydoc" version = "0.2.4" @@ -791,7 +802,7 @@ version = "0.6.0" dependencies = [ "chrono", "chrono-tz", - "dimensioned", + "dimensioned 0.7.0", "serde 1.0.188", "serde_derive", "serde_json", @@ -944,6 +955,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "fitnesstrax" +version = "0.1.0" +dependencies = [ + "chrono", + "dimensioned 0.8.0", + "emseries", +] + [[package]] name = "flate2" version = "1.0.27" diff --git a/Cargo.toml b/Cargo.toml index 6c07497..abb5d09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "dashboard", "emseries", "file-service", + "fitnesstrax", "fluent-ergonomics", "geo-types", "gm-control-panel", diff --git a/build.sh b/build.sh index dcaed56..8311bd5 100755 --- a/build.sh +++ b/build.sh @@ -11,6 +11,7 @@ RUST_ALL_TARGETS=( "dashboard" "emseries" "file-service" + "fitnesstrax" "fluent-ergonomics" "geo-types" "gm-control-panel" diff --git a/fitnesstrax/Cargo.toml b/fitnesstrax/Cargo.toml new file mode 100644 index 0000000..da0b1bc --- /dev/null +++ b/fitnesstrax/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "fitnesstrax" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chrono = { version = "0.4" } +dimensioned = {version = "0.8" } +emseries = { path = "../emseries" } diff --git a/fitnesstrax/src/legacy.rs b/fitnesstrax/src/legacy.rs new file mode 100644 index 0000000..0a79713 --- /dev/null +++ b/fitnesstrax/src/legacy.rs @@ -0,0 +1,24 @@ +use crate::types; + +#[cfg(test)] +mod test { + #[test] + fn read_a_legacy_set_rep_record() { + unimplemented!() + } + + #[test] + fn read_a_legacy_steps_record() { + unimplemented!() + } + + #[test] + fn read_a_legacy_time_distance_record() { + unimplemented!() + } + + #[test] + fn read_a_legacy_weight_record() { + unimplemented!() + } +} diff --git a/fitnesstrax/src/lib.rs b/fitnesstrax/src/lib.rs new file mode 100644 index 0000000..b591639 --- /dev/null +++ b/fitnesstrax/src/lib.rs @@ -0,0 +1,6 @@ +use chrono::NaiveDate; +use dimensioned::si; +use emseries::DateTimeTz; + +mod legacy; +mod types; diff --git a/fitnesstrax/src/main.rs b/fitnesstrax/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/fitnesstrax/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/fitnesstrax/src/types.rs b/fitnesstrax/src/types.rs new file mode 100644 index 0000000..0dfc3e5 --- /dev/null +++ b/fitnesstrax/src/types.rs @@ -0,0 +1,59 @@ +/// SetRep represents workouts like pushups or situps, which involve doing a "set" of a number of +/// actions, resting, and then doing another set. +pub struct SetRep { + /// I assume that a set/rep workout is only done once in a day. + date: NaiveDate, + /// Each set entry represents the number of times that the action was performed in a set. So, a + /// pushup workout that involved five sets would have five entries. Each entry would be x + /// number of pushups. A viable workout would be something like [6, 6, 4, 4, 5]. + sets: Vec, + comments: Option, +} + +/// The number of steps one takes in a single day. +pub struct Steps { + date: NaiveDate, + count: u32, +} + +/// TimeDistance represents workouts characterized by a duration and a distance travelled. These +/// sorts of workouts can occur many times a day, depending on how one records things. I might +/// record a single 30-km workout if I go on a long-distanec ride. Or I might record multiple 5km +/// workouts if I am out running errands. Distance and Duration are both optional because different +/// people have different priorities and may choose to measure different things. +pub struct TimeDistance { + /// The precise time (and the relevant timezone) of the workout. One of the edge cases that I + /// account for is that a ride which occurred at 11pm in one timezone would then count as 1am + /// if one moved two timezones to the east. This is kind of nonsensical from a human + /// perspective, so the DateTimeTz keeps track of the precise time in UTC, but also the + /// timezone in which the event was recorded. + datetime: DateTimeTz, + /// The distance travelled. This is optional because such a workout makes sense even without + /// the distance. + distance: Option>, + /// The duration of the workout, which is also optional. Some people may keep track of the + /// amount of distance travelled without tracking the duration. + duration: Option>, + comments: Option, +} + +/// A singular daily weight measurement. Weight changes slowly enough that it seems unlikely to +/// need to track more than a single weight in a day. +pub struct Weight { + date: NaiveDate, + weight: si::Kilogram, +} + +/// The unified data structure for all records that are part of the app. +pub enum TraxRecord { + BikeRide(TimeDistance), + Pushups, + Row(TimeDistance), + Run(TimeDistance), + Situps, + Squats, + Steps(Steps), + Swim(TimeDistance), + Walk(TimeDistance), + Weight(Weight), +}