• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 
3 /// Identifier in `.proto` file
4 #[derive(Eq, PartialEq, Debug, Clone)]
5 pub struct ProtobufIdent(String);
6 
7 impl ProtobufIdent {
8     /// New ident from a string.
9     #[allow(dead_code)]
new(s: &str) -> ProtobufIdent10     pub fn new(s: &str) -> ProtobufIdent {
11         assert!(!s.is_empty());
12         assert!(!s.contains("/"));
13         assert!(!s.contains("."));
14         assert!(!s.contains(":"));
15         ProtobufIdent(s.to_owned())
16     }
17 
18     /// Get as a string.
get(&self) -> &str19     pub fn get(&self) -> &str {
20         &self.0
21     }
22 }
23 
24 impl From<&'_ str> for ProtobufIdent {
from(s: &str) -> Self25     fn from(s: &str) -> Self {
26         ProtobufIdent::new(s)
27     }
28 }
29 
30 impl From<String> for ProtobufIdent {
from(s: String) -> Self31     fn from(s: String) -> Self {
32         ProtobufIdent::new(&s)
33     }
34 }
35 
36 impl fmt::Display for ProtobufIdent {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result37     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38         fmt::Display::fmt(&self.get(), f)
39     }
40 }
41 
42 /// Relative protobuf identifier path.
43 #[derive(Debug, Eq, PartialEq, Clone)]
44 pub struct ProtobufRelativePath {
45     /// The path
46     pub path: String,
47 }
48 
49 #[allow(dead_code)]
50 impl ProtobufRelativePath {
51     /// Empty relative path.
empty() -> ProtobufRelativePath52     pub fn empty() -> ProtobufRelativePath {
53         ProtobufRelativePath::new(String::new())
54     }
55 
56     /// New path from a string.
new(path: String) -> ProtobufRelativePath57     pub fn new(path: String) -> ProtobufRelativePath {
58         assert!(!path.starts_with("."));
59 
60         ProtobufRelativePath { path }
61     }
62 
63     /// From path components.
from_components<I: IntoIterator<Item = ProtobufIdent>>(i: I) -> ProtobufRelativePath64     pub fn from_components<I: IntoIterator<Item = ProtobufIdent>>(i: I) -> ProtobufRelativePath {
65         let v: Vec<String> = i.into_iter().map(|c| c.get().to_owned()).collect();
66         ProtobufRelativePath::from(v.join("."))
67     }
68 
69     /// Get the string.
get(&self) -> &str70     pub fn get(&self) -> &str {
71         &self.path
72     }
73 
74     /// The path is empty.
is_empty(&self) -> bool75     pub fn is_empty(&self) -> bool {
76         self.path.is_empty()
77     }
78 
79     /// As absolute path from root namespace.
into_absolute(self) -> ProtobufAbsolutePath80     pub fn into_absolute(self) -> ProtobufAbsolutePath {
81         if self.is_empty() {
82             ProtobufAbsolutePath::root()
83         } else {
84             ProtobufAbsolutePath::from(format!(".{}", self))
85         }
86     }
87 
_last_part(&self) -> Option<&str>88     fn _last_part(&self) -> Option<&str> {
89         match self.path.rfind('.') {
90             Some(pos) => Some(&self.path[pos + 1..]),
91             None => {
92                 if self.path.is_empty() {
93                     None
94                 } else {
95                     Some(&self.path)
96                 }
97             }
98         }
99     }
100 
parent(&self) -> Option<ProtobufRelativePath>101     fn parent(&self) -> Option<ProtobufRelativePath> {
102         match self.path.rfind('.') {
103             Some(pos) => Some(ProtobufRelativePath::new(self.path[..pos].to_owned())),
104             None => {
105                 if self.path.is_empty() {
106                     None
107                 } else {
108                     Some(ProtobufRelativePath::empty())
109                 }
110             }
111         }
112     }
113 
114     /// Self path and parent paths.
self_and_parents(&self) -> Vec<ProtobufRelativePath>115     pub fn self_and_parents(&self) -> Vec<ProtobufRelativePath> {
116         let mut tmp = self.clone();
117 
118         let mut r = Vec::new();
119 
120         r.push(self.clone());
121 
122         while let Some(parent) = tmp.parent() {
123             r.push(parent.clone());
124             tmp = parent;
125         }
126 
127         r
128     }
129 
130     /// Append path component.
append(&self, simple: &ProtobufRelativePath) -> ProtobufRelativePath131     pub fn append(&self, simple: &ProtobufRelativePath) -> ProtobufRelativePath {
132         if self.path.is_empty() {
133             ProtobufRelativePath::from(simple.get())
134         } else {
135             ProtobufRelativePath::new(format!("{}.{}", self.path, simple))
136         }
137     }
138 
139     /// Append identifier to the path.
append_ident(&self, simple: &ProtobufIdent) -> ProtobufRelativePath140     pub fn append_ident(&self, simple: &ProtobufIdent) -> ProtobufRelativePath {
141         self.append(&ProtobufRelativePath::from(simple.clone()))
142     }
143 
144     /// Get first component path and remaining.
split_first_rem(&self) -> Option<(ProtobufIdent, ProtobufRelativePath)>145     pub fn split_first_rem(&self) -> Option<(ProtobufIdent, ProtobufRelativePath)> {
146         if self.is_empty() {
147             None
148         } else {
149             Some(match self.path.find('.') {
150                 Some(dot) => (
151                     ProtobufIdent::from(&self.path[..dot]),
152                     ProtobufRelativePath::new(self.path[dot + 1..].to_owned()),
153                 ),
154                 None => (
155                     ProtobufIdent::from(self.path.clone()),
156                     ProtobufRelativePath::empty(),
157                 ),
158             })
159         }
160     }
161 }
162 
163 impl From<&'_ str> for ProtobufRelativePath {
from(s: &str) -> ProtobufRelativePath164     fn from(s: &str) -> ProtobufRelativePath {
165         ProtobufRelativePath::from(s.to_owned())
166     }
167 }
168 
169 impl From<String> for ProtobufRelativePath {
from(s: String) -> ProtobufRelativePath170     fn from(s: String) -> ProtobufRelativePath {
171         ProtobufRelativePath::new(s)
172     }
173 }
174 
175 impl From<ProtobufIdent> for ProtobufRelativePath {
from(s: ProtobufIdent) -> ProtobufRelativePath176     fn from(s: ProtobufIdent) -> ProtobufRelativePath {
177         ProtobufRelativePath::from(s.get())
178     }
179 }
180 
181 impl From<Vec<ProtobufIdent>> for ProtobufRelativePath {
from(s: Vec<ProtobufIdent>) -> ProtobufRelativePath182     fn from(s: Vec<ProtobufIdent>) -> ProtobufRelativePath {
183         ProtobufRelativePath::from_components(s.into_iter())
184     }
185 }
186 
187 impl fmt::Display for ProtobufRelativePath {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result188     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189         fmt::Display::fmt(&self.path, f)
190     }
191 }
192 
193 #[cfg(test)]
194 mod relative_path_test {
195     use super::*;
196 
197     #[test]
parent()198     fn parent() {
199         assert_eq!(None, ProtobufRelativePath::empty().parent());
200         assert_eq!(
201             Some(ProtobufRelativePath::empty()),
202             ProtobufRelativePath::new("aaa".to_owned()).parent()
203         );
204         assert_eq!(
205             Some(ProtobufRelativePath::new("abc".to_owned())),
206             ProtobufRelativePath::new("abc.def".to_owned()).parent()
207         );
208         assert_eq!(
209             Some(ProtobufRelativePath::new("abc.def".to_owned())),
210             ProtobufRelativePath::new("abc.def.gh".to_owned()).parent()
211         );
212     }
213 
214     #[test]
last_part()215     fn last_part() {
216         assert_eq!(None, ProtobufRelativePath::empty()._last_part());
217         assert_eq!(
218             Some("aaa"),
219             ProtobufRelativePath::new("aaa".to_owned())._last_part()
220         );
221         assert_eq!(
222             Some("def"),
223             ProtobufRelativePath::new("abc.def".to_owned())._last_part()
224         );
225         assert_eq!(
226             Some("gh"),
227             ProtobufRelativePath::new("abc.def.gh".to_owned())._last_part()
228         );
229     }
230 }
231 
232 /// Absolute protobuf path (e. g. package).
233 ///
234 /// This is not filesystem path.
235 #[derive(Clone, Eq, PartialEq, Debug, Hash)]
236 pub struct ProtobufAbsolutePath {
237     /// The path.
238     pub path: String,
239 }
240 
241 impl ProtobufAbsolutePath {
root() -> ProtobufAbsolutePath242     fn root() -> ProtobufAbsolutePath {
243         ProtobufAbsolutePath::new(String::new())
244     }
245 
246     /// From string.
new(path: String) -> ProtobufAbsolutePath247     pub fn new(path: String) -> ProtobufAbsolutePath {
248         assert!(path.is_empty() || path.starts_with("."), "{}", path);
249         assert!(!path.ends_with("."), "{}", path);
250         ProtobufAbsolutePath { path }
251     }
252 
253     /// The path is empty.
is_empty(&self) -> bool254     pub fn is_empty(&self) -> bool {
255         self.path.is_empty()
256     }
257 
258     /// From a path without leading dot.
259     ///
260     /// (Protobuf paths start with dot).
from_path_without_dot(path: &str) -> ProtobufAbsolutePath261     pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
262         if path.is_empty() {
263             ProtobufAbsolutePath::root()
264         } else {
265             assert!(!path.starts_with("."));
266             assert!(!path.ends_with("."));
267             ProtobufAbsolutePath::new(format!(".{}", path))
268         }
269     }
270 
271     /// Parse absolute path.
272     #[allow(dead_code)]
from_package_path(path: Option<&str>) -> ProtobufAbsolutePath273     pub fn from_package_path(path: Option<&str>) -> ProtobufAbsolutePath {
274         match path {
275             None => ProtobufAbsolutePath::root(),
276             Some(path) => ProtobufAbsolutePath::from_path_without_dot(path),
277         }
278     }
279 
280     /// Construct abs path from a string which may start with a dot.
from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath281     pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
282         if path.starts_with(".") {
283             ProtobufAbsolutePath::new(path.to_owned())
284         } else {
285             ProtobufAbsolutePath::from_path_without_dot(path)
286         }
287     }
288 
289     /// Push identifier to the path.
push_simple(&mut self, simple: ProtobufIdent)290     pub fn push_simple(&mut self, simple: ProtobufIdent) {
291         self.path.push('.');
292         self.path.push_str(simple.get());
293     }
294 
295     /// Push relative path.
push_relative(&mut self, relative: &ProtobufRelativePath)296     pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
297         if !relative.is_empty() {
298             self.path.push('.');
299             self.path.push_str(&relative.path);
300         }
301     }
302 
303     /// Try remove a prefix.
remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath>304     pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
305         if self.path.starts_with(&prefix.path) {
306             let rem = &self.path[prefix.path.len()..];
307             if rem.is_empty() {
308                 return Some(ProtobufRelativePath::empty());
309             }
310             if rem.starts_with('.') {
311                 return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
312             }
313         }
314         None
315     }
316 }
317 
318 impl From<&'_ str> for ProtobufAbsolutePath {
from(s: &str) -> Self319     fn from(s: &str) -> Self {
320         ProtobufAbsolutePath::new(s.to_owned())
321     }
322 }
323 
324 impl From<String> for ProtobufAbsolutePath {
from(s: String) -> Self325     fn from(s: String) -> Self {
326         ProtobufAbsolutePath::new(s)
327     }
328 }
329 
330 impl fmt::Display for ProtobufAbsolutePath {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result331     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
332         fmt::Display::fmt(&self.path, f)
333     }
334 }
335 
336 #[cfg(test)]
337 mod absolute_path_test {
338     use super::*;
339 
340     #[test]
absolute_path_push_simple()341     fn absolute_path_push_simple() {
342         let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
343         foo.push_simple(ProtobufIdent::from("bar"));
344         assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);
345 
346         let mut foo = ProtobufAbsolutePath::root();
347         foo.push_simple(ProtobufIdent::from("bar"));
348         assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
349     }
350 
351     #[test]
absolute_path_remove_prefix()352     fn absolute_path_remove_prefix() {
353         assert_eq!(
354             Some(ProtobufRelativePath::empty()),
355             ProtobufAbsolutePath::new(".foo".to_owned())
356                 .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
357         );
358         assert_eq!(
359             Some(ProtobufRelativePath::new("bar".to_owned())),
360             ProtobufAbsolutePath::new(".foo.bar".to_owned())
361                 .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
362         );
363         assert_eq!(
364             Some(ProtobufRelativePath::new("baz.qux".to_owned())),
365             ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
366                 .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
367         );
368         assert_eq!(
369             None,
370             ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
371                 .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
372         );
373     }
374 }
375