tdo_core/list.rs
1//! General implementation of todo lists.
2use todo::Todo;
3use error::*;
4
5/// Simple todo list structure.
6///
7/// Todos can be grouped together in so called todo lists (as in the real world).
8/// Therefore, the `TodoList` struct can be used. It's a simple data structure that holds a
9/// number of `Todo` items and offers all basic functions for managing them.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct TodoList {
12 /// Name of the todo list.
13 pub name: String,
14 /// The actual vector of `Todo` items.
15 pub list: Vec<Todo>,
16}
17
18impl TodoList {
19 /// Create a new list with the given name.
20 ///
21 /// # Example
22 ///
23 /// ```
24 /// # use tdo_core::list::*;
25 /// let mut list = TodoList::new("important");
26 /// ```
27 pub fn new(name: &str) -> TodoList {
28 TodoList {
29 name: name.to_string(),
30 list: Vec::new(),
31 }
32 }
33
34 /// Add a new todo to the list.
35 ///
36 /// # Example
37 ///
38 /// ```
39 /// # use tdo_core::list::*;
40 /// # use tdo_core::todo::*;
41 /// # let mut list = TodoList::new("important");
42 /// list.add(Todo::new(0,"A first important todo", None));
43 /// ```
44 pub fn add(&mut self, new_todo: Todo) {
45 self.list.push(new_todo);
46 }
47
48 /// Check if the list contains a todo with the given ID.
49 ///
50 /// This function returns a `TdoResult`, wich will contion a `TodoError::NotInList`
51 /// if the list does not contain any todo with the given ID or the position in the list.
52 pub fn contains_id(&self, id: u32) -> TdoResult<usize> {
53 match self.list.iter().position(|x| x.id == id) {
54 Some(index) => Ok(index),
55 None => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
56 }
57 }
58 /// Mark a todo from the list with the given ID as done.
59 ///
60 /// This function returns a `TdoResult`, which will contain a `TodoError::NotInList`
61 /// if the list does not contain any todo with the given ID.
62 pub fn done_id(&mut self, id: u32) -> TdoResult<()> {
63 match self.contains_id(id) {
64 Ok(index) => Ok(self.list[index].set_done()),
65 _ => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
66 }
67 }
68
69 /// Remove a todo with the given ID from the list.
70 ///
71 /// This function returns a `TdoResult`, which will contain the removed Todo itself or a
72 /// `TodoError::NotInList` if the list does not contain any todo with the given id.
73 pub fn remove_id(&mut self, id: u32) -> TdoResult<Todo> {
74 match self.contains_id(id) {
75 Ok(index) => Ok(self.list.remove(index)),
76 _ => Err(ErrorKind::TodoError(todo_error::ErrorKind::NotInList).into()),
77 }
78 }
79
80 /// Search for all undone todos in the list.
81 ///
82 /// Returns a vector of all undone todos.
83 pub fn list_undone(&self) -> Vec<Todo> {
84 let mut undone: Vec<Todo> = vec![];
85 for entry in self.to_owned().list.into_iter() {
86 if !entry.done {
87 undone.push(entry);
88 }
89 }
90 undone
91 }
92
93 /// Remove all done todos from the list.
94 pub fn clean(&mut self) {
95 for entry in self.to_owned().list.into_iter() {
96 if entry.done {
97 let _ = self.remove_id(entry.id);
98 }
99 }
100 }
101
102 /// Remove a todo with a specific ID from the list.
103 pub fn pop_id(&mut self, todo_id: u32) -> TdoResult<Todo> {
104 let list_pos = self.contains_id(todo_id)?;
105
106 Ok(self.list.remove(list_pos))
107 }
108
109 /// Insert an existing todo into the list, preserving the ordering of the internal list.
110 pub fn insert_todo(&mut self, todo: Todo) {
111 let insert_id = self.list
112 .iter()
113 .fold(0, |acc, &ref x| if todo.id > x.id { acc + 1 } else { acc });
114
115 self.list.insert(insert_id, todo);
116 }
117}
118
119/// Instanciates a _default_ `TodoList`.
120/// This function is invoked when a `Tdo` container structure is instanciated.
121impl Default for TodoList {
122 fn default() -> TodoList {
123 TodoList {
124 name: "default".to_string(),
125 list: Vec::new(),
126 }
127 }
128}