use crate::room4::Room4;
use std::fmt::{Debug, Display, Formatter};
use std::num::NonZeroUsize;
use std::ops::{Deref, Index, IndexMut};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RoomIndex(NonZeroUsize);
#[derive(Debug)]
pub struct Room4List<Tag = ()> {
rooms: Vec<Room4<Tag>>,
}
impl<Tag> Default for Room4List<Tag> {
fn default() -> Self {
Self { rooms: Vec::new() }
}
}
pub(crate) trait EnsureIndexConsistency<Tag> {
fn propagate_index_to_neighbors(&self, list: &mut Room4List<Tag>);
}
impl<Tag> Room4List<Tag> {
pub fn push_default(&mut self, tag: Tag) -> RoomIndex {
self.push_new(tag, |_| {})
}
pub fn push_new<F>(&mut self, tag: Tag, f: F) -> RoomIndex
where
F: FnOnce(&mut Room4<Tag>),
{
let index = RoomIndex(unsafe { NonZeroUsize::new_unchecked(self.rooms.len() + 1) });
let mut room = Room4::new_empty(index, tag);
f(&mut room);
if room.has_neighbors() {
room.propagate_index_to_neighbors(self);
}
self.rooms.push(room);
index
}
pub fn len(&self) -> usize {
self.rooms.len()
}
pub fn is_empty(&self) -> bool {
self.rooms.is_empty()
}
pub fn get(&self, index: RoomIndex) -> Option<&Room4<Tag>> {
let index = (*index).get() - 1;
self.rooms.get(index)
}
pub fn get_mut(&mut self, index: RoomIndex) -> Option<&mut Room4<Tag>> {
let index = (*index).get() - 1;
self.rooms.get_mut(index)
}
pub fn iter(&self) -> std::slice::Iter<'_, Room4<Tag>> {
self.rooms.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Room4<Tag>> {
self.rooms.iter_mut()
}
}
impl<Tag> Index<RoomIndex> for Room4List<Tag> {
type Output = Room4<Tag>;
fn index(&self, index: RoomIndex) -> &Self::Output {
let index = (*index).get() - 1;
&self.rooms[index]
}
}
impl<Tag> Index<usize> for Room4List<Tag> {
type Output = Room4<Tag>;
fn index(&self, index: usize) -> &Self::Output {
&self.rooms[index]
}
}
impl<Tag> IndexMut<RoomIndex> for Room4List<Tag> {
fn index_mut(&mut self, index: RoomIndex) -> &mut Self::Output {
let index = (*index).get() - 1;
&mut self.rooms[index]
}
}
impl<Tag> IndexMut<usize> for Room4List<Tag> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.rooms[index]
}
}
impl RoomIndex {
pub fn from(value: usize) -> Option<RoomIndex> {
if value == usize::MAX {
return None;
}
NonZeroUsize::new(value + 1).map(RoomIndex)
}
#[inline]
pub fn as_usize(self) -> usize {
self.0.get() - 1
}
}
impl Deref for RoomIndex {
type Target = NonZeroUsize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Debug for RoomIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.get() - 1)
}
}
impl Display for RoomIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
pub struct Room4ListIntoIterator<Tag> {
iter: std::vec::IntoIter<Room4<Tag>>,
}
impl<Tag> Iterator for Room4ListIntoIterator<Tag> {
type Item = Room4<Tag>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
impl<Tag> IntoIterator for Room4List<Tag> {
type Item = Room4<Tag>;
type IntoIter = Room4ListIntoIterator<Tag>;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter {
iter: self.rooms.into_iter(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_returns_some() {
let mut list = Room4List::default();
let idx_a = list.push_default("a");
let idx_b = list.push_default("b");
assert_eq!(list.get(idx_a).unwrap().tag, "a");
assert_eq!(list.get(idx_b).unwrap().tag, "b");
}
#[test]
fn index_returns_some() {
let mut list = Room4List::default();
let idx_a = list.push_default("a");
let idx_b = list.push_default("b");
assert_ne!(idx_a, idx_b);
assert_eq!(list[idx_a].tag, "a");
assert_eq!(list[idx_b].tag, "b");
assert_eq!(list[0].tag, "a");
assert_eq!(list[1].tag, "b");
}
#[test]
fn get_mut_returns_some() {
let mut list = Room4List::default();
let idx_a = list.push_default("a");
let idx_b = list.push_default("b");
assert_eq!(list.get_mut(idx_a).unwrap().tag, "a");
assert_eq!(list.get_mut(idx_b).unwrap().tag, "b");
}
#[test]
fn index_mut_returns_some() {
let mut list = Room4List::default();
let idx_a = list.push_default("a");
let idx_b = list.push_default("b");
let room_a = &mut list[idx_a];
assert_eq!(room_a.tag, "a");
let room_b = &mut list[idx_b];
assert_eq!(room_b.tag, "b");
let room_a = &mut list[0];
assert_eq!(room_a.tag, "a");
let room_b = &mut list[1];
assert_eq!(room_b.tag, "b");
}
#[test]
fn get_with_invalid_index_returns_none() {
let mut list = Room4List::default();
let _ = list.push_default("a");
let invalid_idx = RoomIndex(unsafe { NonZeroUsize::new_unchecked(2) });
assert!(list.get(invalid_idx).is_none());
}
}