reproto_core/
rp_package.rs

1use errors::Result;
2use serde;
3use std::borrow::Cow;
4use std::collections::HashMap;
5use std::fmt;
6use std::mem;
7use std::result;
8use std::slice;
9use {AsPackage, RpVersionedPackage};
10
11/// Iterator over parts in a package.
12pub struct Parts<'a> {
13    iter: slice::Iter<'a, String>,
14}
15
16impl<'a> Iterator for Parts<'a> {
17    type Item = <slice::Iter<'a, String> as Iterator>::Item;
18
19    fn next(&mut self) -> Option<Self::Item> {
20        self.iter.next()
21    }
22}
23
24impl<'a> DoubleEndedIterator for Parts<'a> {
25    fn next_back(&mut self) -> Option<Self::Item> {
26        self.iter.next_back()
27    }
28}
29
30impl<'a> Parts<'a> {
31    pub fn as_slice(&self) -> &'a [String] {
32        self.iter.as_slice()
33    }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct RpPackage {
38    parts: Vec<String>,
39}
40
41impl AsPackage for RpPackage {
42    fn try_as_package<'a>(&'a self) -> Result<Cow<'a, RpPackage>> {
43        Ok(Cow::Borrowed(self))
44    }
45
46    fn prefix_with(self, prefix: RpPackage) -> Self {
47        prefix.join_package(self)
48    }
49}
50
51impl RpPackage {
52    pub fn new(parts: Vec<String>) -> RpPackage {
53        RpPackage { parts: parts }
54    }
55
56    /// Get length of package.
57    pub fn len(&self) -> usize {
58        self.parts.len()
59    }
60
61    /// Parse a package from a string.
62    ///
63    /// Warning: This does not perform any validation that the given package only contains
64    /// identifier components!
65    ///
66    /// * An empty string results in a package _without_ any parts.
67    /// * All other strings are split on dots.
68    pub fn parse(input: &str) -> RpPackage {
69        if input.is_empty() {
70            return Self::empty();
71        }
72
73        RpPackage::new(input.split('.').map(ToOwned::to_owned).collect())
74    }
75
76    /// Build an empty package.
77    pub fn empty() -> RpPackage {
78        RpPackage { parts: vec![] }
79    }
80
81    /// Join with the other package.
82    pub fn join_package(mut self, other: RpPackage) -> RpPackage {
83        self.parts.extend(other.parts);
84        self
85    }
86
87    /// Join this package with another, versioned, package.
88    pub fn join_versioned(&self, other: RpVersionedPackage) -> RpVersionedPackage {
89        let mut parts = self.parts.clone();
90        parts.extend(other.package.parts);
91        RpVersionedPackage::new(RpPackage::new(parts), other.version)
92    }
93
94    /// Join the parts of this package with the given string.
95    pub fn join(&self, separator: &str) -> String {
96        self.parts.join(separator)
97    }
98
99    /// Join with the given part.
100    pub fn join_part<S: AsRef<str>>(mut self, other: S) -> RpPackage {
101        self.parts.push(other.as_ref().to_string());
102        self
103    }
104
105    /// Check if this package starts with another package.
106    pub fn starts_with(&self, other: &RpPackage) -> bool {
107        if self.parts.len() < other.parts.len() {
108            return false;
109        }
110
111        self.parts
112            .iter()
113            .zip(other.parts.iter())
114            .all(|(a, b)| a == b)
115    }
116
117    /// Replace all keyword components in this package.
118    pub fn with_replacements(mut self, keywords: &HashMap<String, String>) -> Self {
119        for p in self.parts.iter_mut() {
120            if let Some(keyword) = keywords.get(p.as_str()) {
121                mem::replace(p, keyword.to_string());
122            }
123        }
124
125        self
126    }
127
128    /// Apply the given naming policy to each part.
129    pub fn with_naming<N>(mut self, naming: N) -> Self
130    where
131        N: Fn(&str) -> String,
132    {
133        for p in self.parts.iter_mut() {
134            let new_name = naming(p);
135            mem::replace(p, new_name);
136        }
137
138        self
139    }
140
141    /// Iterate over the parts in the package.
142    pub fn parts(&self) -> Parts {
143        Parts {
144            iter: self.parts.iter(),
145        }
146    }
147}
148
149impl fmt::Display for RpPackage {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        write!(f, "{}", self.parts.join("."))
152    }
153}
154
155impl serde::Serialize for RpPackage {
156    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
157    where
158        S: serde::Serializer,
159    {
160        serializer.collect_str(self)
161    }
162}
163
164impl<'de> serde::Deserialize<'de> for RpPackage {
165    fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
166    where
167        D: serde::Deserializer<'de>,
168    {
169        struct RpPackageVisitor;
170
171        impl<'de> serde::de::Visitor<'de> for RpPackageVisitor {
172            type Value = RpPackage;
173
174            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
175                formatter.write_str("a SemVer version as a string")
176            }
177
178            fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
179            where
180                E: serde::de::Error,
181            {
182                Ok(RpPackage::parse(v))
183            }
184        }
185
186        deserializer.deserialize_str(RpPackageVisitor)
187    }
188}