1use std::fmt;
2use std::hash::{Hash, Hasher};
3
4use derive_new::new;
5
6use crate::Part;
7
8#[derive(new, Debug, PartialEq, Clone, Eq, Default, PartialOrd)]
10pub struct Parts(pub(crate) Vec<Part>);
11
12impl Parts {
13 pub fn add_part<T>(mut self, part: T) -> Self
19 where
20 T: Into<Part>,
21 {
22 self.0.push(part.into());
23 self
24 }
25
26 pub fn into_owned(self) -> Parts {
28 Parts(self.0.into_iter().map(|part| part).collect())
29 }
30
31 pub fn len(&self) -> usize {
33 self.0.len()
34 }
35
36 pub fn is_empty(&self) -> bool {
38 self.0.is_empty()
39 }
40}
41
42impl Hash for Parts {
43 fn hash<H: Hasher>(&self, state: &mut H) {
44 self.0.len().hash(state);
45 for part in &self.0 {
46 part.hash(state);
47 }
48 }
49}
50
51impl FromIterator<Part> for Parts {
52 fn from_iter<T: IntoIterator<Item=Part>>(iter: T) -> Self {
53 Parts(iter.into_iter().collect())
54 }
55}
56
57impl fmt::Display for Parts {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "{}", self.0.iter().map(|p| p.as_str()).collect::<Vec<_>>().join("/"))
61 }
62}
63
64impl IntoIterator for Parts {
65 type Item = Part;
66 type IntoIter = std::vec::IntoIter<Self::Item>;
67
68 fn into_iter(self) -> Self::IntoIter {
69 self.0.into_iter()
70 }
71}
72
73impl<'a> IntoIterator for &'a Parts {
74 type Item = &'a Part;
75 type IntoIter = std::slice::Iter<'a, Part>;
76
77 fn into_iter(self) -> Self::IntoIter {
78 self.0.iter()
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_parts_creation() -> anyhow::Result<()> {
88 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
89 assert_eq!(parts.to_string(), "segment1/segment2");
90 Ok(())
91 }
92
93 #[test]
94 fn test_parts_add_part() -> anyhow::Result<()> {
95 let parts = Parts::new(vec![Part::new("segment1")?])
96 .add_part(Part::new("segment2")?)
97 .add_part(Part::new("segment3")?);
98 assert_eq!(parts.to_string(), "segment1/segment2/segment3");
99 Ok(())
100 }
101
102 #[test]
103 fn test_parts_from_iterator() -> anyhow::Result<()> {
104 let parts: Result<Parts, _> = vec!["segment1", "segment2", "segment3"]
105 .into_iter()
106 .map(Part::new)
107 .collect();
108 match parts {
109 Ok(parts) => {
110 assert_eq!(parts.to_string(), "segment1/segment2/segment3");
111 Ok(())
112 }
113 Err(e) => Err(anyhow::anyhow!(e)),
114 }
115 }
116
117 #[test]
118 fn test_parts_into_owned() -> anyhow::Result<()> {
119 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
120 let owned_parts: Parts = parts;
121 assert_eq!(owned_parts.to_string(), "segment1/segment2");
122 Ok(())
123 }
124
125 #[test]
126 fn test_parts_iterator() -> anyhow::Result<()> {
127 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
128 let collected: Vec<_> = parts.into_iter().collect();
129 assert_eq!(collected.len(), 2);
130 assert_eq!(collected[0].as_str(), "segment1");
131 assert_eq!(collected[1].as_str(), "segment2");
132 Ok(())
133 }
134
135 #[test]
136 fn test_parts_ref_iterator() -> anyhow::Result<()> {
137 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
138 let collected: Vec<_> = (&parts).into_iter().map(|p| p.as_str()).collect();
139 assert_eq!(collected, vec!["segment1", "segment2"]);
140 Ok(())
141 }
142
143 #[test]
144 fn test_parts_for_loop() -> anyhow::Result<()> {
145 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
146 let mut collected = Vec::new();
147 for part in parts {
148 collected.push(part.as_str().to_string());
149 }
150 assert_eq!(collected, vec!["segment1".to_string(), "segment2".to_string()]);
151 Ok(())
152 }
153}