oxihuman_core/
linked_map.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
8
9#[derive(Debug, Clone)]
11#[allow(dead_code)]
12pub struct LinkedMap<V> {
13 keys: Vec<String>,
14 map: HashMap<String, V>,
15}
16
17#[allow(dead_code)]
19pub fn new_linked_map<V>() -> LinkedMap<V> {
20 LinkedMap {
21 keys: Vec::new(),
22 map: HashMap::new(),
23 }
24}
25
26#[allow(dead_code)]
28pub fn lmap_insert<V>(lm: &mut LinkedMap<V>, key: &str, val: V) {
29 if !lm.map.contains_key(key) {
30 lm.keys.push(key.to_string());
31 }
32 lm.map.insert(key.to_string(), val);
33}
34
35#[allow(dead_code)]
37pub fn lmap_get<'a, V>(lm: &'a LinkedMap<V>, key: &str) -> Option<&'a V> {
38 lm.map.get(key)
39}
40
41#[allow(dead_code)]
43pub fn lmap_get_mut<'a, V>(lm: &'a mut LinkedMap<V>, key: &str) -> Option<&'a mut V> {
44 lm.map.get_mut(key)
45}
46
47#[allow(dead_code)]
49pub fn lmap_remove<V>(lm: &mut LinkedMap<V>, key: &str) -> Option<V> {
50 if let Some(val) = lm.map.remove(key) {
51 lm.keys.retain(|k| k != key);
52 Some(val)
53 } else {
54 None
55 }
56}
57
58#[allow(dead_code)]
60pub fn lmap_contains<V>(lm: &LinkedMap<V>, key: &str) -> bool {
61 lm.map.contains_key(key)
62}
63
64#[allow(dead_code)]
66pub fn lmap_len<V>(lm: &LinkedMap<V>) -> usize {
67 lm.map.len()
68}
69
70#[allow(dead_code)]
72pub fn lmap_is_empty<V>(lm: &LinkedMap<V>) -> bool {
73 lm.map.is_empty()
74}
75
76#[allow(dead_code)]
78pub fn lmap_keys<V>(lm: &LinkedMap<V>) -> &[String] {
79 &lm.keys
80}
81
82#[allow(dead_code)]
84pub fn lmap_values<V>(lm: &LinkedMap<V>) -> Vec<&V> {
85 lm.keys.iter().filter_map(|k| lm.map.get(k)).collect()
86}
87
88#[allow(dead_code)]
90pub fn lmap_clear<V>(lm: &mut LinkedMap<V>) {
91 lm.keys.clear();
92 lm.map.clear();
93}
94
95#[allow(dead_code)]
97pub fn lmap_get_at<V>(lm: &LinkedMap<V>, pos: usize) -> Option<(&str, &V)> {
98 lm.keys
99 .get(pos)
100 .and_then(|k| lm.map.get(k).map(|v| (k.as_str(), v)))
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_insert_get() {
109 let mut lm: LinkedMap<u32> = new_linked_map();
110 lmap_insert(&mut lm, "a", 1);
111 assert_eq!(lmap_get(&lm, "a"), Some(&1));
112 }
113
114 #[test]
115 fn test_order_preserved() {
116 let mut lm: LinkedMap<u32> = new_linked_map();
117 lmap_insert(&mut lm, "c", 3);
118 lmap_insert(&mut lm, "a", 1);
119 lmap_insert(&mut lm, "b", 2);
120 assert_eq!(lmap_keys(&lm), &["c", "a", "b"]);
121 }
122
123 #[test]
124 fn test_update_no_reorder() {
125 let mut lm: LinkedMap<u32> = new_linked_map();
126 lmap_insert(&mut lm, "x", 1);
127 lmap_insert(&mut lm, "y", 2);
128 lmap_insert(&mut lm, "x", 99);
129 assert_eq!(lmap_keys(&lm), &["x", "y"]);
130 assert_eq!(lmap_get(&lm, "x"), Some(&99));
131 }
132
133 #[test]
134 fn test_remove() {
135 let mut lm: LinkedMap<u32> = new_linked_map();
136 lmap_insert(&mut lm, "a", 1);
137 lmap_insert(&mut lm, "b", 2);
138 assert_eq!(lmap_remove(&mut lm, "a"), Some(1));
139 assert_eq!(lmap_keys(&lm), &["b"]);
140 }
141
142 #[test]
143 fn test_contains() {
144 let mut lm: LinkedMap<u32> = new_linked_map();
145 lmap_insert(&mut lm, "k", 0);
146 assert!(lmap_contains(&lm, "k"));
147 assert!(!lmap_contains(&lm, "z"));
148 }
149
150 #[test]
151 fn test_len_and_empty() {
152 let mut lm: LinkedMap<u32> = new_linked_map();
153 assert!(lmap_is_empty(&lm));
154 lmap_insert(&mut lm, "a", 1);
155 assert_eq!(lmap_len(&lm), 1);
156 }
157
158 #[test]
159 fn test_values_ordered() {
160 let mut lm: LinkedMap<u32> = new_linked_map();
161 lmap_insert(&mut lm, "a", 10);
162 lmap_insert(&mut lm, "b", 20);
163 assert_eq!(lmap_values(&lm), vec![&10, &20]);
164 }
165
166 #[test]
167 fn test_get_at() {
168 let mut lm: LinkedMap<u32> = new_linked_map();
169 lmap_insert(&mut lm, "first", 1);
170 lmap_insert(&mut lm, "second", 2);
171 let (k, v) = lmap_get_at(&lm, 1).expect("should succeed");
172 assert_eq!(k, "second");
173 assert_eq!(*v, 2);
174 }
175
176 #[test]
177 fn test_clear() {
178 let mut lm: LinkedMap<u32> = new_linked_map();
179 lmap_insert(&mut lm, "a", 1);
180 lmap_clear(&mut lm);
181 assert!(lmap_is_empty(&lm));
182 }
183}