1use std::fmt;
2
3use crate::ident::to_snake;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct Module {
8 components: Vec<String>,
9}
10
11impl Module {
12 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 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 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 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 pub fn len(&self) -> usize {
68 self.components.len()
69 }
70
71 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}