summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkshay <nerdy@peppe.rs>2021-02-24 11:58:30 +0530
committerAkshay <nerdy@peppe.rs>2021-02-24 11:58:30 +0530
commit22a3f02c0363d911d1cc0b6a53c9e5c801a37267 (patch)
treeb6ad455a99f0bd0f683f9c449245a9618572d023
parentfbcc966a3da8a75842c6b8843a9fd7f1edb0db15 (diff)
add initial float habit structure
-rw-r--r--src/habit/float.rs180
-rw-r--r--src/habit/mod.rs3
2 files changed, 183 insertions, 0 deletions
diff --git a/src/habit/float.rs b/src/habit/float.rs
new file mode 100644
index 0000000..7e98b18
--- /dev/null
+++ b/src/habit/float.rs
@@ -0,0 +1,180 @@
+use std::cmp::{Eq, Ord, PartialEq};
+use std::collections::HashMap;
+use std::default::Default;
+use std::fmt;
+use std::ops::{Add, Sub};
+
+use chrono::NaiveDate;
+use serde::{Deserialize, Serialize};
+
+use crate::command::GoalKind;
+use crate::habit::prelude::default_auto;
+use crate::habit::traits::Habit;
+use crate::habit::{InnerData, TrackEvent};
+
+#[derive(Copy, Clone, Debug, Ord, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
+pub struct FloatData {
+ value: u32,
+ precision: u8,
+}
+
+impl FloatData {
+ pub fn add(self, v: u32) -> Self {
+ let f = FloatData {
+ value: v,
+ precision: self.precision,
+ };
+ self + f
+ }
+ pub fn sub(self, v: u32) -> Self {
+ let f = FloatData {
+ value: v,
+ precision: self.precision,
+ };
+ self - f
+ }
+ pub fn zero() -> Self {
+ FloatData {
+ value: 0,
+ precision: 0,
+ }
+ }
+}
+
+impl fmt::Display for FloatData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let characteristic = self.value / (10 * self.precision as u32);
+ let mantissa = self.value % (10 * self.precision as u32);
+ let s = format!("{}.{}", characteristic, mantissa);
+ write!(f, "{:^3}", s)
+ }
+}
+
+impl Add for FloatData {
+ type Output = Self;
+ fn add(self, other: Self) -> Self {
+ Self {
+ value: self.value + other.value,
+ precision: self.precision,
+ }
+ }
+}
+
+impl Sub for FloatData {
+ type Output = Self;
+
+ fn sub(self, other: Self) -> Self {
+ Self {
+ value: self.value.saturating_sub(other.value),
+ precision: self.precision,
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Float {
+ name: String,
+ stats: HashMap<NaiveDate, FloatData>,
+ goal: FloatData,
+ precision: u8,
+ #[serde(default = "default_auto")]
+ auto: bool,
+
+ #[serde(skip)]
+ inner_data: InnerData,
+}
+
+impl Float {
+ pub fn new(name: impl AsRef<str>, goal: u32, precision: u8, auto: bool) -> Self {
+ return Float {
+ name: name.as_ref().to_owned(),
+ stats: HashMap::new(),
+ goal: FloatData {
+ value: goal,
+ precision,
+ },
+ precision,
+ auto,
+ inner_data: Default::default(),
+ };
+ }
+}
+
+impl Habit for Float {
+ type HabitType = FloatData;
+
+ fn name(&self) -> String {
+ return self.name.clone();
+ }
+ fn set_name(&mut self, n: impl AsRef<str>) {
+ self.name = n.as_ref().to_owned();
+ }
+ fn kind(&self) -> GoalKind {
+ GoalKind::Float(self.goal.value, self.goal.precision)
+ }
+ fn set_goal(&mut self, g: Self::HabitType) {
+ self.goal = g;
+ }
+ fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
+ self.stats.get(&date)
+ }
+ fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
+ *self.stats.entry(date).or_insert(val) = val;
+ }
+ fn reached_goal(&self, date: NaiveDate) -> bool {
+ if let Some(val) = self.stats.get(&date) {
+ if val >= &self.goal {
+ return true;
+ }
+ }
+ return false;
+ }
+ fn remaining(&self, date: NaiveDate) -> u32 {
+ if self.reached_goal(date) {
+ return 0;
+ } else {
+ if let Some(&val) = self.stats.get(&date) {
+ return (self.goal - val).value;
+ } else {
+ return self.goal.value;
+ }
+ }
+ }
+ fn goal(&self) -> u32 {
+ return self.goal.value;
+ }
+ fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
+ if let Some(val) = self.stats.get_mut(&date) {
+ match event {
+ TrackEvent::Increment => *val = val.add(1),
+ TrackEvent::Decrement => {
+ if *val > FloatData::zero() {
+ *val = val.sub(1);
+ } else {
+ self.stats.remove(&date);
+ };
+ }
+ }
+ } else {
+ match event {
+ TrackEvent::Increment => self.insert_entry(
+ date,
+ FloatData {
+ value: 1,
+ precision: self.precision,
+ },
+ ),
+ _ => {}
+ };
+ }
+ }
+ fn inner_data_ref(&self) -> &InnerData {
+ &self.inner_data
+ }
+ fn inner_data_mut_ref(&mut self) -> &mut InnerData {
+ &mut self.inner_data
+ }
+ fn is_auto(&self) -> bool {
+ self.auto
+ }
+}
diff --git a/src/habit/mod.rs b/src/habit/mod.rs
index d51abe5..5359bca 100644
--- a/src/habit/mod.rs
+++ b/src/habit/mod.rs
@@ -9,6 +9,9 @@ pub use count::Count;
mod bit;
pub use bit::Bit;
+mod float;
+pub use float::Float;
+
mod prelude;
pub use prelude::{TrackEvent, ViewMode};