1
- //! Implements core timer functionality. Starts a thread which
1
+ //! Implements core timer functionality. Starts a thread which
2
2
//! wakes up every minute and checks if an alarm is to be played.
3
3
//! CPU usage (on Mac) is not significant
4
4
//! The tread runs throughout the life of the app. No need to handle
@@ -62,6 +62,12 @@ mod alarm_manager {
62
62
}
63
63
}
64
64
}
65
+
66
+ if let Some ( alarm) =
67
+ find_next_alarm ( & self . alarms , current_weekday, current_hour, current_minute)
68
+ {
69
+ debug ! ( "Next alarm at: {:?}" , alarm) ;
70
+ }
65
71
}
66
72
67
73
/// Handles message from ui_handlers
@@ -87,6 +93,78 @@ mod alarm_manager {
87
93
}
88
94
}
89
95
96
+ fn find_next_alarm (
97
+ alarm_schedule : & HashMap < Weekday , HashMap < usize , Vec < usize > > > ,
98
+ current_day : Weekday ,
99
+ current_hour : usize ,
100
+ current_minute : usize ,
101
+ ) -> Option < ( Weekday , usize , usize ) > {
102
+ let mut current_day_to_check;
103
+ let mut next_alarm: Option < ( Weekday , usize , usize ) > = None ;
104
+
105
+ // Start with current_day, check if alarms are scheduled after current time.
106
+ // Repeat for successive days until we wrap around to today
107
+
108
+ if let Some ( hour_map) = alarm_schedule. get ( & current_day) {
109
+ //hashmaps are not sorted. So first get sorted hours
110
+ let mut sorted_keys: Vec < usize > = hour_map. keys ( ) . cloned ( ) . collect ( ) ;
111
+ sorted_keys. sort ( ) ;
112
+
113
+ ' hour_loop: for hour in & sorted_keys {
114
+ if let Some ( mins) = hour_map. get ( hour) {
115
+ for min in mins. iter ( ) {
116
+ if * hour > current_hour {
117
+ //mins are sorted. just pick up the first
118
+ next_alarm = Some ( ( current_day, * hour, * min) ) ;
119
+ break ' hour_loop;
120
+ } else if * hour == current_hour {
121
+ if * min > current_minute {
122
+ next_alarm = Some ( ( current_day, * hour, * min) ) ;
123
+ break ' hour_loop;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ if next_alarm. is_some ( ) {
132
+ //we found our next alarm on the same day
133
+ return next_alarm;
134
+ }
135
+
136
+ //try searching other days
137
+ current_day_to_check = current_day. succ ( ) ;
138
+ loop {
139
+ if let Some ( hour_map) = alarm_schedule. get ( & current_day_to_check) {
140
+ let mut sorted_keys: Vec < usize > = hour_map. keys ( ) . cloned ( ) . collect ( ) ;
141
+ sorted_keys. sort ( ) ;
142
+
143
+ for hour in & sorted_keys {
144
+ if let Some ( mins) = hour_map. get ( hour) {
145
+ for min in mins. iter ( ) {
146
+ //mins are sorted. just pick up the first
147
+ return Some ( ( current_day_to_check, * hour, * min) ) ;
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ current_day_to_check = current_day_to_check. succ ( ) ;
154
+
155
+ if current_day_to_check == current_day {
156
+ debug ! ( "breaking" ) ;
157
+ break ;
158
+ }
159
+ }
160
+
161
+ return next_alarm;
162
+ }
163
+
164
+ //fn find_next_for_today(hour_map: &HashMap<usize, Vec<usize>>) -> (Weekday, usize, usize) {
165
+ //return
166
+ //}
167
+
90
168
fn get_hours ( s : usize , e : usize ) -> Vec < usize > {
91
169
let mut hrs = Vec :: new ( ) ;
92
170
@@ -99,7 +177,7 @@ mod alarm_manager {
99
177
hrs
100
178
}
101
179
102
- /// For a set of rules, finds the hours and minutes for each day at which
180
+ /// For a set of rules, finds the hours and minutes for each day at which
103
181
/// alarm should be played. Assumes that rules are not overlapping
104
182
fn get_alarms ( rules : & [ Rule ] ) -> HashMap < Weekday , HashMap < usize , Vec < usize > > > {
105
183
let mut alarms: HashMap < Weekday , HashMap < usize , Vec < usize > > > = HashMap :: new ( ) ;
@@ -172,6 +250,7 @@ mod alarm_manager {
172
250
mod tests {
173
251
use super :: * ;
174
252
use crate :: utils:: * ;
253
+ use maplit:: hashmap;
175
254
176
255
#[ test]
177
256
fn test_get_alarms ( ) {
@@ -198,6 +277,64 @@ mod alarm_manager {
198
277
assert ! ( alarms. contains_key( & Weekday :: Tue ) ) ;
199
278
assert ! ( alarms. contains_key( & Weekday :: Wed ) ) ;
200
279
}
280
+
281
+ #[ test]
282
+ fn test_next_alarm ( ) {
283
+ setup_logger ( ) ;
284
+ let rule1 = Rule {
285
+ serial : 1 ,
286
+ days : vec ! [ "Fri" . to_string( ) ] ,
287
+ interval : 30 ,
288
+ from : 17 ,
289
+ to : 18 ,
290
+ } ;
291
+
292
+ let rule2 = Rule {
293
+ serial : 2 ,
294
+ days : vec ! [ "Sun" . to_string( ) ] ,
295
+ interval : 30 ,
296
+ from : 19 ,
297
+ to : 20 ,
298
+ } ;
299
+
300
+ let rules = vec ! [ rule1, rule2] ;
301
+ let alarms = get_alarms ( & rules) ;
302
+
303
+ let expected = hashmap ! {
304
+ Weekday :: Fri => hashmap! {
305
+ 17 => vec![ 30 ] ,
306
+ 18 => vec![ 0 ] ,
307
+ } ,
308
+ // Add more weekdays and alarms as needed
309
+ Weekday :: Sun => hashmap! {
310
+ 19 => vec![ 30 ] ,
311
+ 20 => vec![ 0 ] ,
312
+ } ,
313
+ } ;
314
+
315
+ assert_eq ! ( alarms, expected) ;
316
+
317
+ let mut next = find_next_alarm ( & alarms, Weekday :: Fri , 17 , 58 ) ;
318
+ assert_eq ! ( next, Some ( ( Weekday :: Fri , 18 , 0 ) ) ) ;
319
+
320
+ next = find_next_alarm ( & alarms, Weekday :: Sat , 18 , 0 ) ;
321
+ assert_eq ! ( next, Some ( ( Weekday :: Sun , 19 , 30 ) ) ) ;
322
+
323
+ next = find_next_alarm ( & alarms, Weekday :: Sun , 18 , 0 ) ;
324
+ assert_eq ! ( next, Some ( ( Weekday :: Sun , 19 , 30 ) ) ) ;
325
+
326
+ next = find_next_alarm ( & alarms, Weekday :: Sun , 19 , 0 ) ;
327
+ assert_eq ! ( next, Some ( ( Weekday :: Sun , 19 , 30 ) ) ) ;
328
+
329
+ next = find_next_alarm ( & alarms, Weekday :: Sun , 19 , 20 ) ;
330
+ assert_eq ! ( next, Some ( ( Weekday :: Sun , 19 , 30 ) ) ) ;
331
+
332
+ next = find_next_alarm ( & alarms, Weekday :: Sun , 19 , 31 ) ;
333
+ assert_eq ! ( next, Some ( ( Weekday :: Sun , 20 , 0 ) ) ) ;
334
+
335
+ next = find_next_alarm ( & alarms, Weekday :: Sun , 20 , 31 ) ;
336
+ assert_eq ! ( next, Some ( ( Weekday :: Fri , 17 , 30 ) ) ) ;
337
+ }
201
338
}
202
339
}
203
340
0 commit comments