aboutsummaryrefslogtreecommitdiff
path: root/src/habit
diff options
context:
space:
mode:
Diffstat (limited to 'src/habit')
-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 @@
1use std::cmp::{Eq, Ord, PartialEq};
2use std::collections::HashMap;
3use std::default::Default;
4use std::fmt;
5use std::ops::{Add, Sub};
6
7use chrono::NaiveDate;
8use serde::{Deserialize, Serialize};
9
10use crate::command::GoalKind;
11use crate::habit::prelude::default_auto;
12use crate::habit::traits::Habit;
13use crate::habit::{InnerData, TrackEvent};
14
15#[derive(Copy, Clone, Debug, Ord, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
16pub struct FloatData {
17 value: u32,
18 precision: u8,
19}
20
21impl FloatData {
22 pub fn add(self, v: u32) -> Self {
23 let f = FloatData {
24 value: v,
25 precision: self.precision,
26 };
27 self + f
28 }
29 pub fn sub(self, v: u32) -> Self {
30 let f = FloatData {
31 value: v,
32 precision: self.precision,
33 };
34 self - f
35 }
36 pub fn zero() -> Self {
37 FloatData {
38 value: 0,
39 precision: 0,
40 }
41 }
42}
43
44impl fmt::Display for FloatData {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 let characteristic = self.value / (10 * self.precision as u32);
47 let mantissa = self.value % (10 * self.precision as u32);
48 let s = format!("{}.{}", characteristic, mantissa);
49 write!(f, "{:^3}", s)
50 }
51}
52
53impl Add for FloatData {
54 type Output = Self;
55 fn add(self, other: Self) -> Self {
56 Self {
57 value: self.value + other.value,
58 precision: self.precision,
59 }
60 }
61}
62
63impl Sub for FloatData {
64 type Output = Self;
65
66 fn sub(self, other: Self) -> Self {
67 Self {
68 value: self.value.saturating_sub(other.value),
69 precision: self.precision,
70 }
71 }
72}
73
74#[derive(Debug, Serialize, Deserialize)]
75pub struct Float {
76 name: String,
77 stats: HashMap<NaiveDate, FloatData>,
78 goal: FloatData,
79 precision: u8,
80 #[serde(default = "default_auto")]
81 auto: bool,
82
83 #[serde(skip)]
84 inner_data: InnerData,
85}
86
87impl Float {
88 pub fn new(name: impl AsRef<str>, goal: u32, precision: u8, auto: bool) -> Self {
89 return Float {
90 name: name.as_ref().to_owned(),
91 stats: HashMap::new(),
92 goal: FloatData {
93 value: goal,
94 precision,
95 },
96 precision,
97 auto,
98 inner_data: Default::default(),
99 };
100 }
101}
102
103impl Habit for Float {
104 type HabitType = FloatData;
105
106 fn name(&self) -> String {
107 return self.name.clone();
108 }
109 fn set_name(&mut self, n: impl AsRef<str>) {
110 self.name = n.as_ref().to_owned();
111 }
112 fn kind(&self) -> GoalKind {
113 GoalKind::Float(self.goal.value, self.goal.precision)
114 }
115 fn set_goal(&mut self, g: Self::HabitType) {
116 self.goal = g;
117 }
118 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
119 self.stats.get(&date)
120 }
121 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
122 *self.stats.entry(date).or_insert(val) = val;
123 }
124 fn reached_goal(&self, date: NaiveDate) -> bool {
125 if let Some(val) = self.stats.get(&date) {
126 if val >= &self.goal {
127 return true;
128 }
129 }
130 return false;
131 }
132 fn remaining(&self, date: NaiveDate) -> u32 {
133 if self.reached_goal(date) {
134 return 0;
135 } else {
136 if let Some(&val) = self.stats.get(&date) {
137 return (self.goal - val).value;
138 } else {
139 return self.goal.value;
140 }
141 }
142 }
143 fn goal(&self) -> u32 {
144 return self.goal.value;
145 }
146 fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
147 if let Some(val) = self.stats.get_mut(&date) {
148 match event {
149 TrackEvent::Increment => *val = val.add(1),
150 TrackEvent::Decrement => {
151 if *val > FloatData::zero() {
152 *val = val.sub(1);
153 } else {
154 self.stats.remove(&date);
155 };
156 }
157 }
158 } else {
159 match event {
160 TrackEvent::Increment => self.insert_entry(
161 date,
162 FloatData {
163 value: 1,
164 precision: self.precision,
165 },
166 ),
167 _ => {}
168 };
169 }
170 }
171 fn inner_data_ref(&self) -> &InnerData {
172 &self.inner_data
173 }
174 fn inner_data_mut_ref(&mut self) -> &mut InnerData {
175 &mut self.inner_data
176 }
177 fn is_auto(&self) -> bool {
178 self.auto
179 }
180}
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;
9mod bit; 9mod bit;
10pub use bit::Bit; 10pub use bit::Bit;
11 11
12mod float;
13pub use float::Float;
14
12mod prelude; 15mod prelude;
13pub use prelude::{TrackEvent, ViewMode}; 16pub use prelude::{TrackEvent, ViewMode};
14 17