use std::collections::VecDeque;
use crate::slot::Slot;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(PartialEq, Debug, Clone, Eq, Hash, Serialize, Deserialize)]
pub struct Path {
slots: VecDeque<Slot>,
}
#[macro_export]
macro_rules! path {
($($x:expr),*) => {{
let mut temp_vec = vec![$($x),*];
temp_vec.reverse();
Path::from(temp_vec)
}};
}
impl Path {
pub fn new() -> Self {
Self { slots: vec![].into() }
}
pub fn push(&mut self, slot: Slot) {
self.slots.push_front(slot);
}
pub fn pull(&mut self) -> Option<Slot> {
self.slots.pop_front()
}
pub fn is_root(&self) -> bool {
self.slots.is_empty()
}
pub fn matches(&self, p: &Path) -> bool {
self == p
}
pub fn head(&self) -> Option<&Slot> {
self.slots.front()
}
}
impl Default for Path {
fn default() -> Self {
Self::new()
}
}
impl From<Vec<Slot>> for Path {
fn from(slots: Vec<Slot>) -> Self {
let mut reversed_slots = slots;
reversed_slots.reverse();
Self {
slots: reversed_slots.into(),
}
}
}
impl Display for Path {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "P://")?;
for (i, slot) in self.slots.iter().enumerate() {
if i != 0 {
write!(f, "/")?;
}
write!(f, "{}", slot)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::slot::Slot::*;
#[test]
fn test_is_root() {
let empty_path = Path::from(Vec::new());
let not_empty_path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
assert!(empty_path.is_root());
assert!(!not_empty_path.is_root())
}
#[test]
fn test_not_empty_head() {
let path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
assert_eq!(path.head().unwrap(), &Branch(0))
}
#[test]
fn test_empty_head() {
let path = Path::new();
assert!(path.head().is_none())
}
#[test]
fn test_push() {
let mut path = path![Nbr(1), Nbr(0), Rep(0)];
path.push(Branch(0));
assert_eq!(path, path![Branch(0), Nbr(1), Nbr(0), Rep(0)])
}
#[test]
fn test_not_empty_pull() {
let mut path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
path.pull();
assert_eq!(path.slots, vec![Nbr(1), Nbr(0), Rep(0)])
}
#[test]
fn test_empty_pull() {
let mut path = Path::new();
assert!(path.pull().is_none());
}
#[test]
fn test_to_str() {
let path = path![Branch(0), Nbr(1), Nbr(0), Rep(0)];
assert_eq!(path.to_string(), "P://Branch(0)/Nbr(1)/Nbr(0)/Rep(0)")
}
#[test]
fn test_matches() {
let path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
assert!(path.matches(&Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)])));
assert!(!path.matches(&Path::from(vec![Nbr(0), Nbr(1), Branch(0)])))
}
#[test]
fn test_serialize_and_deserialize() {
let path = path!(Rep(0), FoldHood(0), Nbr(0), Nbr(1));
let path_str = serde_json::to_string(&path).unwrap();
let path_des = serde_json::from_str(&path_str).unwrap();
assert_eq!(path, path_des);
}
}