rf_core/
path.rs

1use std::collections::VecDeque;
2use crate::slot::Slot;
3use serde::{Deserialize, Serialize};
4use std::fmt::{Display, Formatter};
5
6/// A Path is a collection of Slots that behave like an immutable stack
7#[derive(PartialEq, Debug, Clone, Eq, Hash, Serialize, Deserialize)]
8pub struct Path {
9    slots: VecDeque<Slot>,
10}
11
12#[macro_export]
13macro_rules! path {
14        ($($x:expr),*) => {{
15            let mut temp_vec = vec![$($x),*];
16            temp_vec.reverse();
17            Path::from(temp_vec)
18        }};
19    }
20
21impl Path {
22    /// Factory method to create a new Path
23    ///
24    /// # Returns
25    ///
26    /// A new Path
27    pub fn new() -> Self {
28        Self { slots: vec![].into() }
29    }
30
31    /// Push a Slot into the Path
32    ///
33    /// # Arguments
34    ///
35    /// * `slot` - The Slot to push
36    pub fn push(&mut self, slot: Slot) {
37        self.slots.push_front(slot);
38    }
39
40    /// Remove the first Slot from the Path
41    ///
42    /// # Panics
43    ///
44    /// If the Path is empty
45    pub fn pull(&mut self) -> Option<Slot> {
46        self.slots.pop_front()
47    }
48
49    /// Check if the Path is empty
50    ///
51    /// # Returns
52    ///
53    /// `true` if the Path is empty
54    /// `false` otherwise
55    pub fn is_root(&self) -> bool {
56        self.slots.is_empty()
57    }
58
59    /// Check if the Path matches another Path
60    ///
61    /// # Arguments
62    ///
63    /// * `p` - The Path to check
64    ///
65    /// # Returns
66    ///
67    /// `true` if the Path matches
68    /// `false` otherwise
69    pub fn matches(&self, p: &Path) -> bool {
70        self == p
71    }
72
73    /// Obtain the first Slot of the Path
74    ///
75    /// # Return
76    ///
77    /// The Slot at the head of the Path
78    pub fn head(&self) -> Option<&Slot> {
79        self.slots.front()
80    }
81}
82
83impl Default for Path {
84    fn default() -> Self {
85        Self::new()
86    }
87}
88
89impl From<Vec<Slot>> for Path {
90    fn from(slots: Vec<Slot>) -> Self {
91        let mut reversed_slots = slots;
92        reversed_slots.reverse();
93        Self {
94            slots: reversed_slots.into(),
95        }
96    }
97}
98
99impl Display for Path {
100    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101        write!(f, "P://")?;
102        for (i, slot) in self.slots.iter().enumerate() {
103            if i != 0 {
104                write!(f, "/")?;
105            }
106            write!(f, "{}", slot)?;
107        }
108        Ok(())
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    use crate::slot::Slot::*;
116
117    #[test]
118    fn test_is_root() {
119        let empty_path = Path::from(Vec::new());
120        let not_empty_path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
121        assert!(empty_path.is_root());
122        assert!(!not_empty_path.is_root())
123    }
124
125    #[test]
126    fn test_not_empty_head() {
127        let path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
128        assert_eq!(path.head().unwrap(), &Branch(0))
129    }
130
131    #[test]
132    fn test_empty_head() {
133        let path = Path::new();
134        assert!(path.head().is_none())
135    }
136
137    #[test]
138    fn test_push() {
139        let mut path = path![Nbr(1), Nbr(0), Rep(0)];
140        path.push(Branch(0));
141        assert_eq!(path, path![Branch(0), Nbr(1), Nbr(0), Rep(0)])
142    }
143
144    #[test]
145    fn test_not_empty_pull() {
146        let mut path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
147        path.pull();
148        assert_eq!(path.slots, vec![Nbr(1), Nbr(0), Rep(0)])
149    }
150
151    #[test]
152    fn test_empty_pull() {
153        let mut path = Path::new();
154        assert!(path.pull().is_none());
155    }
156
157    #[test]
158    fn test_to_str() {
159        let path = path![Branch(0), Nbr(1), Nbr(0), Rep(0)];
160        assert_eq!(path.to_string(), "P://Branch(0)/Nbr(1)/Nbr(0)/Rep(0)")
161    }
162
163    #[test]
164    fn test_matches() {
165        let path = Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)]);
166        assert!(path.matches(&Path::from(vec![Rep(0), Nbr(0), Nbr(1), Branch(0)])));
167        assert!(!path.matches(&Path::from(vec![Nbr(0), Nbr(1), Branch(0)])))
168    }
169
170    #[test]
171    fn test_serialize_and_deserialize() {
172        let path = path!(Rep(0), FoldHood(0), Nbr(0), Nbr(1));
173        let path_str = serde_json::to_string(&path).unwrap();
174        let path_des = serde_json::from_str(&path_str).unwrap();
175        assert_eq!(path, path_des);
176    }
177}