1use std::borrow::Cow;
2use std::fmt;
3
4use derive_more::{AsRef, Into};
5
6use crate::errors::ErnError;
7
8#[derive(AsRef, Into, Eq, Debug, PartialEq, Clone, Hash, PartialOrd)]
9pub struct Part(pub(crate) String);
10
11impl Part {
12 pub fn as_str(&self) -> &str {
13 &self.0
14 }
15
16 pub fn into_owned(self) -> Part {
17 Part(self.0.to_string())
18 }
19
20 pub fn new(value: impl Into<String>) -> Result<Part, ErnError> {
21 let value = value.into();
22 if value.contains(':') || value.contains('/') {
23 return Err(ErnError::InvalidPartFormat);
24 }
25 if value.is_empty() {
26 return Err(ErnError::ParseFailure(
27 "Part",
28 "cannot be empty".to_string(),
29 ));
30 }
31 Ok(Part(value))
32 }
33}
34
35impl fmt::Display for Part {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{}", self.0)
38 }
39}
40
41impl std::str::FromStr for Part {
42 type Err = ErnError;
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 Part::new(Cow::Owned(s.to_owned()))
45 }
46}
47
48#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn test_part_creation() -> anyhow::Result<()> {
60 let part = Part::new("segment")?;
61 assert_eq!(part.as_str(), "segment");
62 Ok(())
63 }
64
65 #[test]
66 fn test_part_display() -> anyhow::Result<()> {
67 let part = Part::new("example")?;
68 assert_eq!(format!("{}", part), "example");
69 Ok(())
70 }
71
72 #[test]
73 fn test_part_from_str() {
74 let part: Part = "test".parse().unwrap();
75 assert_eq!(part.as_str(), "test");
76 }
77
78 #[test]
79 fn test_part_equality() -> anyhow::Result<()> {
80 let part1 = Part::new("segment1")?;
81 let part2 = Part::new("segment1")?;
82 let part3 = Part::new("segment2")?;
83 assert_eq!(part1, part2);
84 assert_ne!(part1, part3);
85 Ok(())
86 }
87
88 #[test]
89 fn test_part_into_string() -> anyhow::Result<()> {
90 let part = Part::new("segment")?;
91 let string: String = part.into();
92 assert_eq!(string, "segment");
93 Ok(())
94 }
95}