legion_core/
permission.rs1use smallvec::SmallVec;
2use std::fmt::{Debug, Display};
3
4#[derive(Clone)]
5pub struct Permissions<T: PartialEq> {
6 items: SmallVec<[T; 4]>,
7 shared: usize, write: usize, }
10
11impl<T: PartialEq> Permissions<T> {
12 pub fn new() -> Self {
13 Self {
14 items: SmallVec::default(),
15 shared: 0,
16 write: 0,
17 }
18 }
19
20 fn find(&self, item: &T) -> Option<usize> { self.items.iter().position(|x| x == item) }
21
22 pub fn push(&mut self, item: T) {
23 if let Some(index) = self.find(&item) {
24 if index < self.shared {
25 self.items.swap(index, self.shared - 1);
27 self.shared -= 1;
28 } else if index > self.write {
29 self.items.swap(index, self.write);
31 self.write += 1;
32 }
33 } else {
34 self.items.push(item);
36
37 let index = self.items.len() - 1;
39 self.items.swap(index, self.write);
40 self.write += 1;
41 }
42 }
43
44 pub fn push_read(&mut self, item: T) {
45 if let Some(index) = self.find(&item) {
46 if index >= self.write {
48 self.items.swap(index, self.write);
51 self.write += 1;
52 }
53 } else {
54 self.items.push(item);
56 let index = self.items.len() - 1;
57
58 self.items.swap(index, self.write);
60
61 self.items.swap(self.write, self.shared);
63
64 self.write += 1;
66 self.shared += 1;
67 }
68 }
69
70 pub fn push_write(&mut self, item: T) {
71 if let Some(index) = self.find(&item) {
72 if index < self.shared {
73 self.items.swap(index, self.shared - 1);
75 self.shared -= 1;
76 }
77 } else {
78 self.items.push(item);
80 }
81 }
82
83 pub fn remove(&mut self, item: &T) {
84 if let Some(mut index) = self.find(item) {
85 if index < self.shared {
86 self.items.swap(index, self.shared - 1);
88 self.shared -= 1;
89 index = self.shared;
90 }
91
92 if index < self.write {
93 self.items.swap(index, self.write - 1);
95 self.write -= 1;
96 index = self.write;
97 }
98
99 self.items.swap_remove(index);
100 }
101 }
102
103 pub fn remove_read(&mut self, item: &T) {
104 if let Some(index) = self.find(item) {
105 if index < self.shared {
106 self.items.swap(index, self.shared - 1);
108 self.shared -= 1;
109
110 self.items.swap(self.shared, self.write - 1);
112 self.write -= 1;
113
114 self.items.swap_remove(self.write);
116 } else if index < self.write {
117 self.items.swap(index, self.write - 1);
119 self.write -= 1;
120 }
121 }
122 }
123
124 pub fn remove_write(&mut self, item: &T) {
125 if let Some(index) = self.find(item) {
126 if index >= self.write {
127 self.items.swap_remove(index);
129 } else if index >= self.shared {
130 self.items.swap(index, self.shared);
132 self.shared += 1;
133 }
134 }
135 }
136
137 pub fn add(&mut self, mut other: Self) {
138 for read in other.items.drain(..other.shared) {
139 self.push_read(read);
140 }
141
142 for shared in other.items.drain(..(other.write - other.shared)) {
143 self.push(shared);
144 }
145
146 for write in other.items.drain(..) {
147 self.push_write(write);
148 }
149 }
150
151 pub fn subtract(&mut self, other: &Self) {
152 for read in other.read_only() {
153 self.remove_read(read);
154 }
155
156 for shared in other.readwrite() {
157 self.remove(shared);
158 }
159
160 for write in other.write_only() {
161 self.remove_write(write);
162 }
163 }
164
165 pub fn reads(&self) -> &[T] { &self.items[..self.write] }
166
167 pub fn writes(&self) -> &[T] { &self.items[self.shared..] }
168
169 pub fn read_only(&self) -> &[T] { &self.items[..self.shared] }
170
171 pub fn write_only(&self) -> &[T] { &self.items[self.write..] }
172
173 pub fn readwrite(&self) -> &[T] { &self.items[self.shared..self.write] }
174
175 pub fn is_superset(&self, other: &Self) -> bool {
176 for read in other.read_only() {
177 if self.find(read).map(|i| i >= self.write).unwrap_or(true) {
179 return false;
180 }
181 }
182
183 for shared in other.readwrite() {
184 if self
186 .find(shared)
187 .map(|i| i < self.shared || i >= self.write)
188 .unwrap_or(true)
189 {
190 return false;
191 }
192 }
193
194 for write in other.write_only() {
195 if self.find(write).map(|i| i < self.shared).unwrap_or(true) {
197 return false;
198 }
199 }
200
201 true
202 }
203
204 pub fn is_disjoint(&self, other: &Self) -> bool {
205 for read in other.read_only() {
206 if self.find(read).map(|i| i < self.write).unwrap_or(false) {
208 return false;
209 }
210 }
211
212 for shared in other.readwrite() {
213 if self.find(shared).is_some() {
215 return false;
216 }
217 }
218
219 for write in other.write_only() {
220 if self.find(write).map(|i| i >= self.shared).unwrap_or(false) {
222 return false;
223 }
224 }
225
226 true
227 }
228}
229
230impl<T: PartialEq> Default for Permissions<T> {
231 fn default() -> Self { Self::new() }
232}
233
234impl<T: PartialEq + Debug> Debug for Permissions<T> {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 fn list<V: Debug>(items: &[V]) -> String {
237 use itertools::Itertools;
238 items
239 .iter()
240 .map(|x| format!("{:?}", x))
241 .fold1(|x, y| format!("{}, {}", x, y))
242 .unwrap_or_else(|| "".to_owned())
243 }
244
245 write!(
246 f,
247 "Permissions {{ reads: [{}], writes: [{}] }}",
248 list::<T>(&self.reads()),
249 list::<T>(&self.writes())
250 )
251 }
252}
253
254impl<T: PartialEq + Display> Display for Permissions<T> {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 fn list<V: Display>(items: &[V]) -> String {
257 use itertools::Itertools;
258 items
259 .iter()
260 .map(|x| format!("{}", x))
261 .fold1(|x, y| format!("{}, {}", x, y))
262 .unwrap_or_else(|| "".to_owned())
263 }
264
265 write!(
266 f,
267 "reads: [{}], writes: [{}]",
268 list::<T>(&self.reads()),
269 list::<T>(&self.writes())
270 )
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::Permissions;
277
278 #[test]
279 fn push_read() {
280 let mut permissions = Permissions::new();
281 permissions.push_read(1usize);
282
283 let empty: &[usize] = &[];
284 assert_eq!(permissions.read_only(), &[1usize]);
285 assert_eq!(permissions.readwrite(), empty);
286 assert_eq!(permissions.write_only(), empty);
287 }
288
289 #[test]
290 fn push_write() {
291 let mut permissions = Permissions::new();
292 permissions.push_write(1usize);
293
294 let empty: &[usize] = &[];
295 assert_eq!(permissions.read_only(), empty);
296 assert_eq!(permissions.readwrite(), empty);
297 assert_eq!(permissions.write_only(), &[1usize]);
298 }
299
300 #[test]
301 fn push_both() {
302 let mut permissions = Permissions::new();
303 permissions.push(1usize);
304
305 let empty: &[usize] = &[];
306 assert_eq!(permissions.read_only(), empty);
307 assert_eq!(permissions.readwrite(), &[1usize]);
308 assert_eq!(permissions.write_only(), empty);
309 }
310
311 #[test]
312 fn promote_read_to_readwrite() {
313 let mut permissions = Permissions::new();
314 permissions.push_read(1usize);
315 permissions.push_write(1usize);
316
317 let empty: &[usize] = &[];
318 assert_eq!(permissions.read_only(), empty);
319 assert_eq!(permissions.readwrite(), &[1usize]);
320 assert_eq!(permissions.write_only(), empty);
321 }
322
323 #[test]
324 fn promote_write_to_readwrite() {
325 let mut permissions = Permissions::new();
326 permissions.push_write(1usize);
327 permissions.push_read(1usize);
328
329 let empty: &[usize] = &[];
330 assert_eq!(permissions.read_only(), empty);
331 assert_eq!(permissions.readwrite(), &[1usize]);
332 assert_eq!(permissions.write_only(), empty);
333 }
334
335 #[test]
336 fn remove_write() {
337 let mut permissions = Permissions::new();
338 permissions.push_write(1usize);
339 permissions.remove_write(&1usize);
340
341 let empty: &[usize] = &[];
342 assert_eq!(permissions.read_only(), empty);
343 assert_eq!(permissions.readwrite(), empty);
344 assert_eq!(permissions.write_only(), empty);
345 }
346
347 #[test]
348 fn remove_read() {
349 let mut permissions = Permissions::new();
350 permissions.push_read(1usize);
351 permissions.remove_read(&1usize);
352
353 let empty: &[usize] = &[];
354 assert_eq!(permissions.read_only(), empty);
355 assert_eq!(permissions.readwrite(), empty);
356 assert_eq!(permissions.write_only(), empty);
357 }
358
359 #[test]
360 fn demote_readwrite_to_read() {
361 let mut permissions = Permissions::new();
362 permissions.push(1usize);
363 permissions.remove_write(&1usize);
364
365 let empty: &[usize] = &[];
366 assert_eq!(permissions.read_only(), &[1usize]);
367 assert_eq!(permissions.readwrite(), empty);
368 assert_eq!(permissions.write_only(), empty);
369 }
370
371 #[test]
372 fn demote_readwrite_to_write() {
373 let mut permissions = Permissions::new();
374 permissions.push(1usize);
375 permissions.remove_read(&1usize);
376
377 let empty: &[usize] = &[];
378 assert_eq!(permissions.read_only(), empty);
379 assert_eq!(permissions.readwrite(), empty);
380 assert_eq!(permissions.write_only(), &[1usize]);
381 }
382}