1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4#[derive(Default, Debug)]
5pub struct Locks {
6 hashmap: Arc<Mutex<HashMap<String, RWLock>>>,
11}
12
13#[derive(Debug, PartialOrd, PartialEq)]
14enum RWLock {
15 Read(usize),
16 Write,
17}
18
19impl Locks {
20 pub fn new() -> Locks {
21 Locks {
22 hashmap: Arc::new(Mutex::new(HashMap::new())),
23 }
24 }
25
26 pub fn read_lock(&mut self, key: &str) {
27 loop {
30 let mut hashmap = self.hashmap.lock().unwrap();
31
32 if let Some(lock) = hashmap.get_mut(key) {
33 match lock {
34 RWLock::Read(count) => *count += 1,
35 RWLock::Write => continue,
36 };
37 break;
38 } else {
39 hashmap.insert(key.to_owned(), RWLock::Read(1));
40 break;
41 }
42 }
43 }
44
45 pub fn read_unlock(&mut self, key: &str) {
46 let mut hashmap = self.hashmap.lock().unwrap();
50
51 if let Some(lock) = hashmap.get_mut(key) {
52 match lock {
53 RWLock::Read(count) => {
54 *count -= 1;
55 if *count == 0 {
56 hashmap.remove(key);
57 }
58 }
59 RWLock::Write => panic!("Attempting to release write lock"),
60 };
61 } else {
62 panic!("not found read lock")
63 }
64 }
65
66 pub fn write_lock(&mut self, key: &str) {
67 loop {
69 let mut hashmap = self.hashmap.lock().unwrap();
70
71 if let Some(lock) = hashmap.get_mut(key) {
72 match lock {
73 RWLock::Read(0) => {
74 hashmap.insert(key.to_owned(), RWLock::Write);
75 break;
76 }
77 _ => continue,
78 };
79 } else {
80 hashmap.insert(key.to_owned(), RWLock::Write);
81 break;
82 }
83 }
84 }
85
86 pub fn write_unlock(&mut self, key: &str) {
87 let mut hashmap = self.hashmap.lock().unwrap();
91
92 if let Some(lock) = hashmap.get_mut(key) {
93 match lock {
94 RWLock::Write => hashmap.remove(key),
95 RWLock::Read(_) => panic!("Attempting to release read lock"),
96 };
97 } else {
98 panic!("not found write lock")
99 }
100 }
101}
102
103#[test]
104fn test_read_lock() {
105 let mut locks = Locks::new();
106
107 let key = "key";
108
109 locks.read_lock(key);
110 locks.read_lock(key);
111 locks.read_lock(key);
112 locks.read_lock(key);
113
114 let hashmap = locks.hashmap.lock().unwrap();
115 let lock = hashmap.get(key).unwrap();
116
117 assert_eq!(lock, &RWLock::Read(4));
118}
119
120#[test]
121fn test_read_unlock() {
122 let mut locks = Locks::new();
123
124 let key = "key";
125
126 locks.read_lock(key);
127 locks.read_unlock(key);
128
129 let hashmap = locks.hashmap.lock().unwrap();
130 assert!(hashmap.get(key).is_none());
131}
132
133#[test]
134fn test_write_lock() {
135 let mut locks = Locks::new();
136
137 let key = "key";
138
139 locks.write_lock(key);
140
141 let hashmap = locks.hashmap.lock().unwrap();
142 let lock = hashmap.get(key).unwrap();
143
144 assert_eq!(lock, &RWLock::Write);
145}
146
147#[test]
148fn test_write_unlock() {
149 let mut locks = Locks::new();
150
151 let key = "key";
152
153 locks.write_lock(key);
154 locks.write_unlock(key);
155
156 let hashmap = locks.hashmap.lock().unwrap();
157 assert!(hashmap.get(key).is_none());
158}
159
160#[test]
161#[should_panic]
162fn test_write_unlock_panic_when_not_found_key() {
163 let mut locks = Locks::new();
164
165 locks.write_unlock("not found key");
166}
167
168#[test]
169#[should_panic]
170fn test_write_unlock_panic_when_read_lock() {
171 let mut locks = Locks::new();
172
173 locks.read_lock("key");
174 locks.write_unlock("key");
175}
176
177#[test]
178#[should_panic]
179fn test_read_unlock_panic_when_not_found_key() {
180 let mut locks = Locks::new();
181
182 locks.read_unlock("not found key");
183}
184
185#[test]
186#[should_panic]
187fn test_write_unlock_panic_when_write_lock() {
188 let mut locks = Locks::new();
189
190 locks.write_lock("key");
191 locks.read_unlock("key");
192}