cue: observe JSON mappings for google.protobuf.Struct
Change-Id: I234767c9bcdb67dee3492827cf598f5a45258959
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2681
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/encoding/protobuf/parse.go b/encoding/protobuf/parse.go
index b3e7451..48617c9 100644
--- a/encoding/protobuf/parse.go
+++ b/encoding/protobuf/parse.go
@@ -330,7 +330,9 @@
return err
}
- p.mapBuiltinPackage(v.Position, v.Filename, filename == "")
+ if !p.mapBuiltinPackage(v.Position, v.Filename, filename == "") {
+ return nil
+ }
imp, err := p.state.parse(filename, nil)
if err != nil {
diff --git a/encoding/protobuf/protobuf.go b/encoding/protobuf/protobuf.go
index d813438..d1cdad0 100644
--- a/encoding/protobuf/protobuf.go
+++ b/encoding/protobuf/protobuf.go
@@ -15,6 +15,36 @@
// Package protobuf defines functionality for parsing protocol buffer
// definitions and instances.
//
+// Proto definition mapping follows the guidelines of mapping Proto to JSON as
+// discussed in https://developers.google.com/protocol-buffers/docs/proto3,
+// and carries some of the mapping further when possible with CUE.
+//
+// The following type mappings of defintions apply:
+//
+// Proto type CUE type/def Comments
+// message struct Message fields become CUE fields, whereby
+// names are mapped to lowerCamelCase.
+// enum e1 | e2 | ... Where ex are strings. A separate mapping is
+// generated to obtain the numeric values.
+// map<K, V> { <>: V } All keys are converted to strings.
+// repeated V [...V] null is accepted as the empty list [].
+// bool bool
+// string string
+// bytes bytes A base64-encoded string when converted to JSON.
+// int32, fixed32 int32 An integer with bounds as defined by int32.
+// uint32 uint32 An integer with bounds as defined by uint32.
+// int64, fixed64 int64 An integer with bounds as defined by int64.
+// uint64 uint64 An integer with bounds as defined by uint64.
+// float float32 A number with bounds as defined by float32.
+// double float64 A number with bounds as defined by float64.
+// Struct struct See struct.proto.
+// Value _ See struct.proto.
+// ListValue [...] See struct.proto.
+// BoolValue bool See struct.proto.
+// StringValue string See struct.proto.
+// NumberValue number See struct.proto.
+// StringValue string See struct.proto.
+//
// Protobuf definitions can be annotated with CUE constraints that are
// included in the generated CUE:
// (cue.val) string CUE expression defining a constraint for this
@@ -27,6 +57,14 @@
//
package protobuf
+// TODO mappings:
+// Timestamp string "1972-01-01T10:00:20.021Z" Uses RFC 3339, where generated output will always be Z-normalized and uses 0, 3, 6 or 9 fractional digits. Offsets other than "Z" are also accepted.
+// Duration string "1.000340012s", "1s" Generated output always contains 0, 3, 6, or 9 fractional digits, depending on required precision, followed by the suffix "s". Accepted are any fractional digits (also none) as long as they fit into nano-seconds precision and the suffix "s" is required.
+// Empty object {}
+//
+// Wrapper types various types 2, "2", "foo", true, "true", null, 0, … Wrappers use the same representation in JSON as the wrapped primitive type, except that null is allowed and preserved during data conversion and transfer.
+// FieldMask string "f.fooBar,h" See field_mask.proto.
+
import (
"os"
"path/filepath"
diff --git a/encoding/protobuf/testdata/attributes.proto.out.cue b/encoding/protobuf/testdata/attributes.proto.out.cue
index 9c13d65..dc5a1b1 100644
--- a/encoding/protobuf/testdata/attributes.proto.out.cue
+++ b/encoding/protobuf/testdata/attributes.proto.out.cue
@@ -19,6 +19,15 @@
"github.com/golang/protobuf/ptypes/timestamp"
)
+StructWrap: {
+ struct?: {} @protobuf(1,type=google.protobuf.Struct)
+ any?: _ @protobuf(2,type=google.protobuf.Value)
+ listVal?: [...] @protobuf(3,type=google.protobuf.ListValue)
+ boolVal?: bool @protobuf(4,type=google.protobuf.BoolValue)
+ stringVal?: string @protobuf(5,type=google.protobuf.StringValue)
+ numberVal?: number @protobuf(6,type=google.protobuf.NumberValue)
+}
+
// Attributes represents a set of typed name/value pairs. Many of Mixer's
// API either consume and/or return attributes.
//
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes.proto b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes.proto
index 32fa4fc..780005c 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes.proto
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes.proto
@@ -21,6 +21,7 @@
import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
+import "google/protobuf/struct.proto";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.equal_all) = false;
@@ -28,6 +29,16 @@
option (gogoproto.stable_marshaler_all) = true;
option cc_enable_arenas = true;
+message StructWrap {
+ google.protobuf.Struct struct = 1;
+
+ google.protobuf.Value any = 2;
+ google.protobuf.ListValue listVal = 3;
+ google.protobuf.BoolValue boolVal = 4;
+ google.protobuf.StringValue stringVal = 5;
+ google.protobuf.NumberValue numberVal = 6;
+}
+
// Attributes represents a set of typed name/value pairs. Many of Mixer's
// API either consume and/or return attributes.
//
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
index 9c13d65..df7d3ae 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
@@ -19,6 +19,15 @@
"github.com/golang/protobuf/ptypes/timestamp"
)
+StructWrap: {
+ struct?: {} @protobuf(1,type=google.protobuf.Struct)
+ any?: _ @protobuf(2,type=google.protobuf.Value)
+ listVal?: [...] @protobuf(3,type=google.protobuf.ListValue)
+ boolVal?: bool @protobuf(4,type=google.protobuf.BoolValue)
+ stringVal?: string @protobuf(5,type=google.protobuf.StringValue)
+ numberVal?: number @protobuf(6,type=google.protobuf.NumberValue)
+}
+
// Attributes represents a set of typed name/value pairs. Many of Mixer's
// API either consume and/or return attributes.
//
diff --git a/encoding/protobuf/types.go b/encoding/protobuf/types.go
index c6c8548..f54708e 100644
--- a/encoding/protobuf/types.go
+++ b/encoding/protobuf/types.go
@@ -48,24 +48,40 @@
"bytes": "bytes",
}
-var timePkg = &protoConverter{
- id: "time",
- goPkg: "time",
- goPkgPath: "time",
-}
-
func (p *protoConverter) setBuiltin(from, to string, pkg *protoConverter) {
p.scope[0][from] = mapping{to, "", pkg}
}
-func (p *protoConverter) mapBuiltinPackage(pos scanner.Position, file string, required bool) {
+func (p *protoConverter) mapBuiltinPackage(pos scanner.Position, file string, required bool) (generate bool) {
// Map some builtin types to their JSON/CUE mappings.
switch file {
case "gogoproto/gogo.proto":
+ case "google/protobuf/struct.proto":
+ p.setBuiltin("google.protobuf.Struct", "{}", nil)
+ p.setBuiltin("google.protobuf.Value", "_", nil)
+ p.setBuiltin("google.protobuf.NullValue", "null", nil)
+ p.setBuiltin("google.protobuf.ListValue", "[...]", nil)
+ p.setBuiltin("google.protobuf.StringValue", "string", nil)
+ p.setBuiltin("google.protobuf.BoolValue", "bool", nil)
+ p.setBuiltin("google.protobuf.NumberValue", "number", nil)
+ return false
+
+ // TODO: consider mapping the following:
+
+ // case "google/protobuf/duration.proto":
+ // p.setBuiltin("google.protobuf.Duration", "time.Duration", "time")
+
+ // case "google/protobuf/timestamp.proto":
+ // p.setBuiltin("google.protobuf.Timestamp", "time.Time", "time")
+
+ // case "google/protobuf/empty.proto":
+ // p.setBuiltin("google.protobuf.Empty", "struct.MaxFields(0)", nil)
+
default:
if required {
failf(pos, "import %q not found", file)
}
}
+ return true
}