• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
2 
3 use std::fmt;
4 use std::str;
5 
6 // A struct that divide a name into serveral parts that meets rust's guidelines.
7 struct NameSpliter<'a> {
8     name: &'a [u8],
9     pos: usize,
10 }
11 
12 impl<'a> NameSpliter<'a> {
new(s: &str) -> NameSpliter13     fn new(s: &str) -> NameSpliter {
14         NameSpliter {
15             name: s.as_bytes(),
16             pos: 0,
17         }
18     }
19 }
20 
21 impl<'a> Iterator for NameSpliter<'a> {
22     type Item = &'a str;
23 
next(&mut self) -> Option<&'a str>24     fn next(&mut self) -> Option<&'a str> {
25         if self.pos == self.name.len() {
26             return None;
27         }
28         // skip all prefix '_'
29         while self.pos < self.name.len() && self.name[self.pos] == b'_' {
30             self.pos += 1;
31         }
32         let mut pos = self.name.len();
33         let mut upper_len = 0;
34         let mut meet_lower = false;
35         for i in self.pos..self.name.len() {
36             let c = self.name[i];
37             if (b'A'..=b'Z').contains(&c) {
38                 if meet_lower {
39                     // So it should be AaA or aaA
40                     pos = i;
41                     break;
42                 }
43                 upper_len += 1;
44             } else if c == b'_' {
45                 pos = i;
46                 break;
47             } else {
48                 meet_lower = true;
49                 if upper_len > 1 {
50                     // So it should be AAa
51                     pos = i - 1;
52                     break;
53                 }
54             }
55         }
56         let s = str::from_utf8(&self.name[self.pos..pos]).unwrap();
57         self.pos = pos;
58         Some(s)
59     }
60 }
61 
62 /// Adjust method name to follow rust-guidelines.
to_snake_case(name: &str) -> String63 pub fn to_snake_case(name: &str) -> String {
64     let mut snake_method_name = String::with_capacity(name.len());
65     for s in NameSpliter::new(name) {
66         snake_method_name.push_str(&s.to_lowercase());
67         snake_method_name.push('_');
68     }
69     snake_method_name.pop();
70     snake_method_name
71 }
72 
73 #[cfg(feature = "protobuf-codec")]
to_camel_case(name: &str) -> String74 pub fn to_camel_case(name: &str) -> String {
75     let mut camel_case_name = String::with_capacity(name.len());
76     for s in NameSpliter::new(name) {
77         let mut chs = s.chars();
78         camel_case_name.extend(chs.next().unwrap().to_uppercase());
79         camel_case_name.push_str(&s[1..].to_lowercase());
80     }
81     camel_case_name
82 }
83 
fq_grpc(item: &str) -> String84 pub fn fq_grpc(item: &str) -> String {
85     format!("::grpcio::{}", item)
86 }
87 
88 pub enum MethodType {
89     Unary,
90     ClientStreaming,
91     ServerStreaming,
92     Duplex,
93 }
94 
95 impl fmt::Display for MethodType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result96     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97         write!(
98             f,
99             "{}",
100             match self {
101                 MethodType::Unary => "MethodType::Unary",
102                 MethodType::ClientStreaming => "MethodType::ClientStreaming",
103                 MethodType::ServerStreaming => "MethodType::ServerStreaming",
104                 MethodType::Duplex => "MethodType::Duplex",
105             }
106         )
107     }
108 }
109 
110 #[cfg(test)]
111 mod test {
112     #[test]
test_snake_name()113     fn test_snake_name() {
114         let cases = vec![
115             ("AsyncRequest", "async_request"),
116             ("asyncRequest", "async_request"),
117             ("async_request", "async_request"),
118             ("createID", "create_id"),
119             ("AsyncRClient", "async_r_client"),
120             ("CreateIDForReq", "create_id_for_req"),
121             ("Create_ID_For_Req", "create_id_for_req"),
122             ("Create_ID_For__Req", "create_id_for_req"),
123             ("ID", "id"),
124             ("id", "id"),
125         ];
126 
127         for (origin, exp) in cases {
128             let res = super::to_snake_case(&origin);
129             assert_eq!(res, exp);
130         }
131     }
132 
133     #[test]
134     #[cfg(feature = "protobuf-codec")]
test_camel_name()135     fn test_camel_name() {
136         let cases = vec![
137             ("AsyncRequest", "AsyncRequest"),
138             ("asyncRequest", "AsyncRequest"),
139             ("async_request", "AsyncRequest"),
140             ("createID", "CreateId"),
141             ("AsyncRClient", "AsyncRClient"),
142             ("async_r_client", "AsyncRClient"),
143             ("CreateIDForReq", "CreateIdForReq"),
144             ("Create_ID_For_Req", "CreateIdForReq"),
145             ("Create_ID_For__Req", "CreateIdForReq"),
146             ("ID", "Id"),
147             ("id", "Id"),
148         ];
149 
150         for (origin, exp) in cases {
151             let res = super::to_camel_case(&origin);
152             assert_eq!(res, exp);
153         }
154     }
155 }
156