diff --git a/Makefile b/Makefile index ff0afd87006..3d6a6ec7b42 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,8 @@ GO_PLUGIN=bin/protoc-gen-go GO_PLUGIN_PKG=github.com/golang/protobuf/protoc-gen-go SWAGGER_PLUGIN=bin/protoc-gen-swagger SWAGGER_PLUGIN_SRC= utilities/doc.go \ - utilities/name.go \ utilities/pattern.go \ + utilities/trie.go \ protoc-gen-swagger/genswagger/generator.go \ protoc-gen-swagger/genswagger/template.go \ protoc-gen-swagger/main.go diff --git a/examples/examplepb/a_bit_of_everything.pb.gw.go b/examples/examplepb/a_bit_of_everything.pb.gw.go index 4d3bbb091e6..75cf12cc89a 100644 --- a/examples/examplepb/a_bit_of_everything.pb.gw.go +++ b/examples/examplepb/a_bit_of_everything.pb.gw.go @@ -28,7 +28,7 @@ var _ codes.Code var _ io.Reader var _ = runtime.String var _ = json.Marshal -var _ = utilities.PascalFromSnake +var _ = utilities.NewDoubleArray var ( filter_ABitOfEverythingService_Create_0 = &utilities.DoubleArray{Encoding: map[string]int{"float_value": 0, "double_value": 1, "int64_value": 2, "uint64_value": 3, "int32_value": 4, "fixed64_value": 5, "fixed32_value": 6, "bool_value": 7, "string_value": 8, "uint32_value": 9, "sfixed32_value": 10, "sfixed64_value": 11, "sint32_value": 12, "sint64_value": 13}, Base: []int{1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Check: []int{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}} diff --git a/examples/examplepb/echo_service.pb.gw.go b/examples/examplepb/echo_service.pb.gw.go index 9927d88328f..1e7f121f023 100644 --- a/examples/examplepb/echo_service.pb.gw.go +++ b/examples/examplepb/echo_service.pb.gw.go @@ -27,7 +27,7 @@ var _ codes.Code var _ io.Reader var _ = runtime.String var _ = json.Marshal -var _ = utilities.PascalFromSnake +var _ = utilities.NewDoubleArray func request_EchoService_Echo_0(ctx context.Context, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, error) { var protoReq SimpleMessage diff --git a/examples/examplepb/flow_combination.pb.gw.go b/examples/examplepb/flow_combination.pb.gw.go index a725b8e684d..3839f631998 100644 --- a/examples/examplepb/flow_combination.pb.gw.go +++ b/examples/examplepb/flow_combination.pb.gw.go @@ -27,7 +27,7 @@ var _ codes.Code var _ io.Reader var _ = runtime.String var _ = json.Marshal -var _ = utilities.PascalFromSnake +var _ = utilities.NewDoubleArray func request_FlowCombination_RpcEmptyRpc_0(ctx context.Context, client FlowCombinationClient, req *http.Request, pathParams map[string]string) (proto.Message, error) { var protoReq EmptyProto diff --git a/protoc-gen-grpc-gateway/descriptor/types.go b/protoc-gen-grpc-gateway/descriptor/types.go index afd18ddf856..5cbe6936866 100644 --- a/protoc-gen-grpc-gateway/descriptor/types.go +++ b/protoc-gen-grpc-gateway/descriptor/types.go @@ -5,8 +5,8 @@ import ( "strings" "github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway/httprule" - "github.com/gengo/grpc-gateway/utilities" descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + gogen "github.com/golang/protobuf/protoc-gen-go/generator" ) // GoPackage represents a golang package @@ -235,15 +235,15 @@ type FieldPathComponent struct { // RHS returns a right-hand-side expression in go for this field. func (c FieldPathComponent) RHS() string { - return utilities.PascalFromSnake(c.Name) + return gogen.CamelCase(c.Name) } // LHS returns a left-hand-side expression in go for this field. func (c FieldPathComponent) LHS() string { if c.Target.Message.File.proto2() { - return fmt.Sprintf("Get%s()", utilities.PascalFromSnake(c.Name)) + return fmt.Sprintf("Get%s()", gogen.CamelCase(c.Name)) } - return utilities.PascalFromSnake(c.Name) + return gogen.CamelCase(c.Name) } var ( diff --git a/protoc-gen-grpc-gateway/gengateway/template.go b/protoc-gen-grpc-gateway/gengateway/template.go index 57bd5210ac1..6eaff63bb7e 100644 --- a/protoc-gen-grpc-gateway/gengateway/template.go +++ b/protoc-gen-grpc-gateway/gengateway/template.go @@ -114,7 +114,7 @@ var _ codes.Code var _ io.Reader var _ = runtime.String var _ = json.Marshal -var _ = utilities.PascalFromSnake +var _ = utilities.NewDoubleArray `)) handlerTemplate = template.Must(template.New("handler").Parse(` diff --git a/runtime/query.go b/runtime/query.go index 82b07886ca3..e7592307aca 100644 --- a/runtime/query.go +++ b/runtime/query.go @@ -12,7 +12,7 @@ import ( ) // PopulateQueryParameters populates "values" into "msg". -// A value is ignored if its key starts with one of the elements in "filters". +// A value is ignored if its key starts with one of the elements in "filter". func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error { for key, values := range values { fieldPath := strings.Split(key, ".") @@ -44,7 +44,7 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values [] if !isLast && m.Kind() != reflect.Struct { return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, ".")) } - f := m.FieldByName(utilities.PascalFromSnake(fieldName)) + f := fieldByProtoName(m, fieldName) if !f.IsValid() { glog.Warningf("field not found in %T: %s", msg, strings.Join(fieldPath, ".")) return nil @@ -83,6 +83,18 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values [] return populateField(m, values[0]) } +// fieldByProtoName looks up a field whose corresponding protobuf field name is "name". +// "m" must be a struct value. It returns zero reflect.Value if no such field found. +func fieldByProtoName(m reflect.Value, name string) reflect.Value { + props := proto.GetProperties(m.Type()) + for _, p := range props.Prop { + if p.OrigName == name { + return m.FieldByName(p.Name) + } + } + return reflect.Value{} +} + func populateRepeatedField(f reflect.Value, values []string) error { elemType := f.Type().Elem() conv, ok := convFromType[elemType.Kind()] diff --git a/utilities/name.go b/utilities/name.go deleted file mode 100644 index 01fdb6097b2..00000000000 --- a/utilities/name.go +++ /dev/null @@ -1,82 +0,0 @@ -package utilities - -// PascalFromSnake converts an identifier in snake_case into PascalCase. -func PascalFromSnake(s string) string { - // adopted from github.com/golang/protobuf/protoc-gen-go/generator/generator.go - // - // Copyright 2010 The Go Authors. All rights reserved. - // https://github.com/golang/protobuf - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // * Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // * Redistributions in binary form must reproduce the above - // copyright notice, this list of conditions and the following disclaimer - // in the documentation and/or other materials provided with the - // distribution. - // * Neither the name of Google Inc. nor the names of its - // contributors may be used to endorse or promote products derived from - // this software without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - if s == "" { - return "" - } - t := make([]byte, 0, 32) - i := 0 - if s[0] == '_' { - // Need a capital letter; drop the '_'. - t = append(t, 'X') - i++ - } - // Invariant: if the next letter is lower case, it must be converted - // to upper case. - // That is, we process a word at a time, where words are marked by _ or - // upper case letter. Digits are treated as words. - for ; i < len(s); i++ { - c := s[i] - if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { - continue // Skip the underscore in s. - } - if isASCIIDigit(c) { - t = append(t, c) - continue - } - // Assume we have a letter now - if not, it's a bogus identifier. - // The next word is a sequence of characters that must start upper case. - if isASCIILower(c) { - c ^= ' ' // Make it a capital letter. - } - t = append(t, c) // Guaranteed not lower case. - // Accept lower case sequence that follows. - for i+1 < len(s) && isASCIILower(s[i+1]) { - i++ - t = append(t, s[i]) - } - } - return string(t) -} - -// Is c an ASCII lower-case letter? -func isASCIILower(c byte) bool { - return 'a' <= c && c <= 'z' -} - -// Is c an ASCII digit? -func isASCIIDigit(c byte) bool { - return '0' <= c && c <= '9' -} diff --git a/utilities/name_test.go b/utilities/name_test.go deleted file mode 100644 index a33dde74e8b..00000000000 --- a/utilities/name_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package utilities_test - -import ( - "testing" - - "github.com/gengo/grpc-gateway/utilities" -) - -func TestPascalToSnake(t *testing.T) { - for _, spec := range []struct { - input, want string - }{ - {input: "value", want: "Value"}, - {input: "prefixed_value", want: "PrefixedValue"}, - {input: "foo_id", want: "FooId"}, - } { - got := utilities.PascalFromSnake(spec.input) - if got != spec.want { - t.Errorf("utilities.PascalFromSnake(%q) = %q; want %q", spec.input, got, spec.want) - } - } -}