<NME> protobuf_rel_path.rs
<BEF> #![doc(hidden)]

use std::fmt;
use std::iter;
use std::mem;
use std::ops::Deref;

use crate::protobuf_abs_path::ProtobufAbsPath;
use crate::protobuf_ident::ProtobufIdent;
use crate::ProtobufIdentRef;

impl From<String> for ProtobufRelPath {
    fn from(s: String) -> ProtobufRelPath {
        ProtobufRelPath::new(s)
    }
}

impl From<&'_ str> for ProtobufRelPath {
    fn from(s: &str) -> ProtobufRelPath {
        ProtobufRelPath::from(s.to_owned())
    }
}

impl ProtobufRelPathRef {
    pub fn as_str(&self) -> &str {
        &self
    }

    pub fn empty() -> &'static ProtobufRelPathRef {
        Self::new("")
    }

    pub fn new(path: &str) -> &ProtobufRelPathRef {
        assert!(!path.starts_with('.'));
        // SAFETY: repr(transparent)
        unsafe { mem::transmute(path) }
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn split_first_rem(&self) -> Option<(&ProtobufIdentRef, &ProtobufRelPathRef)> {
        if self.is_empty() {
            None
        } else {
            match self.0.find('.') {
                Some(i) => Some((
                    ProtobufIdentRef::new(&self.0[..i]),
                    ProtobufRelPathRef::new(&self.0[i + 1..]),
                )),
                None => Some((ProtobufIdentRef::new(&self.0), ProtobufRelPathRef::empty())),
            }
        }
    }

    pub fn components(&self) -> impl Iterator<Item = &ProtobufIdentRef> {
        iter::once(&self.0)
            .filter(|s| !s.is_empty())
            .flat_map(|p| p.split('.').map(|s| ProtobufIdentRef::new(s)))
    }

    fn parent(&self) -> Option<&ProtobufRelPathRef> {
        if self.0.is_empty() {
            None
        } else {
            match self.0.rfind('.') {
                Some(i) => Some(ProtobufRelPathRef::new(&self.0[..i])),
                None => Some(ProtobufRelPathRef::empty()),
            }
        }
    }

    pub fn self_and_parents(&self) -> Vec<&ProtobufRelPathRef> {
        let mut tmp = self.clone();

        let mut r = Vec::new();

        r.push(self.clone());

        while let Some(parent) = tmp.parent() {
            r.push(parent);
            tmp = parent;
        }

        r
    }

    pub fn append(&self, simple: &ProtobufRelPathRef) -> ProtobufRelPath {
        if self.is_empty() {
            simple.to_owned()
        } else if simple.is_empty() {
            self.to_owned()
        } else {
            ProtobufRelPath {
                path: format!("{}.{}", &self.0, &simple.0),
            }
        }
    }

    pub fn append_ident(&self, simple: &ProtobufIdentRef) -> ProtobufRelPath {
        self.append(&ProtobufRelPath::from(simple.to_owned()))
    }

    pub fn to_absolute(&self) -> ProtobufAbsPath {
        self.to_owned().into_absolute()
    }

    pub fn to_owned(&self) -> ProtobufRelPath {
        ProtobufRelPath {
            path: self.0.to_owned(),
        }
    }
}

#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ProtobufRelativePath {
    path: Vec<ProtobufIdent>,

    pub fn empty() -> ProtobufRelPath {
        ProtobufRelPath {
            path: String::new(),
        }
    }

    pub fn new<S: Into<String>>(path: S) -> ProtobufRelPath {
        let path = path.into();
        // Validate
        ProtobufRelPathRef::new(&path);
        ProtobufRelPath { path }
    }

    pub fn from_components<'a, I: IntoIterator<Item = &'a ProtobufIdentRef>>(
        i: I,
    ) -> ProtobufRelPath {
        let v: Vec<&str> = i.into_iter().map(|c| c.as_str()).collect();
        ProtobufRelPath::from(v.join("."))
    }

    pub fn into_absolute(self) -> ProtobufAbsPath {
        if self.is_empty() {
            ProtobufAbsPath::root()
        } else {
            ProtobufAbsPath::from(format!(".{}", self))
        }
    }
}

#[doc(hidden)]
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ProtobufRelPath {
    pub(crate) path: String,
}

#[doc(hidden)]
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct ProtobufRelPathRef(str);

impl Deref for ProtobufRelPathRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

impl Deref for ProtobufRelPath {
    type Target = ProtobufRelPathRef;

    fn deref(&self) -> &ProtobufRelPathRef {
        ProtobufRelPathRef::new(&self.path)
    }
}

impl From<ProtobufIdent> for ProtobufRelPath {
    fn from(s: ProtobufIdent) -> ProtobufRelPath {
        ProtobufRelPath { path: s.into() }
    }
}

impl fmt::Display for ProtobufRelPathRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &self.0)
    }
}

impl fmt::Display for ProtobufRelPath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.path)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn parent() {
        assert_eq!(None, ProtobufRelPathRef::empty().parent());
        assert_eq!(
            Some(ProtobufRelPathRef::empty()),
            ProtobufRelPath::new("aaa".to_owned()).parent()
        );
        assert_eq!(
            Some(ProtobufRelPathRef::new("abc")),
            ProtobufRelPath::new("abc.def".to_owned()).parent()
        );
        assert_eq!(
            Some(ProtobufRelPathRef::new("abc.def")),
            ProtobufRelPath::new("abc.def.gh".to_owned()).parent()
        );
    }

    #[test]
    fn self_and_parents() {
        assert_eq!(
            vec![
                ProtobufRelPathRef::new("ab.cde.fghi"),
                ProtobufRelPathRef::new("ab.cde"),
                ProtobufRelPathRef::new("ab"),
                ProtobufRelPathRef::empty(),
            ],
            ProtobufRelPath::new("ab.cde.fghi".to_owned()).self_and_parents()
        );
    }

    #[test]
    fn components() {
        assert_eq!(
            Vec::<&ProtobufIdentRef>::new(),
            ProtobufRelPath::empty().components().collect::<Vec<_>>()
        );
        assert_eq!(
            vec![ProtobufIdentRef::new("ab")],
            ProtobufRelPath::new("ab").components().collect::<Vec<_>>()
        );
        assert_eq!(
            vec![ProtobufIdentRef::new("ab"), ProtobufIdentRef::new("cd")],
            ProtobufRelPath::new("ab.cd")
                .components()
                .collect::<Vec<_>>()
        );
    }
}

<MSG> Better doc

<DFF> @@ -113,6 +113,7 @@ impl ProtobufRelativePath {
     }
 }
 
+#[doc(hidden)]
 #[derive(Debug, Eq, PartialEq, Clone, Hash)]
 pub struct ProtobufRelativePath {
     path: Vec<ProtobufIdent>,

{'commit': "diff --git a/protobuf-parse/src/case_convert.rs b/protobuf-parse/src/case_convert.rs\nindex 9c7c7b73..6da07473 100644\n--- a/protobuf-parse/src/case_convert.rs\n+++ b/protobuf-parse/src/case_convert.rs\n@@ -1,7 +1,6 @@\n-#![doc(hidden)]\n-\n // copy-paste from Google Protobuf\n // must be kept in sync with Google for JSON interop\n+#[doc(hidden)]\n pub fn camel_case(input: &str) -> String {\n     let mut capitalize_next = true;\n     let mut result = String::new();\n@@ -21,6 +20,7 @@ pub fn camel_case(input: &str) -> String {\n     result\n }\n \n+#[doc(hidden)]\n pub fn snake_case(input: &str) -> String {\n     let mut result = String::new();\n \ndiff --git a/protobuf-parse/src/lib.rs b/protobuf-parse/src/lib.rs\nindex 54334c2d..441c04db 100644\n--- a/protobuf-parse/src/lib.rs\n+++ b/protobuf-parse/src/lib.rs\n@@ -1,3 +1,8 @@\n+//! Parse `.proto` files.\n+//!\n+//! Files can be parsed using pure Rust parser (mod `pure`)\n+//! or using the `protoc` command (mod `protoc`).\n+\n mod case_convert;\n mod linked_hash_map;\n mod parse_and_typecheck;\ndiff --git a/protobuf-parse/src/protobuf_abs_path.rs b/protobuf-parse/src/protobuf_abs_path.rs\nindex e6643540..234083b1 100644\n--- a/protobuf-parse/src/protobuf_abs_path.rs\n+++ b/protobuf-parse/src/protobuf_abs_path.rs\n@@ -8,6 +8,7 @@ use crate::protobuf_rel_path::ProtobufRelativePath;\n \n /// Protobuf absolute name (e. g. `.foo.Bar`).\n #[derive(Clone, Eq, PartialEq, Debug, Hash)]\n+#[doc(hidden)]\n pub struct ProtobufAbsolutePath {\n     pub path: String,\n }\ndiff --git a/protobuf-parse/src/protobuf_ident.rs b/protobuf-parse/src/protobuf_ident.rs\nindex 9a9b24ea..e9953972 100644\n--- a/protobuf-parse/src/protobuf_ident.rs\n+++ b/protobuf-parse/src/protobuf_ident.rs\n@@ -4,6 +4,7 @@ use std::fmt;\n \n /// Identifier in `.proto` file\n #[derive(Eq, PartialEq, Debug, Clone, Hash)]\n+#[doc(hidden)]\n pub struct ProtobufIdent(String);\n \n impl From<&'_ str> for ProtobufIdent {\ndiff --git a/protobuf-parse/src/protobuf_rel_path.rs b/protobuf-parse/src/protobuf_rel_path.rs\nindex 9ee71836..ff5f8ae0 100644\n--- a/protobuf-parse/src/protobuf_rel_path.rs\n+++ b/protobuf-parse/src/protobuf_rel_path.rs\n@@ -113,6 +113,7 @@ impl ProtobufRelativePath {\n     }\n }\n \n+#[doc(hidden)]\n #[derive(Debug, Eq, PartialEq, Clone, Hash)]\n pub struct ProtobufRelativePath {\n     path: Vec<ProtobufIdent>,\n", 'commit_subject': 'Better doc', 'repo_name': 'stepancheg/rust-protobuf', 'committer': {'name': 'Stiopa Koltsov', 'email': 'e150b500682c3c55bd53434656d52cd8d6051776@gmail.com', 'time_sec': '1635748029', 'tz_offset': '0', 'date': {'seconds': '1635748029'}}, 'commit_tree': '61df435706011fa0b08d85a20d0ebdf8697dda62', 'commit_message': 'Better doc\n', 'language_name': 'C++', 'license': 'mit', 'hunks': '@@ -113,6 +113,7 @@ impl ProtobufRelativePath {\n     }\n }\n \n+#[doc(hidden)]\n #[derive(Debug, Eq, PartialEq, Clone, Hash)]\n pub struct ProtobufRelativePath {\n     path: Vec<ProtobufIdent>,\n', 'addition_count': 1, 'deletion_count': 0, 'src_file': 'a/protobuf-parse/src/protobuf_rel_path.rs', 'tgt_file': 'b/protobuf-parse/src/protobuf_rel_path.rs', 'file_extension': '.rs', 'before_file': '#![doc(hidden)]\n\nuse std::fmt;\nuse std::iter;\nuse std::mem;\nuse std::ops::Deref;\n\nuse crate::protobuf_abs_path::ProtobufAbsPath;\nuse crate::protobuf_ident::ProtobufIdent;\nuse crate::ProtobufIdentRef;\n\nimpl From<String> for ProtobufRelPath {\n    fn from(s: String) -> ProtobufRelPath {\n        ProtobufRelPath::new(s)\n    }\n}\n\nimpl From<&\'_ str> for ProtobufRelPath {\n    fn from(s: &str) -> ProtobufRelPath {\n        ProtobufRelPath::from(s.to_owned())\n    }\n}\n\nimpl ProtobufRelPathRef {\n    pub fn as_str(&self) -> &str {\n        &self\n    }\n\n    pub fn empty() -> &\'static ProtobufRelPathRef {\n        Self::new("")\n    }\n\n    pub fn new(path: &str) -> &ProtobufRelPathRef {\n        assert!(!path.starts_with(\'.\'));\n        // SAFETY: repr(transparent)\n        unsafe { mem::transmute(path) }\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n\n    pub fn split_first_rem(&self) -> Option<(&ProtobufIdentRef, &ProtobufRelPathRef)> {\n        if self.is_empty() {\n            None\n        } else {\n            match self.0.find(\'.\') {\n                Some(i) => Some((\n                    ProtobufIdentRef::new(&self.0[..i]),\n                    ProtobufRelPathRef::new(&self.0[i + 1..]),\n                )),\n                None => Some((ProtobufIdentRef::new(&self.0), ProtobufRelPathRef::empty())),\n            }\n        }\n    }\n\n    pub fn components(&self) -> impl Iterator<Item = &ProtobufIdentRef> {\n        iter::once(&self.0)\n            .filter(|s| !s.is_empty())\n            .flat_map(|p| p.split(\'.\').map(|s| ProtobufIdentRef::new(s)))\n    }\n\n    fn parent(&self) -> Option<&ProtobufRelPathRef> {\n        if self.0.is_empty() {\n            None\n        } else {\n            match self.0.rfind(\'.\') {\n                Some(i) => Some(ProtobufRelPathRef::new(&self.0[..i])),\n                None => Some(ProtobufRelPathRef::empty()),\n            }\n        }\n    }\n\n    pub fn self_and_parents(&self) -> Vec<&ProtobufRelPathRef> {\n        let mut tmp = self.clone();\n\n        let mut r = Vec::new();\n\n        r.push(self.clone());\n\n        while let Some(parent) = tmp.parent() {\n            r.push(parent);\n            tmp = parent;\n        }\n\n        r\n    }\n\n    pub fn append(&self, simple: &ProtobufRelPathRef) -> ProtobufRelPath {\n        if self.is_empty() {\n            simple.to_owned()\n        } else if simple.is_empty() {\n            self.to_owned()\n        } else {\n            ProtobufRelPath {\n                path: format!("{}.{}", &self.0, &simple.0),\n            }\n        }\n    }\n\n    pub fn append_ident(&self, simple: &ProtobufIdentRef) -> ProtobufRelPath {\n        self.append(&ProtobufRelPath::from(simple.to_owned()))\n    }\n\n    pub fn to_absolute(&self) -> ProtobufAbsPath {\n        self.to_owned().into_absolute()\n    }\n\n    pub fn to_owned(&self) -> ProtobufRelPath {\n        ProtobufRelPath {\n            path: self.0.to_owned(),\n        }\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Clone, Hash)]\npub struct ProtobufRelativePath {\n    path: Vec<ProtobufIdent>,\n\n    pub fn empty() -> ProtobufRelPath {\n        ProtobufRelPath {\n            path: String::new(),\n        }\n    }\n\n    pub fn new<S: Into<String>>(path: S) -> ProtobufRelPath {\n        let path = path.into();\n        // Validate\n        ProtobufRelPathRef::new(&path);\n        ProtobufRelPath { path }\n    }\n\n    pub fn from_components<\'a, I: IntoIterator<Item = &\'a ProtobufIdentRef>>(\n        i: I,\n    ) -> ProtobufRelPath {\n        let v: Vec<&str> = i.into_iter().map(|c| c.as_str()).collect();\n        ProtobufRelPath::from(v.join("."))\n    }\n\n    pub fn into_absolute(self) -> ProtobufAbsPath {\n        if self.is_empty() {\n            ProtobufAbsPath::root()\n        } else {\n            ProtobufAbsPath::from(format!(".{}", self))\n        }\n    }\n}\n\n#[doc(hidden)]\n#[derive(Debug, Eq, PartialEq, Clone, Hash)]\npub struct ProtobufRelPath {\n    pub(crate) path: String,\n}\n\n#[doc(hidden)]\n#[derive(Debug, Eq, PartialEq, Hash)]\n#[repr(transparent)]\npub struct ProtobufRelPathRef(str);\n\nimpl Deref for ProtobufRelPathRef {\n    type Target = str;\n\n    fn deref(&self) -> &str {\n        &self.0\n    }\n}\n\nimpl Deref for ProtobufRelPath {\n    type Target = ProtobufRelPathRef;\n\n    fn deref(&self) -> &ProtobufRelPathRef {\n        ProtobufRelPathRef::new(&self.path)\n    }\n}\n\nimpl From<ProtobufIdent> for ProtobufRelPath {\n    fn from(s: ProtobufIdent) -> ProtobufRelPath {\n        ProtobufRelPath { path: s.into() }\n    }\n}\n\nimpl fmt::Display for ProtobufRelPathRef {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, "{}", &self.0)\n    }\n}\n\nimpl fmt::Display for ProtobufRelPath {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, "{}", self.path)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn parent() {\n        assert_eq!(None, ProtobufRelPathRef::empty().parent());\n        assert_eq!(\n            Some(ProtobufRelPathRef::empty()),\n            ProtobufRelPath::new("aaa".to_owned()).parent()\n        );\n        assert_eq!(\n            Some(ProtobufRelPathRef::new("abc")),\n            ProtobufRelPath::new("abc.def".to_owned()).parent()\n        );\n        assert_eq!(\n            Some(ProtobufRelPathRef::new("abc.def")),\n            ProtobufRelPath::new("abc.def.gh".to_owned()).parent()\n        );\n    }\n\n    #[test]\n    fn self_and_parents() {\n        assert_eq!(\n            vec![\n                ProtobufRelPathRef::new("ab.cde.fghi"),\n                ProtobufRelPathRef::new("ab.cde"),\n                ProtobufRelPathRef::new("ab"),\n                ProtobufRelPathRef::empty(),\n            ],\n            ProtobufRelPath::new("ab.cde.fghi".to_owned()).self_and_parents()\n        );\n    }\n\n    #[test]\n    fn components() {\n        assert_eq!(\n            Vec::<&ProtobufIdentRef>::new(),\n            ProtobufRelPath::empty().components().collect::<Vec<_>>()\n        );\n        assert_eq!(\n            vec![ProtobufIdentRef::new("ab")],\n            ProtobufRelPath::new("ab").components().collect::<Vec<_>>()\n        );\n        assert_eq!(\n            vec![ProtobufIdentRef::new("ab"), ProtobufIdentRef::new("cd")],\n            ProtobufRelPath::new("ab.cd")\n                .components()\n                .collect::<Vec<_>>()\n        );\n    }\n}\n', 'message': 'Better doc\n', 'author_name': 'Stiopa Koltsov', 'lang': 'rs'}