use core::slice::SliceIndex;
use crate::containers::{maps::MapTrait, sets::SetTrait};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NodeState {
Unvisited,
Visiting,
Visited,
}
pub trait VisitedTracker<NI> {
fn reset(&mut self);
fn mark_visited(&mut self, node: &NI) -> Result<(), NI>;
fn is_visited(&self, node: &NI) -> bool;
fn is_unvisited(&self, node: &NI) -> bool;
}
pub trait TriStateVisitedTracker<NI>: VisitedTracker<NI> {
fn mark_visiting(&mut self, node: &NI) -> Result<(), NI>;
fn is_visiting(&self, node: &NI) -> bool;
}
impl<NI> VisitedTracker<NI> for [bool]
where
NI: SliceIndex<[bool], Output = bool> + Copy,
{
fn reset(&mut self) {
self.fill(false);
}
fn mark_visited(&mut self, node: &NI) -> Result<(), NI> {
self[*node] = true;
Ok(())
}
fn is_visited(&self, node: &NI) -> bool {
self[*node]
}
fn is_unvisited(&self, node: &NI) -> bool {
!self[*node]
}
}
impl<NI> VisitedTracker<NI> for [NodeState]
where
NI: SliceIndex<[NodeState], Output = NodeState> + Copy,
{
fn reset(&mut self) {
self.fill(NodeState::Unvisited)
}
fn mark_visited(&mut self, node: &NI) -> Result<(), NI> {
self[*node] = NodeState::Visited;
Ok(())
}
fn is_visited(&self, node: &NI) -> bool {
self[*node] == NodeState::Visited
}
fn is_unvisited(&self, node: &NI) -> bool {
self[*node] == NodeState::Unvisited
}
}
impl<NI> TriStateVisitedTracker<NI> for [NodeState]
where
NI: SliceIndex<[NodeState], Output = NodeState> + Copy,
{
fn mark_visiting(&mut self, node: &NI) -> Result<(), NI> {
self[*node] = NodeState::Visiting;
Ok(())
}
fn is_visiting(&self, node: &NI) -> bool {
self[*node] == NodeState::Visiting
}
}
pub struct SetWrapper<T>(pub T);
pub struct MapWrapper<T>(pub T);
impl<K, T> VisitedTracker<K> for SetWrapper<T>
where
T: SetTrait<K>,
K: Eq + core::hash::Hash + Copy,
NodeState: Clone,
{
fn reset(&mut self) {
self.0.clear();
}
fn mark_visited(&mut self, node: &K) -> Result<(), K> {
self.0.insert(*node).map_or_else(|_| Err(*node), |_| Ok(()))
}
fn is_visited(&self, node: &K) -> bool {
self.0.contains(node)
}
fn is_unvisited(&self, node: &K) -> bool {
!self.is_visited(node)
}
}
impl<K, T> VisitedTracker<K> for MapWrapper<T>
where
T: MapTrait<K, NodeState>,
K: Eq + core::hash::Hash + Copy,
NodeState: Clone,
{
fn reset(&mut self) {
self.0.clear();
}
fn mark_visited(&mut self, node: &K) -> Result<(), K> {
if let Some(k) = self.0.get_mut(node) {
*k = NodeState::Visited;
Ok(())
} else {
self.0
.insert(*node, NodeState::Visited)
.map_or_else(|_| Err(*node), |_| Ok(()))
}
}
fn is_visited(&self, node: &K) -> bool {
self.0.get(node).unwrap_or(&NodeState::Unvisited) == &NodeState::Visited
}
fn is_unvisited(&self, node: &K) -> bool {
self.0.get(node).unwrap_or(&NodeState::Unvisited) == &NodeState::Unvisited
}
}
impl<K, T> TriStateVisitedTracker<K> for MapWrapper<T>
where
T: MapTrait<K, NodeState>,
K: Eq + core::hash::Hash + Copy,
NodeState: Clone,
{
fn mark_visiting(&mut self, node: &K) -> Result<(), K> {
if let Some(k) = self.0.get_mut(node) {
*k = NodeState::Visiting;
Ok(())
} else {
self.0
.insert(*node, NodeState::Visiting)
.map_or_else(|_| Err(*node), |_| Ok(()))
}
}
fn is_visiting(&self, node: &K) -> bool {
self.0.get(node).unwrap_or(&NodeState::Unvisited) == &NodeState::Visiting
}
}
#[cfg(test)]
mod test {
use crate::containers::{
maps::staticdict::Dictionary,
sets::{staticset::Set, SetTrait},
};
use super::*;
fn test_visited<NI: core::fmt::Debug, T: VisitedTracker<NI> + ?Sized>(track: &mut T, n: NI) {
assert_eq!(track.is_visited(&n), false);
assert_eq!(track.is_unvisited(&n), true);
track.mark_visited(&n).unwrap();
}
fn test_reset<NI: core::fmt::Debug, T: VisitedTracker<NI> + ?Sized>(track: &mut T, n: NI) {
track.mark_visited(&n).unwrap();
assert_eq!(track.is_visited(&n), true);
track.reset();
assert_eq!(track.is_visited(&n), false);
assert_eq!(track.is_unvisited(&n), true);
}
#[test]
fn test_bool_array() {
let mut visited = [false; 8];
test_visited(visited.as_mut_slice(), 2_usize);
}
#[test]
fn test_state_array() {
let mut visited = [NodeState::Unvisited; 8];
test_visited(visited.as_mut_slice(), 2_usize);
}
#[test]
fn test_set() {
let mut visited = SetWrapper(Set::<usize, 13>::new());
test_visited(&mut visited, 2_usize);
test_reset(&mut visited, 2_usize);
}
#[test]
fn test_dict() {
let mut visited = MapWrapper(Dictionary::<usize, NodeState, 37>::new());
test_visited(&mut visited, 2_usize);
test_reset(&mut visited, 2_usize);
}
}