kitchen_fridge/utils/
mod.rs1use std::collections::{HashMap, HashSet};
4use std::sync::{Arc, Mutex};
5use std::hash::Hash;
6use std::io::{stdin, stdout, Read, Write};
7
8use minidom::Element;
9use url::Url;
10
11use crate::traits::CompleteCalendar;
12use crate::traits::DavCalendar;
13use crate::Item;
14use crate::item::SyncStatus;
15
16pub fn find_elems<S: AsRef<str>>(root: &Element, searched_name: S) -> Vec<&Element> {
18 let searched_name = searched_name.as_ref();
19 let mut elems: Vec<&Element> = Vec::new();
20
21 for el in root.children() {
22 if el.name() == searched_name {
23 elems.push(el);
24 } else {
25 let ret = find_elems(el, searched_name);
26 elems.extend(ret);
27 }
28 }
29 elems
30}
31
32pub fn find_elem<S: AsRef<str>>(root: &Element, searched_name: S) -> Option<&Element> {
34 let searched_name = searched_name.as_ref();
35 if root.name() == searched_name {
36 return Some(root);
37 }
38
39 for el in root.children() {
40 if el.name() == searched_name {
41 return Some(el);
42 } else {
43 let ret = find_elem(el, searched_name);
44 if ret.is_some() {
45 return ret;
46 }
47 }
48 }
49 None
50}
51
52
53pub fn print_xml(element: &Element) {
54 let mut writer = std::io::stdout();
55
56 let mut xml_writer = minidom::quick_xml::Writer::new_with_indent(
57 std::io::stdout(),
58 0x20, 4
59 );
60 let _ = element.to_writer(&mut xml_writer);
61 let _ = writer.write(&[0x0a]);
62}
63
64pub async fn print_calendar_list<C>(cals: &HashMap<Url, Arc<Mutex<C>>>)
66where
67 C: CompleteCalendar,
68{
69 for (url, cal) in cals {
70 println!("CAL {} ({})", cal.lock().unwrap().name(), url);
71 match cal.lock().unwrap().get_items().await {
72 Err(_err) => continue,
73 Ok(map) => {
74 for (_, item) in map {
75 print_task(item);
76 }
77 },
78 }
79 }
80}
81
82pub async fn print_dav_calendar_list<C>(cals: &HashMap<Url, Arc<Mutex<C>>>)
84where
85 C: DavCalendar,
86{
87 for (url, cal) in cals {
88 println!("CAL {} ({})", cal.lock().unwrap().name(), url);
89 match cal.lock().unwrap().get_item_version_tags().await {
90 Err(_err) => continue,
91 Ok(map) => {
92 for (url, version_tag) in map {
93 println!(" * {} (version {:?})", url, version_tag);
94 }
95 },
96 }
97 }
98}
99
100pub fn print_task(item: &Item) {
101 match item {
102 Item::Task(task) => {
103 let completion = if task.completed() { "✓" } else { " " };
104 let sync = match task.sync_status() {
105 SyncStatus::NotSynced => ".",
106 SyncStatus::Synced(_) => "=",
107 SyncStatus::LocallyModified(_) => "~",
108 SyncStatus::LocallyDeleted(_) => "x",
109 };
110 println!(" {}{} {}\t{}", completion, sync, task.name(), task.url());
111 },
112 _ => return,
113 }
114}
115
116
117pub fn keys_are_the_same<T, U, V>(left: &HashMap<T, U>, right: &HashMap<T, V>) -> bool
119where
120 T: Hash + Eq + Clone + std::fmt::Display,
121{
122 if left.len() != right.len() {
123 log::debug!("Count of keys mismatch: {} and {}", left.len(), right.len());
124 return false;
125 }
126
127 let keys_l: HashSet<T> = left.keys().cloned().collect();
128 let keys_r: HashSet<T> = right.keys().cloned().collect();
129 let result = keys_l == keys_r;
130 if result == false {
131 log::debug!("Keys of a map mismatch");
132 for key in keys_l {
133 log::debug!(" left: {}", key);
134 }
135 log::debug!("RIGHT:");
136 for key in keys_r {
137 log::debug!(" right: {}", key);
138 }
139 }
140 result
141}
142
143
144pub fn pause() {
146 let mut stdout = stdout();
147 stdout.write_all(b"Press Enter to continue...").unwrap();
148 stdout.flush().unwrap();
149 stdin().read_exact(&mut [0]).unwrap();
150}
151
152
153pub fn random_url(parent_calendar: &Url) -> Url {
155 let random = uuid::Uuid::new_v4().to_hyphenated().to_string();
156 parent_calendar.join(&random).unwrap()
157}