ydb_grpc_helpers/
lib.rs

1//! Crate contain helpers for generate grpc imports in ydb-grpc crate.
2//! End customers should use crate ydb.
3
4use std::collections::HashMap;
5
6pub fn get_proto_package(s: &str) -> Option<&str> {
7    for logic_line in s.split(";") {
8        let line = logic_line.trim();
9        if !line.to_lowercase().starts_with("package ") {
10            continue;
11        }
12        let package_name = line["package ".len()..].trim();
13        return Some(package_name);
14    }
15    return None;
16}
17
18#[derive(Clone, Debug, Default, PartialEq)]
19pub struct ProtoModule {
20    file_name: Option<String>,
21    submodules: HashMap<String, ProtoModule>,
22}
23
24impl ProtoModule {
25    pub fn add_file(self: &mut Self, fname: &str) {
26        let parts: Vec<_> = fname.split(".").collect();
27        let mut current = self;
28        for (i, part) in parts.iter().enumerate() {
29            if i == parts.len() - 1 {
30                current.file_name = Some(fname.to_string());
31                continue;
32            }
33            let part = part.to_string();
34            if current.submodules.get(&part).is_none() {
35                current
36                    .submodules
37                    .insert(part.clone(), ProtoModule::default());
38            }
39            current = current.submodules.get_mut(&part).unwrap();
40        }
41    }
42
43    pub fn to_string(self: &Self) -> String {
44        return self.to_string_with_indent("");
45    }
46
47    fn to_string_with_indent(self: &Self, indent: &str) -> String {
48        let mut res = String::new();
49
50        if let Some(file_name) = &self.file_name {
51            res += format!("{}include!(\"{}\");\n", indent, file_name).as_str();
52        }
53
54        let mut keys: Vec<_> = self.submodules.keys().collect();
55        keys.sort();
56
57        for key in keys {
58            res += format!("{}pub mod {} {{\n", indent, key).as_str();
59
60            let m = self.submodules.get(key).unwrap();
61            res += m
62                .to_string_with_indent(format!("{}  ", indent).as_str())
63                .as_str();
64
65            res += format!("{}}}\n", indent).as_str()
66        }
67
68        return res;
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::*;
75
76    #[test]
77    fn test_get_proto_package() {
78        assert_eq!(get_proto_package(""), None);
79        assert_eq!(get_proto_package("asd"), None);
80        assert_eq!(get_proto_package("package asd"), Some("asd"));
81        assert_eq!(get_proto_package("package asd;"), Some("asd"));
82        assert_eq!(
83            get_proto_package(
84                "saldjhfsalkdjf;\
85        package \
86        asd;\
87        "
88            ),
89            Some("asd")
90        );
91    }
92
93    #[test]
94    fn test_add_file() {
95        let mut m = ProtoModule::default();
96        m.add_file("asd.rs");
97        let asd = "asd".to_string();
98        let mut expected_m = ProtoModule::default();
99        expected_m
100            .submodules
101            .insert(asd.clone(), ProtoModule::default());
102        expected_m.submodules.get_mut("asd").unwrap().file_name = Some("asd.rs".to_string());
103        assert_eq!(m, expected_m);
104
105        m.add_file("asd.sub.v1.rs");
106        let sub = "sub".to_string();
107        let v1 = "v1".to_string();
108        expected_m
109            .submodules
110            .get_mut("asd")
111            .unwrap()
112            .submodules
113            .insert(sub.clone(), ProtoModule::default());
114        expected_m
115            .submodules
116            .get_mut("asd")
117            .unwrap()
118            .submodules
119            .get_mut(&sub)
120            .unwrap()
121            .submodules
122            .insert(v1.clone(), ProtoModule::default());
123        expected_m
124            .submodules
125            .get_mut("asd")
126            .unwrap()
127            .submodules
128            .get_mut(&sub)
129            .unwrap()
130            .submodules
131            .get_mut(&v1)
132            .unwrap()
133            .file_name = Some("asd.sub.v1.rs".to_string());
134        assert_eq!(m, expected_m);
135    }
136
137    #[test]
138    fn test_to_string() {
139        let m = ProtoModule {
140            file_name: None,
141            submodules: [(
142                "asd".to_string(),
143                ProtoModule {
144                    file_name: None,
145                    submodules: [(
146                        "v1".to_string(),
147                        ProtoModule {
148                            file_name: Some("asd.v1.rs".to_string()),
149                            submodules: HashMap::default(),
150                        },
151                    )]
152                    .iter()
153                    .cloned()
154                    .collect(),
155                },
156            )]
157            .iter()
158            .cloned()
159            .collect(),
160        };
161
162        let s = m.to_string();
163        let expected = "pub mod asd {
164  pub mod v1 {
165    include!(\"asd.v1.rs\");
166  }
167}
168";
169        assert_eq!(s, expected);
170    }
171}