protobuf_parse/
protobuf_rel_path.rs

1#![doc(hidden)]
2
3use std::fmt;
4use std::iter;
5use std::mem;
6use std::ops::Deref;
7
8use crate::protobuf_abs_path::ProtobufAbsPath;
9use crate::protobuf_ident::ProtobufIdent;
10use crate::ProtobufIdentRef;
11
12impl From<String> for ProtobufRelPath {
13    fn from(s: String) -> ProtobufRelPath {
14        ProtobufRelPath::new(s)
15    }
16}
17
18impl From<&'_ str> for ProtobufRelPath {
19    fn from(s: &str) -> ProtobufRelPath {
20        ProtobufRelPath::from(s.to_owned())
21    }
22}
23
24impl ProtobufRelPathRef {
25    pub fn as_str(&self) -> &str {
26        &self
27    }
28
29    pub fn empty() -> &'static ProtobufRelPathRef {
30        Self::new("")
31    }
32
33    pub fn new(path: &str) -> &ProtobufRelPathRef {
34        assert!(!path.starts_with('.'));
35        // SAFETY: repr(transparent)
36        unsafe { mem::transmute(path) }
37    }
38
39    pub fn is_empty(&self) -> bool {
40        self.0.is_empty()
41    }
42
43    pub fn split_first_rem(&self) -> Option<(&ProtobufIdentRef, &ProtobufRelPathRef)> {
44        if self.is_empty() {
45            None
46        } else {
47            match self.0.find('.') {
48                Some(i) => Some((
49                    ProtobufIdentRef::new(&self.0[..i]),
50                    ProtobufRelPathRef::new(&self.0[i + 1..]),
51                )),
52                None => Some((ProtobufIdentRef::new(&self.0), ProtobufRelPathRef::empty())),
53            }
54        }
55    }
56
57    pub fn components(&self) -> impl Iterator<Item = &ProtobufIdentRef> {
58        iter::once(&self.0)
59            .filter(|s| !s.is_empty())
60            .flat_map(|p| p.split('.').map(|s| ProtobufIdentRef::new(s)))
61    }
62
63    fn parent(&self) -> Option<&ProtobufRelPathRef> {
64        if self.0.is_empty() {
65            None
66        } else {
67            match self.0.rfind('.') {
68                Some(i) => Some(ProtobufRelPathRef::new(&self.0[..i])),
69                None => Some(ProtobufRelPathRef::empty()),
70            }
71        }
72    }
73
74    pub fn self_and_parents(&self) -> Vec<&ProtobufRelPathRef> {
75        let mut tmp = self;
76
77        let mut r = Vec::new();
78
79        r.push(self);
80
81        while let Some(parent) = tmp.parent() {
82            r.push(parent);
83            tmp = parent;
84        }
85
86        r
87    }
88
89    pub fn append(&self, simple: &ProtobufRelPathRef) -> ProtobufRelPath {
90        if self.is_empty() {
91            simple.to_owned()
92        } else if simple.is_empty() {
93            self.to_owned()
94        } else {
95            ProtobufRelPath {
96                path: format!("{}.{}", &self.0, &simple.0),
97            }
98        }
99    }
100
101    pub fn append_ident(&self, simple: &ProtobufIdentRef) -> ProtobufRelPath {
102        self.append(&ProtobufRelPath::from(simple.to_owned()))
103    }
104
105    pub fn to_absolute(&self) -> ProtobufAbsPath {
106        self.to_owned().into_absolute()
107    }
108
109    pub fn to_owned(&self) -> ProtobufRelPath {
110        ProtobufRelPath {
111            path: self.0.to_owned(),
112        }
113    }
114}
115
116impl ProtobufRelPath {
117    pub fn as_ref(&self) -> &ProtobufRelPathRef {
118        &self
119    }
120
121    pub fn empty() -> ProtobufRelPath {
122        ProtobufRelPath {
123            path: String::new(),
124        }
125    }
126
127    pub fn new<S: Into<String>>(path: S) -> ProtobufRelPath {
128        let path = path.into();
129        // Validate
130        ProtobufRelPathRef::new(&path);
131        ProtobufRelPath { path }
132    }
133
134    pub fn from_components<'a, I: IntoIterator<Item = &'a ProtobufIdentRef>>(
135        i: I,
136    ) -> ProtobufRelPath {
137        let v: Vec<&str> = i.into_iter().map(|c| c.as_str()).collect();
138        ProtobufRelPath::from(v.join("."))
139    }
140
141    pub fn into_absolute(self) -> ProtobufAbsPath {
142        if self.is_empty() {
143            ProtobufAbsPath::root()
144        } else {
145            ProtobufAbsPath::from(format!(".{}", self))
146        }
147    }
148}
149
150#[doc(hidden)]
151#[derive(Debug, Eq, PartialEq, Clone, Hash)]
152pub struct ProtobufRelPath {
153    pub(crate) path: String,
154}
155
156#[doc(hidden)]
157#[derive(Debug, Eq, PartialEq, Hash)]
158#[repr(transparent)]
159pub struct ProtobufRelPathRef(str);
160
161impl Deref for ProtobufRelPathRef {
162    type Target = str;
163
164    fn deref(&self) -> &str {
165        &self.0
166    }
167}
168
169impl Deref for ProtobufRelPath {
170    type Target = ProtobufRelPathRef;
171
172    fn deref(&self) -> &ProtobufRelPathRef {
173        ProtobufRelPathRef::new(&self.path)
174    }
175}
176
177impl From<ProtobufIdent> for ProtobufRelPath {
178    fn from(s: ProtobufIdent) -> ProtobufRelPath {
179        ProtobufRelPath { path: s.into() }
180    }
181}
182
183impl fmt::Display for ProtobufRelPathRef {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        write!(f, "{}", &self.0)
186    }
187}
188
189impl fmt::Display for ProtobufRelPath {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "{}", self.path)
192    }
193}
194
195#[cfg(test)]
196mod test {
197    use super::*;
198
199    #[test]
200    fn parent() {
201        assert_eq!(None, ProtobufRelPathRef::empty().parent());
202        assert_eq!(
203            Some(ProtobufRelPathRef::empty()),
204            ProtobufRelPath::new("aaa".to_owned()).parent()
205        );
206        assert_eq!(
207            Some(ProtobufRelPathRef::new("abc")),
208            ProtobufRelPath::new("abc.def".to_owned()).parent()
209        );
210        assert_eq!(
211            Some(ProtobufRelPathRef::new("abc.def")),
212            ProtobufRelPath::new("abc.def.gh".to_owned()).parent()
213        );
214    }
215
216    #[test]
217    fn self_and_parents() {
218        assert_eq!(
219            vec![
220                ProtobufRelPathRef::new("ab.cde.fghi"),
221                ProtobufRelPathRef::new("ab.cde"),
222                ProtobufRelPathRef::new("ab"),
223                ProtobufRelPathRef::empty(),
224            ],
225            ProtobufRelPath::new("ab.cde.fghi".to_owned()).self_and_parents()
226        );
227    }
228
229    #[test]
230    fn components() {
231        assert_eq!(
232            Vec::<&ProtobufIdentRef>::new(),
233            ProtobufRelPath::empty().components().collect::<Vec<_>>()
234        );
235        assert_eq!(
236            vec![ProtobufIdentRef::new("ab")],
237            ProtobufRelPath::new("ab").components().collect::<Vec<_>>()
238        );
239        assert_eq!(
240            vec![ProtobufIdentRef::new("ab"), ProtobufIdentRef::new("cd")],
241            ProtobufRelPath::new("ab.cd")
242                .components()
243                .collect::<Vec<_>>()
244        );
245    }
246}