1use std::fmt;
2use std::hash::{Hash, Hasher};
3
4use derive_new::new;
5
6use crate::Part;
7use crate::errors::ErnError;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(new, Debug, PartialEq, Clone, Eq, Default, PartialOrd)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub struct Parts(pub(crate) Vec<Part>);
16
17impl Parts {
18 pub fn add_part<T>(mut self, part: T) -> Result<Self, ErnError>
37 where
38 T: Into<Part>,
39 {
40 if self.0.len() >= 10 {
42 return Err(ErnError::ParseFailure(
43 "Parts",
44 "cannot exceed maximum of 10 parts".to_string(),
45 ));
46 }
47
48 self.0.push(part.into());
49 Ok(self)
50 }
51
52 pub fn into_owned(self) -> Parts {
54 Parts(self.0.into_iter().collect())
55 }
56
57 pub fn len(&self) -> usize {
59 self.0.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.0.is_empty()
65 }
66}
67
68impl Hash for Parts {
69 fn hash<H: Hasher>(&self, state: &mut H) {
70 self.0.len().hash(state);
71 for part in &self.0 {
72 part.hash(state);
73 }
74 }
75}
76
77impl FromIterator<Part> for Parts {
78 fn from_iter<T: IntoIterator<Item=Part>>(iter: T) -> Self {
79 Parts(iter.into_iter().collect())
80 }
81}
82
83impl fmt::Display for Parts {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 write!(f, "{}", self.0.iter().map(|p| p.as_str()).collect::<Vec<_>>().join("/"))
87 }
88}
89
90impl IntoIterator for Parts {
91 type Item = Part;
92 type IntoIter = std::vec::IntoIter<Self::Item>;
93
94 fn into_iter(self) -> Self::IntoIter {
95 self.0.into_iter()
96 }
97}
98
99impl<'a> IntoIterator for &'a Parts {
100 type Item = &'a Part;
101 type IntoIter = std::slice::Iter<'a, Part>;
102
103 fn into_iter(self) -> Self::IntoIter {
104 self.0.iter()
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_parts_creation() -> anyhow::Result<()> {
114 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
115 assert_eq!(parts.to_string(), "segment1/segment2");
116 Ok(())
117 }
118
119 #[test]
120 fn test_parts_add_part() -> anyhow::Result<()> {
121 let mut parts = Parts::new(vec![Part::new("segment1")?]);
122 parts = parts.add_part(Part::new("segment2")?)?;
123 parts = parts.add_part(Part::new("segment3")?)?;
124
125 assert_eq!(parts.to_string(), "segment1/segment2/segment3");
126 Ok(())
127 }
128
129 #[test]
130 fn test_parts_from_iterator() -> anyhow::Result<()> {
131 let parts: Result<Parts, _> = vec!["segment1", "segment2", "segment3"]
132 .into_iter()
133 .map(Part::new)
134 .collect();
135 match parts {
136 Ok(parts) => {
137 assert_eq!(parts.to_string(), "segment1/segment2/segment3");
138 Ok(())
139 }
140 Err(e) => Err(anyhow::anyhow!(e)),
141 }
142 }
143
144 #[test]
145 fn test_parts_into_owned() -> anyhow::Result<()> {
146 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
147 let owned_parts: Parts = parts;
148 assert_eq!(owned_parts.to_string(), "segment1/segment2");
149 Ok(())
150 }
151
152 #[test]
153 fn test_parts_iterator() -> anyhow::Result<()> {
154 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
155 let collected: Vec<_> = parts.into_iter().collect();
156 assert_eq!(collected.len(), 2);
157 assert_eq!(collected[0].as_str(), "segment1");
158 assert_eq!(collected[1].as_str(), "segment2");
159 Ok(())
160 }
161
162 #[test]
163 fn test_parts_ref_iterator() -> anyhow::Result<()> {
164 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
165 let collected: Vec<_> = (&parts).into_iter().map(|p| p.as_str()).collect();
166 assert_eq!(collected, vec!["segment1", "segment2"]);
167 Ok(())
168 }
169
170 #[test]
171 fn test_parts_for_loop() -> anyhow::Result<()> {
172 let parts = Parts::new(vec![Part::new("segment1")?, Part::new("segment2")?]);
173 let mut collected = Vec::new();
174 for part in parts {
175 collected.push(part.as_str().to_string());
176 }
177 assert_eq!(collected, vec!["segment1".to_string(), "segment2".to_string()]);
178 Ok(())
179 }
180 #[test]
181 fn test_parts_validation_max_parts() -> anyhow::Result<()> {
182 let mut parts = Parts::new(vec![]);
184 for i in 0..10 {
185 parts = parts.add_part(Part::new(format!("part{}", i))?)?;
186 }
187
188 let result = parts.add_part(Part::new("one_too_many")?);
190 assert!(result.is_err());
191
192 match result {
193 Err(ErnError::ParseFailure(component, msg)) => {
194 assert_eq!(component, "Parts");
195 assert!(msg.contains("cannot exceed maximum"));
196 }
197 _ => panic!("Expected ParseFailure error for too many parts"),
198 }
199
200 Ok(())
201 }
202}