diff --git a/encoding/protobuf/jsonpb/decoder.go b/encoding/protobuf/jsonpb/decoder.go index 7b616d37a..37d062a37 100644 --- a/encoding/protobuf/jsonpb/decoder.go +++ b/encoding/protobuf/jsonpb/decoder.go @@ -51,7 +51,7 @@ type Option func() // disjunction of strings: // this is assumed to represent a protobuf enum value. Strings // are left as is. For integers, the disjunction is resolved -// by converting it to the string that has a corresponding #intValue +// by converting it to the string that has a corresponding #enumValue // value. // {}: JSON objects representing any values will be left as is. // If the CUE type corresponding to the URL can be determined within @@ -245,7 +245,7 @@ func (r *rewriter) rewrite(schema cue.Value, expr ast.Expr) (x ast.Expr) { values = []cue.Value{schema} // allow single values. } for _, v := range values { - i, err := v.LookupPath(cue.MakePath(cue.Def("#intValue"))).Int64() + i, err := v.LookupPath(cue.MakePath(cue.Def("#enumValue"))).Int64() if err == nil && i == enum { str, err := v.String() if err != nil { diff --git a/encoding/protobuf/jsonpb/testdata/decoder/enums.txtar b/encoding/protobuf/jsonpb/testdata/decoder/enums.txtar index 5c4d1a2b6..5ef453c4b 100644 --- a/encoding/protobuf/jsonpb/testdata/decoder/enums.txtar +++ b/encoding/protobuf/jsonpb/testdata/decoder/enums.txtar @@ -1,15 +1,15 @@ -- schema.cue -- enum: [string]: { "foo" - #intValue: 1 + #enumValue: 1 } | { "bar" - #intValue: 2 + #enumValue: 2 } -singleEnum: { "single", #intValue: 1 } +singleEnum: { "single", #enumValue: 1 } -badEnum: { string, #intValue: 1 } | { "two", #intValue: 2 } +badEnum: { string, #enumValue: 1 } | { "two", #enumValue: 2 } -- data.cue -- enum: asIs: "foo" diff --git a/encoding/protobuf/parse.go b/encoding/protobuf/parse.go index a272c3479..47d2ed38a 100644 --- a/encoding/protobuf/parse.go +++ b/encoding/protobuf/parse.go @@ -617,6 +617,8 @@ func (p *protoConverter) enum(x *proto.Enum) { } } + lastSingle := false + // The line comments for an enum field need to attach after the '|', which // is only known at the next iteration. var lastComment *proto.Comment @@ -624,36 +626,42 @@ func (p *protoConverter) enum(x *proto.Enum) { switch y := v.(type) { case *proto.EnumField: // Add enum value to map + intValue := ast.NewLit(token.INT, strconv.Itoa(y.Integer)) f := &ast.Field{ Label: p.stringLit(y.Position, y.Name), - Value: ast.NewLit(token.INT, strconv.Itoa(y.Integer)), + Value: intValue, } valueMap.Elts = append(valueMap.Elts, f) // add to enum disjunction value := p.stringLit(y.Position, y.Name) - var e ast.Expr = value - // Make the first value the default value. - if i > 0 { - value.ValuePos = newline + embed := &ast.EmbedDecl{Expr: value} + ast.SetRelPos(embed, token.Blank) + field := &ast.Field{Label: ast.NewIdent("#enumValue"), Value: intValue} + st := &ast.StructLit{ + Lbrace: token.Blank.Pos(), + Elts: []ast.Decl{embed, field}, } - addComments(e, i, y.Comment, nil) - if enum.Value != nil { - e = &ast.BinaryExpr{X: enum.Value, Op: token.OR, Y: e} - if cg := comment(lastComment, false); cg != nil { - cg.Position = 2 - e.AddComment(cg) + + addComments(embed, 0, y.Comment, y.InlineComment) + if y.Comment == nil && y.InlineComment == nil { + ast.SetRelPos(field, token.Blank) + ast.SetRelPos(field.Label, token.Blank) + st.Rbrace = token.Blank.Pos() + if i > 0 && lastSingle { + st.Lbrace = token.Newline.Pos() } + lastSingle = true + } else { + lastSingle = false } - enum.Value = e + var e ast.Expr = st - if y.Comment != nil { - lastComment = nil - addComments(f, 0, nil, y.InlineComment) - } else { - lastComment = y.InlineComment + if enum.Value != nil { + e = &ast.BinaryExpr{X: enum.Value, Op: token.OR, Y: e} } + enum.Value = e // a := fmt.Sprintf("@protobuf(enum,name=%s)", y.Name) // f.Attrs = append(f.Attrs, &ast.Attribute{Text: a}) diff --git a/encoding/protobuf/testdata/client_config.proto.out.cue b/encoding/protobuf/testdata/client_config.proto.out.cue index c57dbebb7..84672a0aa 100644 --- a/encoding/protobuf/testdata/client_config.proto.out.cue +++ b/encoding/protobuf/testdata/client_config.proto.out.cue @@ -27,10 +27,12 @@ import ( // Specifies the behavior when the client is unable to connect to Mixer. #NetworkFailPolicy: { // Example of single-value enum. - #FailPolicy: + #FailPolicy: { // If network connection fails, request is allowed and delivered to the // service. "FAIL_OPEN" + #enumValue: 0 + } #FailPolicy_value: FAIL_OPEN: 0 diff --git a/encoding/protobuf/testdata/gateway.proto.out.cue b/encoding/protobuf/testdata/gateway.proto.out.cue index 80ed7a1ad..8f804716d 100644 --- a/encoding/protobuf/testdata/gateway.proto.out.cue +++ b/encoding/protobuf/testdata/gateway.proto.out.cue @@ -324,19 +324,22 @@ package v1alpha3 httpsRedirect?: bool @protobuf(1,bool,name=https_redirect) // TLS modes enforced by the proxy - #TLSmode: + #TLSmode: { // The SNI string presented by the client will be used as the match // criterion in a VirtualService TLS route to determine the // destination service from the service registry. - "PASSTHROUGH" | - + "PASSTHROUGH" + #enumValue: 0 + } | { // Secure connections with standard TLS semantics. - "SIMPLE" | - + "SIMPLE" + #enumValue: 1 + } | { // Secure connections to the upstream using mutual TLS by presenting // client certificates for authentication. - "MUTUAL" | - + "MUTUAL" + #enumValue: 2 + } | { // Similar to the passthrough mode, except servers with this TLS mode // do not require an associated VirtualService to map from the SNI // value to service in the registry. The destination details such as @@ -348,6 +351,8 @@ package v1alpha3 // their respective endpoints. Use of this mode assumes that both the // source and the destination are using Istio mTLS to secure traffic. "AUTO_PASSTHROUGH" + #enumValue: 3 + } #TLSmode_value: { PASSTHROUGH: 0 @@ -398,11 +403,22 @@ package v1alpha3 subjectAltNames?: [...string] @protobuf(6,string,name=subject_alt_names) // TLS protocol versions. - #TLSProtocol: "TLS_AUTO" | // Automatically choose the optimal TLS version. - "TLSV1_0" | // TLS version 1.0 - "TLSV1_1" | // TLS version 1.1 - "TLSV1_2" | // TLS version 1.2 - "TLSV1_3" // TLS version 1.3 + #TLSProtocol: { + "TLS_AUTO"// Automatically choose the optimal TLS version. + #enumValue: 0 + } | { + "TLSV1_0"// TLS version 1.0 + #enumValue: 1 + } | { + "TLSV1_1"// TLS version 1.1 + #enumValue: 2 + } | { + "TLSV1_2"// TLS version 1.2 + #enumValue: 3 + } | { + "TLSV1_3"// TLS version 1.3 + #enumValue: 4 + } #TLSProtocol_value: { TLS_AUTO: 0 diff --git a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue index 3d39a1952..24640e267 100644 --- a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue +++ b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue @@ -149,40 +149,48 @@ package descriptor // Describes a field within a message. #FieldDescriptorProto: { - #Type: + #Type: { // 0 is reserved for errors. // Order is weird for historical reasons. - "TYPE_DOUBLE" | - "TYPE_FLOAT" | - + "TYPE_DOUBLE" + #enumValue: 1 + } | {"TYPE_FLOAT", #enumValue: 2} | { // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if // negative values are likely. - "TYPE_INT64" | - "TYPE_UINT64" | - + "TYPE_INT64" + #enumValue: 3 + } | {"TYPE_UINT64", #enumValue: 4} | { // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if // negative values are likely. - "TYPE_INT32" | - "TYPE_FIXED64" | - "TYPE_FIXED32" | - "TYPE_BOOL" | - "TYPE_STRING" | - - // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. - "TYPE_GROUP" | - "TYPE_MESSAGE" | // Length-delimited aggregate. - - // New in version 2. - "TYPE_BYTES" | - "TYPE_UINT32" | - "TYPE_ENUM" | - "TYPE_SFIXED32" | - "TYPE_SFIXED64" | - "TYPE_SINT32" | // Uses ZigZag encoding. - "TYPE_SINT64" // Uses ZigZag encoding. + "TYPE_INT32" + #enumValue: 5 + } | {"TYPE_FIXED64", #enumValue: 6} | + {"TYPE_FIXED32", #enumValue: 7} | + {"TYPE_BOOL", #enumValue: 8} | + {"TYPE_STRING", #enumValue: 9} | { + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + "TYPE_GROUP" + #enumValue: 10 + } | { + "TYPE_MESSAGE"// Length-delimited aggregate. + #enumValue: 11 + } | { + // New in version 2. + "TYPE_BYTES" + #enumValue: 12 + } | {"TYPE_UINT32", #enumValue: 13} | + {"TYPE_ENUM", #enumValue: 14} | + {"TYPE_SFIXED32", #enumValue: 15} | + {"TYPE_SFIXED64", #enumValue: 16} | { + "TYPE_SINT32"// Uses ZigZag encoding. + #enumValue: 17 + } | { + "TYPE_SINT64"// Uses ZigZag encoding. + #enumValue: 18 + } #Type_value: { "TYPE_DOUBLE": 1 @@ -204,11 +212,12 @@ package descriptor "TYPE_SINT32": 17 "TYPE_SINT64": 18 } - #Label: + #Label: { // 0 is reserved for errors - "LABEL_OPTIONAL" | - "LABEL_REQUIRED" | - "LABEL_REPEATED" + "LABEL_OPTIONAL" + #enumValue: 1 + } | {"LABEL_REQUIRED", #enumValue: 2} | + {"LABEL_REPEATED", #enumValue: 3} #Label_value: { "LABEL_OPTIONAL": 1 @@ -351,15 +360,21 @@ package descriptor javaStringCheckUtf8?: bool @protobuf(27,bool,name=java_string_check_utf8,"default=false") // Generated classes can be optimized for speed or code size. - #OptimizeMode: "SPEED" | // Generate complete code for parsing, serialization, - + #OptimizeMode: { + "SPEED"// Generate complete code for parsing, serialization, + #enumValue: 1 + } | { // etc. - "CODE_SIZE" | - "LITE_RUNTIME" // Generate code using MessageLite and the lite runtime. + "CODE_SIZE"// Use ReflectionOps to implement these methods. + #enumValue: 2 + } | { + "LITE_RUNTIME"// Generate code using MessageLite and the lite runtime. + #enumValue: 3 + } #OptimizeMode_value: { "SPEED": 1 - "CODE_SIZE": 2 // Use ReflectionOps to implement these methods. + "CODE_SIZE": 2 "LITE_RUNTIME": 3 } optimizeFor?: #OptimizeMode @protobuf(9,OptimizeMode,name=optimize_for,"default=SPEED") @@ -498,11 +513,12 @@ package descriptor // options below. This option is not yet implemented in the open source // release -- sorry, we'll try to include it in a future version! ctype?: #CType @protobuf(1,CType,"default=STRING") - #CType: + #CType: { // Default mode. - "STRING" | - "CORD" | - "STRING_PIECE" + "STRING" + #enumValue: 0 + } | {"CORD", #enumValue: 1} | + {"STRING_PIECE", #enumValue: 2} #CType_value: { "STRING": 0 @@ -529,15 +545,19 @@ package descriptor // This option is an enum to permit additional types to be added, e.g. // goog.math.Integer. jstype?: #JSType @protobuf(6,JSType,"default=JS_NORMAL") - #JSType: + #JSType: { // Use the default type. - "JS_NORMAL" | - + "JS_NORMAL" + #enumValue: 0 + } | { // Use JavaScript strings. - "JS_STRING" | - + "JS_STRING" + #enumValue: 1 + } | { // Use JavaScript numbers. "JS_NUMBER" + #enumValue: 2 + } #JSType_value: { "JS_NORMAL": 0 @@ -650,9 +670,13 @@ package descriptor // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, // or neither? HTTP based RPC implementation may choose GET verb for safe // methods, and PUT verb for idempotent methods instead of the default POST. - #IdempotencyLevel: "IDEMPOTENCY_UNKNOWN" | - "NO_SIDE_EFFECTS" | // implies idempotent - "IDEMPOTENT" // idempotent, but may have side effects + #IdempotencyLevel: {"IDEMPOTENCY_UNKNOWN", #enumValue: 0} | { + "NO_SIDE_EFFECTS"// implies idempotent + #enumValue: 1 + } | { + "IDEMPOTENT"// idempotent, but may have side effects + #enumValue: 2 + } #IdempotencyLevel_value: { "IDEMPOTENCY_UNKNOWN": 0 diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue index 8ae32c209..4d0352c53 100644 --- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue +++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue @@ -27,10 +27,12 @@ import ( // Specifies the behavior when the client is unable to connect to Mixer. #NetworkFailPolicy: { // Example of single-value enum. - #FailPolicy: + #FailPolicy: { // If network connection fails, request is allowed and delivered to the // service. "FAIL_OPEN" + #enumValue: 0 + } #FailPolicy_value: "FAIL_OPEN": 0 diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue index 1e3fac491..868af2249 100644 --- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue +++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue @@ -103,10 +103,19 @@ import ( // This can be used to construct a response cache. #ReferencedAttributes: { // How an attribute's value was matched - #Condition: "CONDITION_UNSPECIFIED" | // should not occur - "ABSENCE" | // match when attribute doesn't exist - "EXACT" | // match when attribute value is an exact byte-for-byte match - "REGEX" // match when attribute value matches the included regex + #Condition: { + "CONDITION_UNSPECIFIED"// should not occur + #enumValue: 0 + } | { + "ABSENCE"// match when attribute doesn't exist + #enumValue: 1 + } | { + "EXACT"// match when attribute value is an exact byte-for-byte match + #enumValue: 2 + } | { + "REGEX"// match when attribute value matches the included regex + #enumValue: 3 + } #Condition_value: { "CONDITION_UNSPECIFIED": 0 @@ -155,9 +164,16 @@ import ( // the request headers. #HeaderOperation: { // Operation type. - #Operation: "REPLACE" | // replaces the header with the given name - "REMOVE" | // removes the header with the given name (the value is ignored) - "APPEND" // appends the value to the header value, or sets it if not present + #Operation: { + "REPLACE"// replaces the header with the given name + #enumValue: 0 + } | { + "REMOVE"// removes the header with the given name (the value is ignored) + #enumValue: 1 + } | { + "APPEND"// appends the value to the header value, or sets it if not present + #enumValue: 2 + } #Operation_value: { "REPLACE": 0 @@ -198,17 +214,20 @@ import ( // next value: 5 // Used to signal how the sets of compressed attributes should be reconstitued server-side. - #RepeatedAttributesSemantics: + #RepeatedAttributesSemantics: { // Use delta encoding between sets of compressed attributes to reduce the overall on-wire // request size. Each individual set of attributes is used to modify the previous set. // NOTE: There is no way with this encoding to specify attribute value deletion. This // option should be used with extreme caution. - "DELTA_ENCODING" | - + "DELTA_ENCODING" + #enumValue: 0 + } | { // Treat each set of compressed attributes as complete - independent from other sets // in this request. This will result in on-wire duplication of attributes and values, but // will allow for proper accounting of absent values in overall encoding. "INDEPENDENT_ENCODING" + #enumValue: 1 + } #RepeatedAttributesSemantics_value: { "DELTA_ENCODING": 0 diff --git a/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue index 80dd5cdfa..e06a95628 100644 --- a/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue +++ b/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue @@ -324,19 +324,22 @@ package v1alpha3 httpsRedirect?: bool @protobuf(1,bool,name=https_redirect) // TLS modes enforced by the proxy - #TLSmode: + #TLSmode: { // The SNI string presented by the client will be used as the match // criterion in a VirtualService TLS route to determine the // destination service from the service registry. - "PASSTHROUGH" | - + "PASSTHROUGH" + #enumValue: 0 + } | { // Secure connections with standard TLS semantics. - "SIMPLE" | - + "SIMPLE" + #enumValue: 1 + } | { // Secure connections to the upstream using mutual TLS by presenting // client certificates for authentication. - "MUTUAL" | - + "MUTUAL" + #enumValue: 2 + } | { // Similar to the passthrough mode, except servers with this TLS mode // do not require an associated VirtualService to map from the SNI // value to service in the registry. The destination details such as @@ -348,6 +351,8 @@ package v1alpha3 // their respective endpoints. Use of this mode assumes that both the // source and the destination are using Istio mTLS to secure traffic. "AUTO_PASSTHROUGH" + #enumValue: 3 + } #TLSmode_value: { "PASSTHROUGH": 0 @@ -398,11 +403,22 @@ package v1alpha3 subjectAltNames?: [...string] @protobuf(6,string,name=subject_alt_names) // TLS protocol versions. - #TLSProtocol: "TLS_AUTO" | // Automatically choose the optimal TLS version. - "TLSV1_0" | // TLS version 1.0 - "TLSV1_1" | // TLS version 1.1 - "TLSV1_2" | // TLS version 1.2 - "TLSV1_3" // TLS version 1.3 + #TLSProtocol: { + "TLS_AUTO"// Automatically choose the optimal TLS version. + #enumValue: 0 + } | { + "TLSV1_0"// TLS version 1.0 + #enumValue: 1 + } | { + "TLSV1_1"// TLS version 1.1 + #enumValue: 2 + } | { + "TLSV1_2"// TLS version 1.2 + #enumValue: 3 + } | { + "TLSV1_3"// TLS version 1.3 + #enumValue: 4 + } #TLSProtocol_value: { "TLS_AUTO": 0