1use chrono::{DateTime, Utc};
10use std::collections::vec_deque::VecDeque;
11use std::ptr;
12use super::custom_icon_uuid::CustomIconUuid;
13use super::entry::Entry;
14use super::entry_uuid::EntryUuid;
15use super::group_uuid::GroupUuid;
16use super::icon::Icon;
17use super::times::Times;
18
19#[derive(Clone, Debug, PartialEq)]
21pub struct Group {
22 pub creation_time: DateTime<Utc>,
24
25 pub custom_icon_uuid: Option<CustomIconUuid>,
27
28 pub def_auto_type_sequence: String,
30
31 pub enable_auto_type: Option<bool>,
33
34 pub enable_searching: Option<bool>,
36
37 pub entries: Vec<Entry>,
39
40 pub expires: bool,
42
43 pub expiry_time: DateTime<Utc>,
45
46 pub groups: Vec<Group>,
48
49 pub icon: Icon,
51
52 pub is_expanded: bool,
54
55 pub last_accessed: DateTime<Utc>,
57
58 pub last_modified: DateTime<Utc>,
60
61 pub last_top_visible_entry: EntryUuid,
63
64 pub location_changed: DateTime<Utc>,
66
67 pub name: String,
69
70 pub notes: String,
72
73 pub usage_count: i32,
75
76 pub uuid: GroupUuid,
78}
79
80impl Group {
81 pub fn new<S: Into<String>>(name: S) -> Group {
91 let mut group = Group::default();
92 group.name = name.into();
93 group.uuid = GroupUuid::new_random();
94 group
95 }
96
97 pub fn add_entry(&mut self, entry: Entry) {
113 self.entries.push(entry);
114 }
115
116 pub fn add_group(&mut self, group: Group) {
132 self.groups.push(group);
133 }
134
135 pub fn iter(&self) -> Iter {
155 Iter::new(self)
156 }
157
158 pub fn iter_mut(&mut self) -> IterMut {
172 IterMut::new(self)
173 }
174
175 pub fn remove_entry(&mut self, entry_uuid: EntryUuid) -> Option<Entry> {
190 match self.entries.iter().position(|x| x.uuid == entry_uuid) {
191 Some(x) => Some(self.entries.remove(x)),
192 None => None,
193 }
194 }
195
196 pub fn remove_group(&mut self, group_uuid: GroupUuid) -> Option<Group> {
211 match self.groups.iter().position(|x| x.uuid == group_uuid) {
212 Some(x) => Some(self.groups.remove(x)),
213 None => None,
214 }
215 }
216}
217
218impl Default for Group {
219 fn default() -> Group {
220 let now = Utc::now();
221 Group {
222 creation_time: now,
223 custom_icon_uuid: None,
224 def_auto_type_sequence: String::new(),
225 enable_auto_type: None,
226 enable_searching: None,
227 entries: Vec::new(),
228 expires: false,
229 expiry_time: now,
230 groups: Vec::new(),
231 icon: Icon::Folder,
232 is_expanded: true,
233 last_accessed: now,
234 last_modified: now,
235 last_top_visible_entry: EntryUuid::nil(),
236 location_changed: now,
237 name: String::new(),
238 notes: String::new(),
239 usage_count: 0,
240 uuid: GroupUuid::nil(),
241 }
242 }
243}
244
245impl Times for Group {
246 fn creation_time(&self) -> DateTime<Utc> {
247 self.creation_time
248 }
249
250 fn expires(&self) -> bool {
251 self.expires
252 }
253
254 fn expiry_time(&self) -> DateTime<Utc> {
255 self.expiry_time
256 }
257
258 fn last_accessed(&self) -> DateTime<Utc> {
259 self.last_accessed
260 }
261
262 fn last_modified(&self) -> DateTime<Utc> {
263 self.last_modified
264 }
265
266 fn location_changed(&self) -> DateTime<Utc> {
267 self.location_changed
268 }
269
270 fn usage_count(&self) -> i32 {
271 self.usage_count
272 }
273
274 fn set_creation_time(&mut self, val: DateTime<Utc>) {
275 self.creation_time = val;
276 }
277
278 fn set_expires(&mut self, val: bool) {
279 self.expires = val;
280 }
281
282 fn set_expiry_time(&mut self, val: DateTime<Utc>) {
283 self.expiry_time = val;
284 }
285
286 fn set_last_accessed(&mut self, val: DateTime<Utc>) {
287 self.last_accessed = val;
288 }
289
290 fn set_last_modified(&mut self, val: DateTime<Utc>) {
291 self.last_modified = val;
292 }
293
294 fn set_location_changed(&mut self, val: DateTime<Utc>) {
295 self.location_changed = val;
296 }
297
298 fn set_usage_count(&mut self, val: i32) {
299 self.usage_count = val;
300 }
301}
302
303pub struct Iter<'a> {
305 curr: Option<&'a Group>,
306 todo: VecDeque<&'a Group>,
307}
308
309impl<'a> Iter<'a> {
310 fn new(group: &'a Group) -> Iter<'a> {
311 let mut queue = VecDeque::new();
312 queue.push_back(group);
313 Iter {
314 curr: None,
315 todo: queue,
316 }
317 }
318}
319
320impl<'a> Iterator for Iter<'a> {
321 type Item = &'a Group;
322
323 fn next(&mut self) -> Option<&'a Group> {
324 match self.curr.take() {
325 Some(group) => {
326 for sub in group.groups.iter() {
327 self.todo.push_back(sub);
328 }
329 }
330 None => {}
331 }
332 self.curr = self.todo.pop_front();
333 self.curr
334 }
335}
336
337pub struct IterMut<'a> {
339 curr: Option<&'a mut Group>,
340 todo: VecDeque<&'a mut Group>,
341}
342
343impl<'a> IterMut<'a> {
344 fn new(group: &'a mut Group) -> IterMut<'a> {
345 let mut queue = VecDeque::new();
346 queue.push_back(group);
347 IterMut {
348 curr: None,
349 todo: queue,
350 }
351 }
352}
353
354impl<'a> Iterator for IterMut<'a> {
355 type Item = &'a mut Group;
356
357 fn next(&mut self) -> Option<&'a mut Group> {
358 match self.curr.take() {
359 Some(group) => {
360 for sub in group.groups.iter_mut() {
361 self.todo.push_back(sub);
362 }
363 }
364 None => {}
365 }
366 let curr = self.todo.pop_front();
367 self.curr = unsafe { ptr::read(&curr) };
368 curr
369 }
370}
371
372#[cfg(test)]
373mod tests {
374
375 use chrono::Utc;
376 use super::*;
377 use types::EntryUuid;
378 use types::GroupUuid;
379 use types::Icon;
380 use utils::test::approx_equal_datetime;
381
382 #[test]
383 fn test_new_returns_correct_instance() {
384 let now = Utc::now();
385 let name = "Root";
386 let group = Group::new(name.clone());
387 assert!(approx_equal_datetime(group.creation_time, now));
388 assert_eq!(group.custom_icon_uuid, None);
389 assert_eq!(group.def_auto_type_sequence, "");
390 assert_eq!(group.enable_auto_type, None);
391 assert_eq!(group.enable_searching, None);
392 assert_eq!(group.entries, Vec::new());
393 assert_eq!(group.expires, false);
394 assert!(approx_equal_datetime(group.expiry_time, now));
395 assert_eq!(group.groups, Vec::new());
396 assert_eq!(group.icon, Icon::Folder);
397 assert_eq!(group.is_expanded, true);
398 assert!(approx_equal_datetime(group.last_accessed, now));
399 assert!(approx_equal_datetime(group.last_modified, now));
400 assert_eq!(group.last_top_visible_entry, EntryUuid::nil());
401 assert!(approx_equal_datetime(group.location_changed, now));
402 assert_eq!(group.name, name);
403 assert_eq!(group.notes, "");
404 assert_eq!(group.usage_count, 0);
405 assert!(group.uuid != GroupUuid::nil());
406 }
407
408 #[test]
409 fn test_add_entry_adds_entry() {
410 let mut group = Group::new("group");
411 let entry = Entry::new();
412
413 assert_eq!(group.entries.len(), 0);
414 group.add_entry(entry.clone());
415 assert_eq!(group.entries.len(), 1);
416 assert_eq!(group.entries[0], entry);
417 }
418
419 #[test]
420 fn test_add_group_adds_group() {
421 let mut root = Group::new("root");
422 let child = Group::new("child");
423
424 assert_eq!(root.groups.len(), 0);
425 root.add_group(child.clone());
426 assert_eq!(root.groups.len(), 1);
427 assert_eq!(root.groups[0], child);
428 }
429
430 #[test]
431 fn test_iter_returns_correct_iterator() {
432 let mut root = Group::new("root");
433 let mut sub_1 = Group::new("sub_1");
434 let mut sub_2 = Group::new("sub_2");
435 let sub_1_1 = Group::new("sub_1_1");
436 let sub_1_2 = Group::new("sub_1_2");
437 let sub_2_1 = Group::new("sub_2_1");
438 let sub_2_2 = Group::new("sub_2_2");
439 sub_1.add_group(sub_1_1.clone());
440 sub_1.add_group(sub_1_2.clone());
441 sub_2.add_group(sub_2_1.clone());
442 sub_2.add_group(sub_2_2.clone());
443 root.add_group(sub_1.clone());
444 root.add_group(sub_2.clone());
445
446 let mut iterator = root.iter();
447 assert_eq!(iterator.next(), Some(&root));
448 assert_eq!(iterator.next(), Some(&sub_1));
449 assert_eq!(iterator.next(), Some(&sub_2));
450 assert_eq!(iterator.next(), Some(&sub_1_1));
451 assert_eq!(iterator.next(), Some(&sub_1_2));
452 assert_eq!(iterator.next(), Some(&sub_2_1));
453 assert_eq!(iterator.next(), Some(&sub_2_2));
454 assert_eq!(iterator.next(), None);
455 }
456
457 #[test]
458 fn test_iter_mut_returns_correct_iterator() {
459 let mut root = Group::new("root");
460 let sub_1 = Group::new("sub_1");
461 let sub_2 = Group::new("sub_2");
462 root.add_group(sub_1);
463 root.add_group(sub_2);
464
465 let mut num = 0;
466 for group in root.iter_mut() {
467 group.name = num.to_string();
468 num += 1;
469 }
470
471 let mut num = 0;
472 for group in root.iter() {
473 assert_eq!(group.name, num.to_string());
474 num += 1;
475 }
476 }
477
478 #[test]
479 fn test_remove_entry_removes_entry() {
480 let mut group = Group::new("Sample");
481 let entry = Entry::new();
482
483 assert_eq!(group.entries.len(), 0);
484 group.add_entry(entry.clone());
485 assert_eq!(group.entries.len(), 1);
486 assert_eq!(group.remove_entry(entry.uuid), Some(entry.clone()));
487 assert_eq!(group.entries.len(), 0);
488 assert_eq!(group.remove_entry(entry.uuid), None);
489 }
490
491 #[test]
492 fn test_remove_group_removes_group() {
493 let mut parent = Group::new("Parent");
494 let child = Group::new("Child");
495
496 assert_eq!(parent.groups.len(), 0);
497 parent.add_group(child.clone());
498 assert_eq!(parent.groups.len(), 1);
499 assert_eq!(parent.remove_group(child.uuid), Some(child.clone()));
500 assert_eq!(parent.groups.len(), 0);
501 assert_eq!(parent.remove_group(child.uuid), None);
502 }
503
504 #[test]
505 fn test_default_returns_correct_instance() {
506 let now = Utc::now();
507 let group = Group::default();
508 assert!(approx_equal_datetime(group.creation_time, now));
509 assert_eq!(group.custom_icon_uuid, None);
510 assert_eq!(group.def_auto_type_sequence, "");
511 assert_eq!(group.enable_auto_type, None);
512 assert_eq!(group.enable_searching, None);
513 assert_eq!(group.entries, Vec::new());
514 assert_eq!(group.expires, false);
515 assert!(approx_equal_datetime(group.expiry_time, now));
516 assert_eq!(group.groups, Vec::new());
517 assert_eq!(group.icon, Icon::Folder);
518 assert_eq!(group.is_expanded, true);
519 assert!(approx_equal_datetime(group.last_accessed, now));
520 assert!(approx_equal_datetime(group.last_modified, now));
521 assert_eq!(group.last_top_visible_entry, EntryUuid::nil());
522 assert!(approx_equal_datetime(group.location_changed, now));
523 assert_eq!(group.name, "");
524 assert_eq!(group.notes, "");
525 assert_eq!(group.usage_count, 0);
526 assert_eq!(group.uuid, GroupUuid::nil());
527 }
528}