1 package casing 2 3 // Camel returns the CamelCased name. 4 // 5 // This was moved from the now deprecated github.com/golang/protobuf/protoc-gen-go/generator package 6 // 7 // If there is an interior underscore followed by a lower case letter, 8 // drop the underscore and convert the letter to upper case. 9 // There is a remote possibility of this rewrite causing a name collision, 10 // but it's so remote we're prepared to pretend it's nonexistent - since the 11 // C++ generator lowercases names, it's extremely unlikely to have two fields 12 // with different capitalizations. 13 // In short, _my_field_name_2 becomes XMyFieldName_2. 14 func Camel(s string) string { 15 if s == "" { 16 return "" 17 } 18 t := make([]byte, 0, 32) 19 i := 0 20 if s[0] == '_' { 21 // Need a capital letter; drop the '_'. 22 t = append(t, 'X') 23 i++ 24 } 25 // Invariant: if the next letter is lower case, it must be converted 26 // to upper case. 27 // That is, we process a word at a time, where words are marked by _ or 28 // upper case letter. Digits are treated as words. 29 for ; i < len(s); i++ { 30 c := s[i] 31 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { 32 continue // Skip the underscore in s. 33 } 34 if isASCIIDigit(c) { 35 t = append(t, c) 36 continue 37 } 38 // Assume we have a letter now - if not, it's a bogus identifier. 39 // The next word is a sequence of characters that must start upper case. 40 if isASCIILower(c) { 41 c ^= ' ' // Make it a capital letter. 42 } 43 t = append(t, c) // Guaranteed not lower case. 44 // Accept lower case sequence that follows. 45 for i+1 < len(s) && isASCIILower(s[i+1]) { 46 i++ 47 t = append(t, s[i]) 48 } 49 } 50 return string(t) 51 } 52 53 // And now lots of helper functions. 54 55 // Is c an ASCII lower-case letter? 56 func isASCIILower(c byte) bool { 57 return 'a' <= c && c <= 'z' 58 } 59 60 // Is c an ASCII digit? 61 func isASCIIDigit(c byte) bool { 62 return '0' <= c && c <= '9' 63 } 64