1 #![doc(hidden)] 2 3 use std::fmt; 4 use std::iter; 5 use std::mem; 6 use std::ops::Deref; 7 8 use crate::protobuf_abs_path::ProtobufAbsPath; 9 use crate::protobuf_ident::ProtobufIdent; 10 use crate::ProtobufIdentRef; 11 12 impl From<String> for ProtobufRelPath { from(s: String) -> ProtobufRelPath13 fn from(s: String) -> ProtobufRelPath { 14 ProtobufRelPath::new(s) 15 } 16 } 17 18 impl From<&'_ str> for ProtobufRelPath { from(s: &str) -> ProtobufRelPath19 fn from(s: &str) -> ProtobufRelPath { 20 ProtobufRelPath::from(s.to_owned()) 21 } 22 } 23 24 impl ProtobufRelPathRef { as_str(&self) -> &str25 pub fn as_str(&self) -> &str { 26 &self 27 } 28 empty() -> &'static ProtobufRelPathRef29 pub fn empty() -> &'static ProtobufRelPathRef { 30 Self::new("") 31 } 32 new(path: &str) -> &ProtobufRelPathRef33 pub fn new(path: &str) -> &ProtobufRelPathRef { 34 assert!(!path.starts_with('.')); 35 // SAFETY: repr(transparent) 36 unsafe { mem::transmute(path) } 37 } 38 is_empty(&self) -> bool39 pub fn is_empty(&self) -> bool { 40 self.0.is_empty() 41 } 42 split_first_rem(&self) -> Option<(&ProtobufIdentRef, &ProtobufRelPathRef)>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 components(&self) -> impl Iterator<Item = &ProtobufIdentRef>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 parent(&self) -> Option<&ProtobufRelPathRef>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 self_and_parents(&self) -> Vec<&ProtobufRelPathRef>74 pub fn self_and_parents(&self) -> Vec<&ProtobufRelPathRef> { 75 let mut tmp = self.clone(); 76 77 let mut r = Vec::new(); 78 79 r.push(self.clone()); 80 81 while let Some(parent) = tmp.parent() { 82 r.push(parent); 83 tmp = parent; 84 } 85 86 r 87 } 88 append(&self, simple: &ProtobufRelPathRef) -> ProtobufRelPath89 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 append_ident(&self, simple: &ProtobufIdentRef) -> ProtobufRelPath101 pub fn append_ident(&self, simple: &ProtobufIdentRef) -> ProtobufRelPath { 102 self.append(&ProtobufRelPath::from(simple.to_owned())) 103 } 104 to_absolute(&self) -> ProtobufAbsPath105 pub fn to_absolute(&self) -> ProtobufAbsPath { 106 self.to_owned().into_absolute() 107 } 108 to_owned(&self) -> ProtobufRelPath109 pub fn to_owned(&self) -> ProtobufRelPath { 110 ProtobufRelPath { 111 path: self.0.to_owned(), 112 } 113 } 114 } 115 116 impl ProtobufRelPath { as_ref(&self) -> &ProtobufRelPathRef117 pub fn as_ref(&self) -> &ProtobufRelPathRef { 118 &self 119 } 120 empty() -> ProtobufRelPath121 pub fn empty() -> ProtobufRelPath { 122 ProtobufRelPath { 123 path: String::new(), 124 } 125 } 126 new<S: Into<String>>(path: S) -> ProtobufRelPath127 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 from_components<'a, I: IntoIterator<Item = &'a ProtobufIdentRef>>( i: I, ) -> ProtobufRelPath134 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 into_absolute(self) -> ProtobufAbsPath141 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)] 152 pub struct ProtobufRelPath { 153 pub(crate) path: String, 154 } 155 156 #[doc(hidden)] 157 #[derive(Debug, Eq, PartialEq, Hash)] 158 #[repr(transparent)] 159 pub struct ProtobufRelPathRef(str); 160 161 impl Deref for ProtobufRelPathRef { 162 type Target = str; 163 deref(&self) -> &str164 fn deref(&self) -> &str { 165 &self.0 166 } 167 } 168 169 impl Deref for ProtobufRelPath { 170 type Target = ProtobufRelPathRef; 171 deref(&self) -> &ProtobufRelPathRef172 fn deref(&self) -> &ProtobufRelPathRef { 173 ProtobufRelPathRef::new(&self.path) 174 } 175 } 176 177 impl From<ProtobufIdent> for ProtobufRelPath { from(s: ProtobufIdent) -> ProtobufRelPath178 fn from(s: ProtobufIdent) -> ProtobufRelPath { 179 ProtobufRelPath { path: s.into() } 180 } 181 } 182 183 impl fmt::Display for ProtobufRelPathRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 185 write!(f, "{}", &self.0) 186 } 187 } 188 189 impl fmt::Display for ProtobufRelPath { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result190 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 191 write!(f, "{}", self.path) 192 } 193 } 194 195 #[cfg(test)] 196 mod test { 197 use super::*; 198 199 #[test] parent()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] self_and_parents()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] components()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 } 247