1use regex::Regex;
2use std::collections::hash_map::{Iter, Values};
3use std::collections::HashMap;
4use std::fmt::Debug;
5use std::hash::Hash;
6use std::rc::Rc;
7
8use crate::error::LedgerError;
9use crate::models::{FromDirective, HasAliases, HasName};
10
11#[derive(Debug, Clone)]
22pub struct List<T> {
23 aliases: HashMap<String, String>,
24 list: HashMap<String, Rc<T>>,
25 matches: HashMap<String, Option<String>>,
26}
27impl<'a, T: Eq + Hash + HasName + Clone + FromDirective + HasAliases + Debug> Default for List<T> {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32impl<'a, T: Eq + Hash + HasName + Clone + FromDirective + HasAliases + Debug> List<T> {
33 pub fn new() -> Self {
34 let aliases: HashMap<String, String> = HashMap::new();
35 let list: HashMap<String, Rc<T>> = HashMap::new();
36 let matches: HashMap<String, Option<String>> = HashMap::new();
37 List {
38 aliases,
39 list,
40 matches,
41 }
42 }
43
44 pub fn insert(&mut self, element: T) {
46 let found = self.list.get(&element.get_name().to_lowercase());
47 match found {
48 Some(_) => eprintln!("Duplicate element: {:?}", element), None => {
50 let name = element.get_name().to_string().to_lowercase();
52 for alias in element.get_aliases().iter() {
53 self.aliases.insert(alias.to_lowercase(), name.clone());
54 }
55 self.list.insert(name, Rc::new(element));
56 }
57 }
58 }
59 pub fn remove(&mut self, element: &T) {
61 let found = self.list.get(&element.get_name().to_lowercase());
62 match found {
63 Some(x) => {
64 for alias in x.get_aliases() {
65 self.aliases.remove(&alias.to_lowercase());
66 }
67 self.list.remove(&element.get_name().to_lowercase());
68 }
69 None => {
70 for alias in element.get_aliases() {
71 let value = self.aliases.remove(&alias.to_lowercase());
72 if let Some(x) = value {
73 self.list.remove(&x);
74 }
75 self.list.remove(&alias.to_lowercase());
76 }
77 }
78 }
79 }
80 pub fn add_alias(&mut self, alias: String, for_element: &'a T) {
82 let element = self.aliases.get(&alias.to_lowercase());
83 match element {
84 Some(x) => panic!(
85 "Repeated alias {} for {} and {}",
86 alias,
87 for_element.get_name(),
88 x
89 ),
90 None => {
91 self.aliases
92 .insert(alias.to_lowercase(), for_element.get_name().to_lowercase());
93 }
94 }
95 }
96
97 pub fn get(&self, index: &str) -> Result<&Rc<T>, LedgerError> {
98 match self.list.get(&index.to_lowercase()) {
99 None => match self.aliases.get(&index.to_lowercase()) {
100 None => Err(LedgerError::AliasNotInList(format!(
101 "{} {:?} not found",
102 std::any::type_name::<T>(),
103 index
104 ))),
105 Some(x) => Ok(self.list.get(x).unwrap()),
106 },
107 Some(x) => Ok(x),
108 }
109 }
110 pub fn get_regex(&mut self, regex: Regex) -> Option<&Rc<T>> {
112 let alias = self.matches.get(regex.as_str());
113 match alias {
114 Some(x) => match x {
115 Some(alias) => Some(self.get(alias).unwrap()),
116 None => None,
117 },
118 None => {
119 for (_alias, value) in self.list.iter() {
121 if regex.is_match(value.get_name()) {
122 self.matches
123 .insert(regex.as_str().to_string(), Some(_alias.clone()));
124 return Some(value);
125 }
126 }
127 for (alias, value) in self.aliases.iter() {
128 if regex.is_match(alias) {
129 self.matches
130 .insert(regex.as_str().to_string(), Some(value.clone()));
131 return self.list.get(value);
132 }
133 }
134 self.matches.insert(regex.as_str().to_string(), None);
135 None
136 }
137 }
138 }
142
143 pub fn iter(&self) -> Iter<'_, String, Rc<T>> {
144 self.list.iter()
145 }
146 pub fn values(&self) -> Values<'_, String, Rc<T>> {
147 self.list.values()
148 }
149 pub fn len(&self) -> usize {
150 self.list.len()
151 }
152 pub fn is_empty(&self) -> bool {
153 self.list.is_empty()
154 }
155 pub fn len_alias(&self) -> usize {
156 self.aliases.len() + self.len()
157 }
158}
159
160impl<T: Clone + FromDirective + HasAliases + Debug + Eq + Hash + HasName> List<T> {
161 pub fn append(&mut self, other: &List<T>) {
162 for (key, value) in other.list.iter() {
163 if value.is_from_directive() {
164 self.list.insert(key.clone(), value.clone());
165 for alias in value.get_aliases().iter() {
166 self.aliases.insert(alias.to_lowercase(), key.clone());
167 }
168 } else if self.get(key).is_err() {
169 self.list.insert(key.clone(), value.clone());
170 }
171 }
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::models::Payee;
179 use regex::Regex;
180 #[test]
181 fn list() {
182 let name = "ACME Inc.";
183 let payee = Payee::from(name);
184 let mut list: List<Payee> = List::new();
185 list.insert(payee.clone());
186
187 let pattern = Regex::new("ACME").unwrap();
189 let retrieved = list.get_regex(pattern);
190
191 assert!(retrieved.is_some());
192 assert_eq!(retrieved.unwrap().get_name(), "ACME Inc.");
193 assert_eq!(list.len_alias(), 1);
194
195 list.add_alias("ACME is awesome".to_string(), &payee);
197 assert_eq!(list.len_alias(), 2);
198
199 assert!(list.get_regex(Regex::new("Warner").unwrap()).is_none());
201 assert!(list.get("Warner").is_err());
202 assert!(list.get_regex(Regex::new("awesome").unwrap()).is_some());
203 }
204 #[test]
205 #[should_panic]
206 fn list_repeated_alias() {
207 let mut list: List<Payee> = List::new();
208 list.insert(Payee::from("ACME"));
209 for _ in 0..2 {
210 let retrieved = list.get("ACME").unwrap().clone();
211 list.add_alias("ACME, Inc.".to_string(), &retrieved)
212 }
213 }
214}