circular_resources/
lib.rs

1//! UNTESTED code.
2//!
3//! TODO: docs
4
5use std::collections::HashMap;
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8pub struct PositionID(u64);
9
10impl PositionID {
11    pub const ZERO: PositionID = PositionID(0);
12}
13
14pub struct Circular<T> {
15    vec: Vec<T>,
16    positions: HashMap<PositionID, Option<usize>>,
17    next_pos_id: PositionID,
18}
19
20/// We have a vector and "position" therein.
21///
22/// TODO: More tests.
23impl<T> Circular<T> {
24    pub fn new() -> Self {
25        Self {
26            vec: Vec::new(),
27            positions: HashMap::new(),
28            next_pos_id: PositionID(0),
29        }
30    }
31    fn my_assert(&self) {
32        for p in self.positions.values() {
33            debug_assert!(p.is_none() || p.unwrap() < self.len())
34        }
35    }
36    pub fn vec(&self) -> &Vec<T> {
37        &self.vec
38    }
39    pub fn push(&mut self, value: T) {
40        self.vec.push(value)
41    }
42    pub fn append(&mut self, other: &mut Vec<T>) {
43        self.vec.append(other);
44        self.my_assert();
45    }
46    pub fn remove_unsafe(&mut self, index: usize) -> T {
47        assert!(index < self.len());
48        self.my_assert();
49        let result = self.vec.remove(index);
50        let new_len = self.len();
51        let empty = self.is_empty();
52        for position in self.positions.values_mut() {
53            if empty {
54                *position = None;
55            } else if let Some(ref mut pos) = *position {
56                if *pos > index {
57                    *pos -= 1;
58                } else if *pos == new_len {
59                    *pos = 0;
60                }
61            }
62        }
63        self.my_assert();
64        result
65    }
66    pub fn remove_by_pos_id(&mut self, pos_id: PositionID) -> Option<T> {
67        if let Some(pos) = self.positions[&pos_id] {
68            self.my_assert();
69            Some(self.remove_unsafe(pos))
70        } else {
71            self.my_assert();
72            None
73        }
74    }
75
76    pub fn is_empty(&self) -> bool {
77        self.vec.is_empty()
78    }
79    pub fn len(&self) -> usize {
80        self.vec.len()
81    }
82
83    pub fn positions_is_empty(&self) -> bool {
84        self.positions.is_empty()
85    }
86    pub fn positions_len(&self) -> usize {
87        self.positions.len()
88    }
89
90    pub fn iter(&self) -> std::slice::Iter<T> {
91        self.vec.iter()
92    }
93    pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
94        self.vec.iter_mut()
95    }
96    pub fn create_position(&mut self) -> PositionID {
97        let result = self.next_pos_id;
98        self.positions.insert(self.next_pos_id, None);
99        self.next_pos_id.0 += 1;
100        self.my_assert();
101        result
102    }
103    pub fn destroy_position(&mut self, pos_id: PositionID) {
104        self.positions.remove(&pos_id);
105        self.my_assert();
106    }
107    pub fn get_position(&self, pos_id: PositionID) -> &Option<usize> {
108        &self.positions[&pos_id]
109    }
110    pub fn set_position_unsafe(&mut self, pos_id: PositionID, index: Option<usize>) {
111        self.positions.insert(pos_id, index);
112        self.my_assert();
113    }
114    pub fn get_by_pos_id(&self, pos_id: PositionID) -> Option<&T> {
115        self.positions[&pos_id].map(|pos| &self.vec[pos])
116    }
117    pub fn get_by_pos_id_mut(&mut self, pos_id: PositionID) -> Option<&mut T> {
118        self.positions[&pos_id].map(|pos| &mut self.vec[pos])
119    }
120    /// If current is `None` tries to set it to `Some`.
121    pub fn force_get_by_pos_id_mut(&mut self, pos_id: PositionID) -> Option<&mut T> {
122        if let Some(pos) = self.positions[&pos_id] {
123            self.my_assert();
124            Some(&mut self.vec[pos])
125        } else {
126            self.init_position(pos_id)
127        }
128    }
129    pub fn clear(&mut self) {
130        self.vec.clear();
131        for p in self.positions.values_mut() {
132            *p = None;
133        }
134        self.my_assert();
135    }
136
137    pub fn next(&mut self, pos_id: PositionID) -> Option<&T> {
138        let pos = self.positions[&pos_id];
139        if let Some(pos) = pos {
140            self.positions.insert(pos_id, Some(if pos + 1 == self.vec.len() {
141                0
142            } else {
143                pos + 1
144            }));
145            debug_assert!(pos < self.vec.len());
146            Some(&self.vec[pos.clone()])
147        } else {
148            self.init_position(pos_id).map(|r| &*r)
149        }
150    }
151    fn init_position(&mut self, pos_id: PositionID) -> Option<&mut T> {
152        if self.vec.is_empty() {
153            self.positions.insert(pos_id, None);
154            self.my_assert();
155            None
156        } else {
157            self.positions.insert(pos_id, Some(0));
158            self.my_assert();
159            Some(&mut self.vec[0])
160        }
161    }
162}
163
164/// Tests do not pass.
165#[cfg(test)]
166mod tests {
167    use crate::{Circular};
168
169    #[test]
170    fn one_position_middle() {
171        let mut v = Circular::new();
172        let mut input = (0..10).collect::<Vec<i32>>();
173        v.append(&mut input);
174        v.set_position_unsafe(Some(5));
175        v.remove_current();
176        assert_eq!(v.iter().map(|n| *n).collect::<Vec<i32>>(), vec![0, 1, 2, 3, 4, 6, 7, 8, 9]);
177        assert_eq!(v.get_position(), Some(5));
178    }
179}