diff options
Diffstat (limited to '2.27.1/src/protobuf_name.rs')
-rw-r--r-- | 2.27.1/src/protobuf_name.rs | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/2.27.1/src/protobuf_name.rs b/2.27.1/src/protobuf_name.rs new file mode 100644 index 0000000..c40a69c --- /dev/null +++ b/2.27.1/src/protobuf_name.rs @@ -0,0 +1,374 @@ +use std::fmt; + +/// Identifier in `.proto` file +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct ProtobufIdent(String); + +impl ProtobufIdent { + /// New ident from a string. + #[allow(dead_code)] + pub fn new(s: &str) -> ProtobufIdent { + assert!(!s.is_empty()); + assert!(!s.contains("/")); + assert!(!s.contains(".")); + assert!(!s.contains(":")); + ProtobufIdent(s.to_owned()) + } + + /// Get as a string. + pub fn get(&self) -> &str { + &self.0 + } +} + +impl From<&'_ str> for ProtobufIdent { + fn from(s: &str) -> Self { + ProtobufIdent::new(s) + } +} + +impl From<String> for ProtobufIdent { + fn from(s: String) -> Self { + ProtobufIdent::new(&s) + } +} + +impl fmt::Display for ProtobufIdent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.get(), f) + } +} + +/// Relative protobuf identifier path. +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct ProtobufRelativePath { + /// The path + pub path: String, +} + +#[allow(dead_code)] +impl ProtobufRelativePath { + /// Empty relative path. + pub fn empty() -> ProtobufRelativePath { + ProtobufRelativePath::new(String::new()) + } + + /// New path from a string. + pub fn new(path: String) -> ProtobufRelativePath { + assert!(!path.starts_with(".")); + + ProtobufRelativePath { path } + } + + /// From path components. + pub fn from_components<I: IntoIterator<Item = ProtobufIdent>>(i: I) -> ProtobufRelativePath { + let v: Vec<String> = i.into_iter().map(|c| c.get().to_owned()).collect(); + ProtobufRelativePath::from(v.join(".")) + } + + /// Get the string. + pub fn get(&self) -> &str { + &self.path + } + + /// The path is empty. + pub fn is_empty(&self) -> bool { + self.path.is_empty() + } + + /// As absolute path from root namespace. + pub fn into_absolute(self) -> ProtobufAbsolutePath { + if self.is_empty() { + ProtobufAbsolutePath::root() + } else { + ProtobufAbsolutePath::from(format!(".{}", self)) + } + } + + fn _last_part(&self) -> Option<&str> { + match self.path.rfind('.') { + Some(pos) => Some(&self.path[pos + 1..]), + None => { + if self.path.is_empty() { + None + } else { + Some(&self.path) + } + } + } + } + + fn parent(&self) -> Option<ProtobufRelativePath> { + match self.path.rfind('.') { + Some(pos) => Some(ProtobufRelativePath::new(self.path[..pos].to_owned())), + None => { + if self.path.is_empty() { + None + } else { + Some(ProtobufRelativePath::empty()) + } + } + } + } + + /// Self path and parent paths. + pub fn self_and_parents(&self) -> Vec<ProtobufRelativePath> { + let mut tmp = self.clone(); + + let mut r = Vec::new(); + + r.push(self.clone()); + + while let Some(parent) = tmp.parent() { + r.push(parent.clone()); + tmp = parent; + } + + r + } + + /// Append path component. + pub fn append(&self, simple: &ProtobufRelativePath) -> ProtobufRelativePath { + if self.path.is_empty() { + ProtobufRelativePath::from(simple.get()) + } else { + ProtobufRelativePath::new(format!("{}.{}", self.path, simple)) + } + } + + /// Append identifier to the path. + pub fn append_ident(&self, simple: &ProtobufIdent) -> ProtobufRelativePath { + self.append(&ProtobufRelativePath::from(simple.clone())) + } + + /// Get first component path and remaining. + pub fn split_first_rem(&self) -> Option<(ProtobufIdent, ProtobufRelativePath)> { + if self.is_empty() { + None + } else { + Some(match self.path.find('.') { + Some(dot) => ( + ProtobufIdent::from(&self.path[..dot]), + ProtobufRelativePath::new(self.path[dot + 1..].to_owned()), + ), + None => ( + ProtobufIdent::from(self.path.clone()), + ProtobufRelativePath::empty(), + ), + }) + } + } +} + +impl From<&'_ str> for ProtobufRelativePath { + fn from(s: &str) -> ProtobufRelativePath { + ProtobufRelativePath::from(s.to_owned()) + } +} + +impl From<String> for ProtobufRelativePath { + fn from(s: String) -> ProtobufRelativePath { + ProtobufRelativePath::new(s) + } +} + +impl From<ProtobufIdent> for ProtobufRelativePath { + fn from(s: ProtobufIdent) -> ProtobufRelativePath { + ProtobufRelativePath::from(s.get()) + } +} + +impl From<Vec<ProtobufIdent>> for ProtobufRelativePath { + fn from(s: Vec<ProtobufIdent>) -> ProtobufRelativePath { + ProtobufRelativePath::from_components(s.into_iter()) + } +} + +impl fmt::Display for ProtobufRelativePath { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.path, f) + } +} + +#[cfg(test)] +mod relative_path_test { + use super::*; + + #[test] + fn parent() { + assert_eq!(None, ProtobufRelativePath::empty().parent()); + assert_eq!( + Some(ProtobufRelativePath::empty()), + ProtobufRelativePath::new("aaa".to_owned()).parent() + ); + assert_eq!( + Some(ProtobufRelativePath::new("abc".to_owned())), + ProtobufRelativePath::new("abc.def".to_owned()).parent() + ); + assert_eq!( + Some(ProtobufRelativePath::new("abc.def".to_owned())), + ProtobufRelativePath::new("abc.def.gh".to_owned()).parent() + ); + } + + #[test] + fn last_part() { + assert_eq!(None, ProtobufRelativePath::empty()._last_part()); + assert_eq!( + Some("aaa"), + ProtobufRelativePath::new("aaa".to_owned())._last_part() + ); + assert_eq!( + Some("def"), + ProtobufRelativePath::new("abc.def".to_owned())._last_part() + ); + assert_eq!( + Some("gh"), + ProtobufRelativePath::new("abc.def.gh".to_owned())._last_part() + ); + } +} + +/// Absolute protobuf path (e. g. package). +/// +/// This is not filesystem path. +#[derive(Clone, Eq, PartialEq, Debug, Hash)] +pub struct ProtobufAbsolutePath { + /// The path. + pub path: String, +} + +impl ProtobufAbsolutePath { + fn root() -> ProtobufAbsolutePath { + ProtobufAbsolutePath::new(String::new()) + } + + /// From string. + pub fn new(path: String) -> ProtobufAbsolutePath { + assert!(path.is_empty() || path.starts_with("."), "{}", path); + assert!(!path.ends_with("."), "{}", path); + ProtobufAbsolutePath { path } + } + + /// The path is empty. + pub fn is_empty(&self) -> bool { + self.path.is_empty() + } + + /// From a path without leading dot. + /// + /// (Protobuf paths start with dot). + pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath { + if path.is_empty() { + ProtobufAbsolutePath::root() + } else { + assert!(!path.starts_with(".")); + assert!(!path.ends_with(".")); + ProtobufAbsolutePath::new(format!(".{}", path)) + } + } + + /// Parse absolute path. + #[allow(dead_code)] + pub fn from_package_path(path: Option<&str>) -> ProtobufAbsolutePath { + match path { + None => ProtobufAbsolutePath::root(), + Some(path) => ProtobufAbsolutePath::from_path_without_dot(path), + } + } + + /// Construct abs path from a string which may start with a dot. + pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath { + if path.starts_with(".") { + ProtobufAbsolutePath::new(path.to_owned()) + } else { + ProtobufAbsolutePath::from_path_without_dot(path) + } + } + + /// Push identifier to the path. + pub fn push_simple(&mut self, simple: ProtobufIdent) { + self.path.push('.'); + self.path.push_str(simple.get()); + } + + /// Push relative path. + pub fn push_relative(&mut self, relative: &ProtobufRelativePath) { + if !relative.is_empty() { + self.path.push('.'); + self.path.push_str(&relative.path); + } + } + + /// Try remove a prefix. + pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> { + if self.path.starts_with(&prefix.path) { + let rem = &self.path[prefix.path.len()..]; + if rem.is_empty() { + return Some(ProtobufRelativePath::empty()); + } + if rem.starts_with('.') { + return Some(ProtobufRelativePath::new(rem[1..].to_owned())); + } + } + None + } +} + +impl From<&'_ str> for ProtobufAbsolutePath { + fn from(s: &str) -> Self { + ProtobufAbsolutePath::new(s.to_owned()) + } +} + +impl From<String> for ProtobufAbsolutePath { + fn from(s: String) -> Self { + ProtobufAbsolutePath::new(s) + } +} + +impl fmt::Display for ProtobufAbsolutePath { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.path, f) + } +} + +#[cfg(test)] +mod absolute_path_test { + use super::*; + + #[test] + fn absolute_path_push_simple() { + let mut foo = ProtobufAbsolutePath::new(".foo".to_owned()); + foo.push_simple(ProtobufIdent::from("bar")); + assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo); + + let mut foo = ProtobufAbsolutePath::root(); + foo.push_simple(ProtobufIdent::from("bar")); + assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo); + } + + #[test] + fn absolute_path_remove_prefix() { + assert_eq!( + Some(ProtobufRelativePath::empty()), + ProtobufAbsolutePath::new(".foo".to_owned()) + .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned())) + ); + assert_eq!( + Some(ProtobufRelativePath::new("bar".to_owned())), + ProtobufAbsolutePath::new(".foo.bar".to_owned()) + .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned())) + ); + assert_eq!( + Some(ProtobufRelativePath::new("baz.qux".to_owned())), + ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned()) + .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned())) + ); + assert_eq!( + None, + ProtobufAbsolutePath::new(".foo.barbaz".to_owned()) + .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned())) + ); + } +} |