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