prost_build/
module.rs

1use std::fmt;
2
3use crate::ident::to_snake;
4
5/// A Rust module path for a Protobuf package.
6#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct Module {
8    components: Vec<String>,
9}
10
11impl Module {
12    /// Construct a module path from an iterator of parts.
13    pub fn from_parts<I>(parts: I) -> Self
14    where
15        I: IntoIterator,
16        I::Item: Into<String>,
17    {
18        Self {
19            components: parts.into_iter().map(|s| s.into()).collect(),
20        }
21    }
22
23    /// Construct a module path from a Protobuf package name.
24    ///
25    /// Constituent parts are automatically converted to snake case in order to follow
26    /// Rust module naming conventions.
27    pub fn from_protobuf_package_name(name: &str) -> Self {
28        Self {
29            components: name
30                .split('.')
31                .filter(|s| !s.is_empty())
32                .map(to_snake)
33                .collect(),
34        }
35    }
36
37    /// An iterator over the parts of the path.
38    pub fn parts(&self) -> impl Iterator<Item = &str> {
39        self.components.iter().map(|s| s.as_str())
40    }
41
42    #[must_use]
43    #[inline(always)]
44    pub(crate) fn starts_with(&self, needle: &[String]) -> bool
45    where
46        String: PartialEq,
47    {
48        self.components.starts_with(needle)
49    }
50
51    /// Format the module path into a filename for generated Rust code.
52    ///
53    /// If the module path is empty, `default` is used to provide the root of the filename.
54    pub fn to_file_name_or(&self, default: &str) -> String {
55        let mut root = if self.components.is_empty() {
56            default.to_owned()
57        } else {
58            self.components.join(".")
59        };
60
61        root.push_str(".rs");
62
63        root
64    }
65
66    /// The number of parts in the module's path.
67    pub fn len(&self) -> usize {
68        self.components.len()
69    }
70
71    /// Whether the module's path contains any components.
72    pub fn is_empty(&self) -> bool {
73        self.components.is_empty()
74    }
75
76    pub(crate) fn part(&self, idx: usize) -> &str {
77        self.components[idx].as_str()
78    }
79}
80
81impl fmt::Display for Module {
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        let mut parts = self.parts();
84        if let Some(first) = parts.next() {
85            f.write_str(first)?;
86        }
87        for part in parts {
88            f.write_str("::")?;
89            f.write_str(part)?;
90        }
91        Ok(())
92    }
93}