1 use crate::gen::inside::protobuf_crate_path;
2 use crate::gen::rust::ident::RustIdent;
3 use crate::gen::rust::path::RustPath;
4 use crate::gen::strx;
5 use crate::gen::well_known_types::WELL_KNOWN_TYPES_PROTO_FILE_FULL_NAMES;
6 use crate::Customize;
7
8 // Copy-pasted from libsyntax.
ident_start(c: char) -> bool9 fn ident_start(c: char) -> bool {
10 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
11 }
12
13 // Copy-pasted from libsyntax.
ident_continue(c: char) -> bool14 fn ident_continue(c: char) -> bool {
15 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'
16 }
17
proto_path_to_rust_mod(path: &str) -> RustIdent18 pub(crate) fn proto_path_to_rust_mod(path: &str) -> RustIdent {
19 let without_dir = strx::remove_to(path, std::path::is_separator);
20 let without_suffix = strx::remove_suffix(without_dir, ".proto");
21
22 let name = without_suffix
23 .chars()
24 .enumerate()
25 .map(|(i, c)| {
26 let valid = if i == 0 {
27 ident_start(c)
28 } else {
29 ident_continue(c)
30 };
31 if valid {
32 c
33 } else {
34 '_'
35 }
36 })
37 .collect::<String>();
38
39 RustIdent::new(&name)
40 }
41
42 /// Used in protobuf-codegen-identical-test
proto_name_to_rs(proto_file_path: &str) -> String43 pub fn proto_name_to_rs(proto_file_path: &str) -> String {
44 format!("{}.rs", proto_path_to_rust_mod(proto_file_path))
45 }
46
proto_path_to_fn_file_descriptor( proto_path: &str, customize: &Customize, ) -> RustPath47 pub(crate) fn proto_path_to_fn_file_descriptor(
48 proto_path: &str,
49 customize: &Customize,
50 ) -> RustPath {
51 let protobuf_crate = protobuf_crate_path(customize);
52 match proto_path {
53 "rustproto.proto" => protobuf_crate.append("rustproto::file_descriptor".into()),
54 "google/protobuf/descriptor.proto" => {
55 protobuf_crate.append("descriptor::file_descriptor".into())
56 }
57 s if WELL_KNOWN_TYPES_PROTO_FILE_FULL_NAMES.contains(&s) => protobuf_crate
58 .append_ident("well_known_types".into())
59 .append_ident(proto_path_to_rust_mod(s))
60 .append_ident("file_descriptor".into()),
61 s => RustPath::super_path()
62 .append_ident(proto_path_to_rust_mod(s))
63 .append_ident("file_descriptor".into()),
64 }
65 }
66
67 #[cfg(test)]
68 mod test {
69 use super::proto_path_to_rust_mod;
70 use crate::gen::rust::ident::RustIdent;
71
72 #[test]
test_mod_path_proto_ext()73 fn test_mod_path_proto_ext() {
74 assert_eq!(
75 RustIdent::from("proto"),
76 proto_path_to_rust_mod("proto.proto")
77 );
78 }
79
80 #[test]
test_mod_path_unknown_ext()81 fn test_mod_path_unknown_ext() {
82 assert_eq!(
83 RustIdent::from("proto_proto3"),
84 proto_path_to_rust_mod("proto.proto3")
85 );
86 }
87
88 #[test]
test_mod_path_empty_ext()89 fn test_mod_path_empty_ext() {
90 assert_eq!(RustIdent::from("proto"), proto_path_to_rust_mod("proto"));
91 }
92
93 #[test]
test_mod_path_dir()94 fn test_mod_path_dir() {
95 assert_eq!(
96 RustIdent::from("baz"),
97 proto_path_to_rust_mod("foo/bar/baz.proto"),
98 )
99 }
100
101 #[cfg(target_os = "windows")]
102 #[test]
test_mod_path_dir_backslashes()103 fn test_mod_path_dir_backslashes() {
104 assert_eq!(
105 RustIdent::from("baz"),
106 proto_path_to_rust_mod("foo\\bar\\baz.proto"),
107 )
108 }
109 }
110