1use crate::room4::Room4;
2use std::fmt::{Debug, Display, Formatter};
3use std::num::NonZeroUsize;
4use std::ops::{Deref, Index, IndexMut};
5
6#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
8pub struct RoomIndex(NonZeroUsize);
9
10#[derive(Debug, Default)]
11pub struct Room4List<Tag = ()> {
12 rooms: Vec<Room4<Tag>>,
13}
14
15pub(crate) trait EnsureIndexConsistency<Tag> {
16 fn propagate_index_to_neighbors(&self, list: &mut Room4List<Tag>);
18}
19
20impl<Tag> Room4List<Tag> {
21 pub fn push_default(&mut self, tag: Tag) -> RoomIndex {
29 self.push_new(tag, |_| {})
30 }
31
32 pub fn push_new<F>(&mut self, tag: Tag, f: F) -> RoomIndex
44 where
45 F: FnOnce(&mut Room4<Tag>),
46 {
47 let index = RoomIndex(unsafe { NonZeroUsize::new_unchecked(self.rooms.len() + 1) });
51
52 let mut room = Room4::new_empty(index, tag);
53 f(&mut room);
54
55 if room.has_neighbors() {
57 room.propagate_index_to_neighbors(self);
58 }
59
60 self.rooms.push(room);
61 index
62 }
63
64 pub fn len(&self) -> usize {
66 self.rooms.len()
67 }
68
69 pub fn is_empty(&self) -> bool {
71 self.rooms.is_empty()
72 }
73
74 pub fn get(&self, index: RoomIndex) -> Option<&Room4<Tag>> {
75 let index = (*index).get() - 1;
76 self.rooms.get(index)
77 }
78
79 pub fn get_mut(&mut self, index: RoomIndex) -> Option<&mut Room4<Tag>> {
80 let index = (*index).get() - 1;
81 self.rooms.get_mut(index)
82 }
83}
84
85impl<Tag> Index<RoomIndex> for Room4List<Tag> {
86 type Output = Room4<Tag>;
87
88 fn index(&self, index: RoomIndex) -> &Self::Output {
89 let index = (*index).get() - 1;
90 &self.rooms[index]
91 }
92}
93
94impl<Tag> Index<usize> for Room4List<Tag> {
95 type Output = Room4<Tag>;
96
97 fn index(&self, index: usize) -> &Self::Output {
98 &self.rooms[index]
99 }
100}
101
102impl<Tag> IndexMut<RoomIndex> for Room4List<Tag> {
103 fn index_mut(&mut self, index: RoomIndex) -> &mut Self::Output {
104 let index = (*index).get() - 1;
105 &mut self.rooms[index]
106 }
107}
108
109impl<Tag> IndexMut<usize> for Room4List<Tag> {
110 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
111 &mut self.rooms[index]
112 }
113}
114
115impl RoomIndex {
116 pub fn from(value: usize) -> Option<RoomIndex> {
117 if value == usize::MAX {
118 return None;
119 }
120 NonZeroUsize::new(value + 1).map(RoomIndex)
121 }
122}
123
124impl Deref for RoomIndex {
125 type Target = NonZeroUsize;
126
127 fn deref(&self) -> &Self::Target {
128 &self.0
129 }
130}
131
132impl Debug for RoomIndex {
133 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134 write!(f, "{}", self.0.get() - 1)
135 }
136}
137
138impl Display for RoomIndex {
139 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140 write!(f, "{:?}", self)
141 }
142}
143
144pub struct Room4ListIntoIterator<Tag> {
145 list: Vec<Room4<Tag>>,
146}
147
148impl<Tag> Iterator for Room4ListIntoIterator<Tag> {
149 type Item = Room4<Tag>;
150
151 fn next(&mut self) -> Option<Self::Item> {
152 self.list.pop()
153 }
154}
155
156impl<Tag> IntoIterator for Room4List<Tag> {
157 type Item = Room4<Tag>;
158 type IntoIter = Room4ListIntoIterator<Tag>;
159
160 fn into_iter(self) -> Self::IntoIter {
161 Self::IntoIter { list: self.rooms }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn get_returns_some() {
171 let mut list = Room4List::default();
172 let idx_a = list.push_default("a");
173 let idx_b = list.push_default("b");
174 assert_eq!(list.get(idx_a).unwrap().tag, "a");
175 assert_eq!(list.get(idx_b).unwrap().tag, "b");
176 }
177
178 #[test]
179 fn index_returns_some() {
180 let mut list = Room4List::default();
181 let idx_a = list.push_default("a");
182 let idx_b = list.push_default("b");
183 assert_ne!(idx_a, idx_b);
184
185 assert_eq!(list[idx_a].tag, "a");
187 assert_eq!(list[idx_b].tag, "b");
188
189 assert_eq!(list[0].tag, "a");
191 assert_eq!(list[1].tag, "b");
192 }
193
194 #[test]
195 fn get_mut_returns_some() {
196 let mut list = Room4List::default();
197 let idx_a = list.push_default("a");
198 let idx_b = list.push_default("b");
199 assert_eq!(list.get_mut(idx_a).unwrap().tag, "a");
200 assert_eq!(list.get_mut(idx_b).unwrap().tag, "b");
201 }
202
203 #[test]
204 fn index_mut_returns_some() {
205 let mut list = Room4List::default();
206 let idx_a = list.push_default("a");
207 let idx_b = list.push_default("b");
208
209 let room_a = &mut list[idx_a];
211 assert_eq!(room_a.tag, "a");
212 let room_b = &mut list[idx_b];
213 assert_eq!(room_b.tag, "b");
214
215 let room_a = &mut list[0];
217 assert_eq!(room_a.tag, "a");
218 let room_b = &mut list[1];
219 assert_eq!(room_b.tag, "b");
220 }
221
222 #[test]
223 fn get_with_invalid_index_returns_none() {
224 let mut list = Room4List::default();
225 let _ = list.push_default("a");
226
227 let invalid_idx = RoomIndex(unsafe { NonZeroUsize::new_unchecked(2) });
228 assert!(list.get(invalid_idx).is_none());
229 }
230}