683
vendor/google.golang.org/protobuf/encoding/protojson/decode.go
generated
vendored
Normal file
683
vendor/google.golang.org/protobuf/encoding/protojson/decode.go
generated
vendored
Normal file
@@ -0,0 +1,683 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package protojson
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/internal/encoding/json"
|
||||
"google.golang.org/protobuf/internal/encoding/messageset"
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
"google.golang.org/protobuf/internal/pragma"
|
||||
"google.golang.org/protobuf/internal/set"
|
||||
"google.golang.org/protobuf/proto"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
)
|
||||
|
||||
// Unmarshal reads the given []byte into the given proto.Message.
|
||||
func Unmarshal(b []byte, m proto.Message) error {
|
||||
return UnmarshalOptions{}.Unmarshal(b, m)
|
||||
}
|
||||
|
||||
// UnmarshalOptions is a configurable JSON format parser.
|
||||
type UnmarshalOptions struct {
|
||||
pragma.NoUnkeyedLiterals
|
||||
|
||||
// If AllowPartial is set, input for messages that will result in missing
|
||||
// required fields will not return an error.
|
||||
AllowPartial bool
|
||||
|
||||
// If DiscardUnknown is set, unknown fields are ignored.
|
||||
DiscardUnknown bool
|
||||
|
||||
// Resolver is used for looking up types when unmarshaling
|
||||
// google.protobuf.Any messages or extension fields.
|
||||
// If nil, this defaults to using protoregistry.GlobalTypes.
|
||||
Resolver interface {
|
||||
protoregistry.MessageTypeResolver
|
||||
protoregistry.ExtensionTypeResolver
|
||||
}
|
||||
}
|
||||
|
||||
// Unmarshal reads the given []byte and populates the given proto.Message using
|
||||
// options in UnmarshalOptions object. It will clear the message first before
|
||||
// setting the fields. If it returns an error, the given message may be
|
||||
// partially set.
|
||||
func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
|
||||
proto.Reset(m)
|
||||
|
||||
if o.Resolver == nil {
|
||||
o.Resolver = protoregistry.GlobalTypes
|
||||
}
|
||||
|
||||
dec := decoder{json.NewDecoder(b), o}
|
||||
if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for EOF.
|
||||
tok, err := dec.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.EOF {
|
||||
return dec.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
if o.AllowPartial {
|
||||
return nil
|
||||
}
|
||||
return proto.CheckInitialized(m)
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
*json.Decoder
|
||||
opts UnmarshalOptions
|
||||
}
|
||||
|
||||
// newError returns an error object with position info.
|
||||
func (d decoder) newError(pos int, f string, x ...interface{}) error {
|
||||
line, column := d.Position(pos)
|
||||
head := fmt.Sprintf("(line %d:%d): ", line, column)
|
||||
return errors.New(head+f, x...)
|
||||
}
|
||||
|
||||
// unexpectedTokenError returns a syntax error for the given unexpected token.
|
||||
func (d decoder) unexpectedTokenError(tok json.Token) error {
|
||||
return d.syntaxError(tok.Pos(), "unexpected token %s", tok.RawString())
|
||||
}
|
||||
|
||||
// syntaxError returns a syntax error for given position.
|
||||
func (d decoder) syntaxError(pos int, f string, x ...interface{}) error {
|
||||
line, column := d.Position(pos)
|
||||
head := fmt.Sprintf("syntax error (line %d:%d): ", line, column)
|
||||
return errors.New(head+f, x...)
|
||||
}
|
||||
|
||||
// unmarshalMessage unmarshals a message into the given protoreflect.Message.
|
||||
func (d decoder) unmarshalMessage(m pref.Message, skipTypeURL bool) error {
|
||||
if isCustomType(m.Descriptor().FullName()) {
|
||||
return d.unmarshalCustomType(m)
|
||||
}
|
||||
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.ObjectOpen {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
if err := d.unmarshalFields(m, skipTypeURL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshalFields unmarshals the fields into the given protoreflect.Message.
|
||||
func (d decoder) unmarshalFields(m pref.Message, skipTypeURL bool) error {
|
||||
messageDesc := m.Descriptor()
|
||||
if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
|
||||
return errors.New("no support for proto1 MessageSets")
|
||||
}
|
||||
|
||||
var seenNums set.Ints
|
||||
var seenOneofs set.Ints
|
||||
fieldDescs := messageDesc.Fields()
|
||||
for {
|
||||
// Read field name.
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
default:
|
||||
return d.unexpectedTokenError(tok)
|
||||
case json.ObjectClose:
|
||||
return nil
|
||||
case json.Name:
|
||||
// Continue below.
|
||||
}
|
||||
|
||||
name := tok.Name()
|
||||
// Unmarshaling a non-custom embedded message in Any will contain the
|
||||
// JSON field "@type" which should be skipped because it is not a field
|
||||
// of the embedded message, but simply an artifact of the Any format.
|
||||
if skipTypeURL && name == "@type" {
|
||||
d.Read()
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the FieldDescriptor.
|
||||
var fd pref.FieldDescriptor
|
||||
if strings.HasPrefix(name, "[") && strings.HasSuffix(name, "]") {
|
||||
// Only extension names are in [name] format.
|
||||
extName := pref.FullName(name[1 : len(name)-1])
|
||||
extType, err := d.findExtension(extName)
|
||||
if err != nil && err != protoregistry.NotFound {
|
||||
return d.newError(tok.Pos(), "unable to resolve %s: %v", tok.RawString(), err)
|
||||
}
|
||||
if extType != nil {
|
||||
fd = extType.TypeDescriptor()
|
||||
if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() {
|
||||
return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The name can either be the JSON name or the proto field name.
|
||||
fd = fieldDescs.ByJSONName(name)
|
||||
if fd == nil {
|
||||
fd = fieldDescs.ByName(pref.Name(name))
|
||||
if fd == nil {
|
||||
// The proto name of a group field is in all lowercase,
|
||||
// while the textual field name is the group message name.
|
||||
gd := fieldDescs.ByName(pref.Name(strings.ToLower(name)))
|
||||
if gd != nil && gd.Kind() == pref.GroupKind && gd.Message().Name() == pref.Name(name) {
|
||||
fd = gd
|
||||
}
|
||||
} else if fd.Kind() == pref.GroupKind && fd.Message().Name() != pref.Name(name) {
|
||||
fd = nil // reset since field name is actually the message name
|
||||
}
|
||||
}
|
||||
}
|
||||
if flags.ProtoLegacy {
|
||||
if fd != nil && fd.IsWeak() && fd.Message().IsPlaceholder() {
|
||||
fd = nil // reset since the weak reference is not linked in
|
||||
}
|
||||
}
|
||||
|
||||
if fd == nil {
|
||||
// Field is unknown.
|
||||
if d.opts.DiscardUnknown {
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return d.newError(tok.Pos(), "unknown field %v", tok.RawString())
|
||||
}
|
||||
|
||||
// Do not allow duplicate fields.
|
||||
num := uint64(fd.Number())
|
||||
if seenNums.Has(num) {
|
||||
return d.newError(tok.Pos(), "duplicate field %v", tok.RawString())
|
||||
}
|
||||
seenNums.Set(num)
|
||||
|
||||
// No need to set values for JSON null unless the field type is
|
||||
// google.protobuf.Value or google.protobuf.NullValue.
|
||||
if tok, _ := d.Peek(); tok.Kind() == json.Null && !isKnownValue(fd) && !isNullValue(fd) {
|
||||
d.Read()
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case fd.IsList():
|
||||
list := m.Mutable(fd).List()
|
||||
if err := d.unmarshalList(list, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
case fd.IsMap():
|
||||
mmap := m.Mutable(fd).Map()
|
||||
if err := d.unmarshalMap(mmap, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// If field is a oneof, check if it has already been set.
|
||||
if od := fd.ContainingOneof(); od != nil {
|
||||
idx := uint64(od.Index())
|
||||
if seenOneofs.Has(idx) {
|
||||
return d.newError(tok.Pos(), "error parsing %s, oneof %v is already set", tok.RawString(), od.FullName())
|
||||
}
|
||||
seenOneofs.Set(idx)
|
||||
}
|
||||
|
||||
// Required or optional fields.
|
||||
if err := d.unmarshalSingular(m, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findExtension returns protoreflect.ExtensionType from the resolver if found.
|
||||
func (d decoder) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
|
||||
xt, err := d.opts.Resolver.FindExtensionByName(xtName)
|
||||
if err == nil {
|
||||
return xt, nil
|
||||
}
|
||||
return messageset.FindMessageSetExtension(d.opts.Resolver, xtName)
|
||||
}
|
||||
|
||||
func isKnownValue(fd pref.FieldDescriptor) bool {
|
||||
md := fd.Message()
|
||||
return md != nil && md.FullName() == "google.protobuf.Value"
|
||||
}
|
||||
|
||||
func isNullValue(fd pref.FieldDescriptor) bool {
|
||||
ed := fd.Enum()
|
||||
return ed != nil && ed.FullName() == "google.protobuf.NullValue"
|
||||
}
|
||||
|
||||
// unmarshalSingular unmarshals to the non-repeated field specified
|
||||
// by the given FieldDescriptor.
|
||||
func (d decoder) unmarshalSingular(m pref.Message, fd pref.FieldDescriptor) error {
|
||||
var val pref.Value
|
||||
var err error
|
||||
switch fd.Kind() {
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
val = m.NewField(fd)
|
||||
err = d.unmarshalMessage(val.Message(), false)
|
||||
default:
|
||||
val, err = d.unmarshalScalar(fd)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Set(fd, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshalScalar unmarshals to a scalar/enum protoreflect.Value specified by
|
||||
// the given FieldDescriptor.
|
||||
func (d decoder) unmarshalScalar(fd pref.FieldDescriptor) (pref.Value, error) {
|
||||
const b32 int = 32
|
||||
const b64 int = 64
|
||||
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return pref.Value{}, err
|
||||
}
|
||||
|
||||
kind := fd.Kind()
|
||||
switch kind {
|
||||
case pref.BoolKind:
|
||||
if tok.Kind() == json.Bool {
|
||||
return pref.ValueOfBool(tok.Bool()), nil
|
||||
}
|
||||
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
if v, ok := unmarshalInt(tok, b32); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
if v, ok := unmarshalInt(tok, b64); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
if v, ok := unmarshalUint(tok, b32); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
if v, ok := unmarshalUint(tok, b64); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.FloatKind:
|
||||
if v, ok := unmarshalFloat(tok, b32); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.DoubleKind:
|
||||
if v, ok := unmarshalFloat(tok, b64); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.StringKind:
|
||||
if tok.Kind() == json.String {
|
||||
return pref.ValueOfString(tok.ParsedString()), nil
|
||||
}
|
||||
|
||||
case pref.BytesKind:
|
||||
if v, ok := unmarshalBytes(tok); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
case pref.EnumKind:
|
||||
if v, ok := unmarshalEnum(tok, fd); ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unmarshalScalar: invalid scalar kind %v", kind))
|
||||
}
|
||||
|
||||
return pref.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString())
|
||||
}
|
||||
|
||||
func unmarshalInt(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
switch tok.Kind() {
|
||||
case json.Number:
|
||||
return getInt(tok, bitSize)
|
||||
|
||||
case json.String:
|
||||
// Decode number from string.
|
||||
s := strings.TrimSpace(tok.ParsedString())
|
||||
if len(s) != len(tok.ParsedString()) {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
dec := json.NewDecoder([]byte(s))
|
||||
tok, err := dec.Read()
|
||||
if err != nil {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
return getInt(tok, bitSize)
|
||||
}
|
||||
return pref.Value{}, false
|
||||
}
|
||||
|
||||
func getInt(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
n, ok := tok.Int(bitSize)
|
||||
if !ok {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfInt32(int32(n)), true
|
||||
}
|
||||
return pref.ValueOfInt64(n), true
|
||||
}
|
||||
|
||||
func unmarshalUint(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
switch tok.Kind() {
|
||||
case json.Number:
|
||||
return getUint(tok, bitSize)
|
||||
|
||||
case json.String:
|
||||
// Decode number from string.
|
||||
s := strings.TrimSpace(tok.ParsedString())
|
||||
if len(s) != len(tok.ParsedString()) {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
dec := json.NewDecoder([]byte(s))
|
||||
tok, err := dec.Read()
|
||||
if err != nil {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
return getUint(tok, bitSize)
|
||||
}
|
||||
return pref.Value{}, false
|
||||
}
|
||||
|
||||
func getUint(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
n, ok := tok.Uint(bitSize)
|
||||
if !ok {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfUint32(uint32(n)), true
|
||||
}
|
||||
return pref.ValueOfUint64(n), true
|
||||
}
|
||||
|
||||
func unmarshalFloat(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
switch tok.Kind() {
|
||||
case json.Number:
|
||||
return getFloat(tok, bitSize)
|
||||
|
||||
case json.String:
|
||||
s := tok.ParsedString()
|
||||
switch s {
|
||||
case "NaN":
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfFloat32(float32(math.NaN())), true
|
||||
}
|
||||
return pref.ValueOfFloat64(math.NaN()), true
|
||||
case "Infinity":
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfFloat32(float32(math.Inf(+1))), true
|
||||
}
|
||||
return pref.ValueOfFloat64(math.Inf(+1)), true
|
||||
case "-Infinity":
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfFloat32(float32(math.Inf(-1))), true
|
||||
}
|
||||
return pref.ValueOfFloat64(math.Inf(-1)), true
|
||||
}
|
||||
|
||||
// Decode number from string.
|
||||
if len(s) != len(strings.TrimSpace(s)) {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
dec := json.NewDecoder([]byte(s))
|
||||
tok, err := dec.Read()
|
||||
if err != nil {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
return getFloat(tok, bitSize)
|
||||
}
|
||||
return pref.Value{}, false
|
||||
}
|
||||
|
||||
func getFloat(tok json.Token, bitSize int) (pref.Value, bool) {
|
||||
n, ok := tok.Float(bitSize)
|
||||
if !ok {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
if bitSize == 32 {
|
||||
return pref.ValueOfFloat32(float32(n)), true
|
||||
}
|
||||
return pref.ValueOfFloat64(n), true
|
||||
}
|
||||
|
||||
func unmarshalBytes(tok json.Token) (pref.Value, bool) {
|
||||
if tok.Kind() != json.String {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
|
||||
s := tok.ParsedString()
|
||||
enc := base64.StdEncoding
|
||||
if strings.ContainsAny(s, "-_") {
|
||||
enc = base64.URLEncoding
|
||||
}
|
||||
if len(s)%4 != 0 {
|
||||
enc = enc.WithPadding(base64.NoPadding)
|
||||
}
|
||||
b, err := enc.DecodeString(s)
|
||||
if err != nil {
|
||||
return pref.Value{}, false
|
||||
}
|
||||
return pref.ValueOfBytes(b), true
|
||||
}
|
||||
|
||||
func unmarshalEnum(tok json.Token, fd pref.FieldDescriptor) (pref.Value, bool) {
|
||||
switch tok.Kind() {
|
||||
case json.String:
|
||||
// Lookup EnumNumber based on name.
|
||||
s := tok.ParsedString()
|
||||
if enumVal := fd.Enum().Values().ByName(pref.Name(s)); enumVal != nil {
|
||||
return pref.ValueOfEnum(enumVal.Number()), true
|
||||
}
|
||||
|
||||
case json.Number:
|
||||
if n, ok := tok.Int(32); ok {
|
||||
return pref.ValueOfEnum(pref.EnumNumber(n)), true
|
||||
}
|
||||
|
||||
case json.Null:
|
||||
// This is only valid for google.protobuf.NullValue.
|
||||
if isNullValue(fd) {
|
||||
return pref.ValueOfEnum(0), true
|
||||
}
|
||||
}
|
||||
|
||||
return pref.Value{}, false
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalList(list pref.List, fd pref.FieldDescriptor) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.ArrayOpen {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
switch fd.Kind() {
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
for {
|
||||
tok, err := d.Peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tok.Kind() == json.ArrayClose {
|
||||
d.Read()
|
||||
return nil
|
||||
}
|
||||
|
||||
val := list.NewElement()
|
||||
if err := d.unmarshalMessage(val.Message(), false); err != nil {
|
||||
return err
|
||||
}
|
||||
list.Append(val)
|
||||
}
|
||||
default:
|
||||
for {
|
||||
tok, err := d.Peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tok.Kind() == json.ArrayClose {
|
||||
d.Read()
|
||||
return nil
|
||||
}
|
||||
|
||||
val, err := d.unmarshalScalar(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list.Append(val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.ObjectOpen {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
// Determine ahead whether map entry is a scalar type or a message type in
|
||||
// order to call the appropriate unmarshalMapValue func inside the for loop
|
||||
// below.
|
||||
var unmarshalMapValue func() (pref.Value, error)
|
||||
switch fd.MapValue().Kind() {
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
unmarshalMapValue = func() (pref.Value, error) {
|
||||
val := mmap.NewValue()
|
||||
if err := d.unmarshalMessage(val.Message(), false); err != nil {
|
||||
return pref.Value{}, err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
default:
|
||||
unmarshalMapValue = func() (pref.Value, error) {
|
||||
return d.unmarshalScalar(fd.MapValue())
|
||||
}
|
||||
}
|
||||
|
||||
Loop:
|
||||
for {
|
||||
// Read field name.
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
default:
|
||||
return d.unexpectedTokenError(tok)
|
||||
case json.ObjectClose:
|
||||
break Loop
|
||||
case json.Name:
|
||||
// Continue.
|
||||
}
|
||||
|
||||
// Unmarshal field name.
|
||||
pkey, err := d.unmarshalMapKey(tok, fd.MapKey())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for duplicate field name.
|
||||
if mmap.Has(pkey) {
|
||||
return d.newError(tok.Pos(), "duplicate map key %v", tok.RawString())
|
||||
}
|
||||
|
||||
// Read and unmarshal field value.
|
||||
pval, err := unmarshalMapValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mmap.Set(pkey, pval)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshalMapKey converts given token of Name kind into a protoreflect.MapKey.
|
||||
// A map key type is any integral or string type.
|
||||
func (d decoder) unmarshalMapKey(tok json.Token, fd pref.FieldDescriptor) (pref.MapKey, error) {
|
||||
const b32 = 32
|
||||
const b64 = 64
|
||||
const base10 = 10
|
||||
|
||||
name := tok.Name()
|
||||
kind := fd.Kind()
|
||||
switch kind {
|
||||
case pref.StringKind:
|
||||
return pref.ValueOfString(name).MapKey(), nil
|
||||
|
||||
case pref.BoolKind:
|
||||
switch name {
|
||||
case "true":
|
||||
return pref.ValueOfBool(true).MapKey(), nil
|
||||
case "false":
|
||||
return pref.ValueOfBool(false).MapKey(), nil
|
||||
}
|
||||
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
if n, err := strconv.ParseInt(name, base10, b32); err == nil {
|
||||
return pref.ValueOfInt32(int32(n)).MapKey(), nil
|
||||
}
|
||||
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
if n, err := strconv.ParseInt(name, base10, b64); err == nil {
|
||||
return pref.ValueOfInt64(int64(n)).MapKey(), nil
|
||||
}
|
||||
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
if n, err := strconv.ParseUint(name, base10, b32); err == nil {
|
||||
return pref.ValueOfUint32(uint32(n)).MapKey(), nil
|
||||
}
|
||||
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
if n, err := strconv.ParseUint(name, base10, b64); err == nil {
|
||||
return pref.ValueOfUint64(uint64(n)).MapKey(), nil
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid kind for map key: %v", kind))
|
||||
}
|
||||
|
||||
return pref.MapKey{}, d.newError(tok.Pos(), "invalid value for %v key: %s", kind, tok.RawString())
|
||||
}
|
||||
11
vendor/google.golang.org/protobuf/encoding/protojson/doc.go
generated
vendored
Normal file
11
vendor/google.golang.org/protobuf/encoding/protojson/doc.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package protojson marshals and unmarshals protocol buffer messages as JSON
|
||||
// format. It follows the guide at
|
||||
// https://developers.google.com/protocol-buffers/docs/proto3#json.
|
||||
//
|
||||
// This package produces a different output than the standard "encoding/json"
|
||||
// package, which does not operate correctly on protocol buffer messages.
|
||||
package protojson
|
||||
394
vendor/google.golang.org/protobuf/encoding/protojson/encode.go
generated
vendored
Normal file
394
vendor/google.golang.org/protobuf/encoding/protojson/encode.go
generated
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package protojson
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"google.golang.org/protobuf/internal/encoding/json"
|
||||
"google.golang.org/protobuf/internal/encoding/messageset"
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
"google.golang.org/protobuf/internal/pragma"
|
||||
"google.golang.org/protobuf/proto"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
)
|
||||
|
||||
const defaultIndent = " "
|
||||
|
||||
// Format formats the message as a multiline string.
|
||||
// This function is only intended for human consumption and ignores errors.
|
||||
// Do not depend on the output being stable. It may change over time across
|
||||
// different versions of the program.
|
||||
func Format(m proto.Message) string {
|
||||
return MarshalOptions{Multiline: true}.Format(m)
|
||||
}
|
||||
|
||||
// Marshal writes the given proto.Message in JSON format using default options.
|
||||
// Do not depend on the output being stable. It may change over time across
|
||||
// different versions of the program.
|
||||
func Marshal(m proto.Message) ([]byte, error) {
|
||||
return MarshalOptions{}.Marshal(m)
|
||||
}
|
||||
|
||||
// MarshalOptions is a configurable JSON format marshaler.
|
||||
type MarshalOptions struct {
|
||||
pragma.NoUnkeyedLiterals
|
||||
|
||||
// Multiline specifies whether the marshaler should format the output in
|
||||
// indented-form with every textual element on a new line.
|
||||
// If Indent is an empty string, then an arbitrary indent is chosen.
|
||||
Multiline bool
|
||||
|
||||
// Indent specifies the set of indentation characters to use in a multiline
|
||||
// formatted output such that every entry is preceded by Indent and
|
||||
// terminated by a newline. If non-empty, then Multiline is treated as true.
|
||||
// Indent can only be composed of space or tab characters.
|
||||
Indent string
|
||||
|
||||
// AllowPartial allows messages that have missing required fields to marshal
|
||||
// without returning an error. If AllowPartial is false (the default),
|
||||
// Marshal will return error if there are any missing required fields.
|
||||
AllowPartial bool
|
||||
|
||||
// UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
|
||||
// field names.
|
||||
UseProtoNames bool
|
||||
|
||||
// UseEnumNumbers emits enum values as numbers.
|
||||
UseEnumNumbers bool
|
||||
|
||||
// EmitUnpopulated specifies whether to emit unpopulated fields. It does not
|
||||
// emit unpopulated oneof fields or unpopulated extension fields.
|
||||
// The JSON value emitted for unpopulated fields are as follows:
|
||||
// ╔═══════╤════════════════════════════╗
|
||||
// ║ JSON │ Protobuf field ║
|
||||
// ╠═══════╪════════════════════════════╣
|
||||
// ║ false │ proto3 boolean fields ║
|
||||
// ║ 0 │ proto3 numeric fields ║
|
||||
// ║ "" │ proto3 string/bytes fields ║
|
||||
// ║ null │ proto2 scalar fields ║
|
||||
// ║ null │ message fields ║
|
||||
// ║ [] │ list fields ║
|
||||
// ║ {} │ map fields ║
|
||||
// ╚═══════╧════════════════════════════╝
|
||||
EmitUnpopulated bool
|
||||
|
||||
// Resolver is used for looking up types when expanding google.protobuf.Any
|
||||
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
|
||||
Resolver interface {
|
||||
protoregistry.ExtensionTypeResolver
|
||||
protoregistry.MessageTypeResolver
|
||||
}
|
||||
}
|
||||
|
||||
// Format formats the message as a string.
|
||||
// This method is only intended for human consumption and ignores errors.
|
||||
// Do not depend on the output being stable. It may change over time across
|
||||
// different versions of the program.
|
||||
func (o MarshalOptions) Format(m proto.Message) string {
|
||||
if m == nil || !m.ProtoReflect().IsValid() {
|
||||
return "<nil>" // invalid syntax, but okay since this is for debugging
|
||||
}
|
||||
o.AllowPartial = true
|
||||
b, _ := o.Marshal(m)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Marshal marshals the given proto.Message in the JSON format using options in
|
||||
// MarshalOptions. Do not depend on the output being stable. It may change over
|
||||
// time across different versions of the program.
|
||||
func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
|
||||
if o.Multiline && o.Indent == "" {
|
||||
o.Indent = defaultIndent
|
||||
}
|
||||
if o.Resolver == nil {
|
||||
o.Resolver = protoregistry.GlobalTypes
|
||||
}
|
||||
|
||||
internalEnc, err := json.NewEncoder(o.Indent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Treat nil message interface as an empty message,
|
||||
// in which case the output in an empty JSON object.
|
||||
if m == nil {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
|
||||
enc := encoder{internalEnc, o}
|
||||
if err := enc.marshalMessage(m.ProtoReflect()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.AllowPartial {
|
||||
return enc.Bytes(), nil
|
||||
}
|
||||
return enc.Bytes(), proto.CheckInitialized(m)
|
||||
}
|
||||
|
||||
type encoder struct {
|
||||
*json.Encoder
|
||||
opts MarshalOptions
|
||||
}
|
||||
|
||||
// marshalMessage marshals the given protoreflect.Message.
|
||||
func (e encoder) marshalMessage(m pref.Message) error {
|
||||
if isCustomType(m.Descriptor().FullName()) {
|
||||
return e.marshalCustomType(m)
|
||||
}
|
||||
|
||||
e.StartObject()
|
||||
defer e.EndObject()
|
||||
if err := e.marshalFields(m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshalFields marshals the fields in the given protoreflect.Message.
|
||||
func (e encoder) marshalFields(m pref.Message) error {
|
||||
messageDesc := m.Descriptor()
|
||||
if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
|
||||
return errors.New("no support for proto1 MessageSets")
|
||||
}
|
||||
|
||||
// Marshal out known fields.
|
||||
fieldDescs := messageDesc.Fields()
|
||||
for i := 0; i < fieldDescs.Len(); {
|
||||
fd := fieldDescs.Get(i)
|
||||
if od := fd.ContainingOneof(); od != nil {
|
||||
fd = m.WhichOneof(od)
|
||||
i += od.Fields().Len()
|
||||
if fd == nil {
|
||||
continue // unpopulated oneofs are not affected by EmitUnpopulated
|
||||
}
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
|
||||
val := m.Get(fd)
|
||||
if !m.Has(fd) {
|
||||
if !e.opts.EmitUnpopulated {
|
||||
continue
|
||||
}
|
||||
isProto2Scalar := fd.Syntax() == pref.Proto2 && fd.Default().IsValid()
|
||||
isSingularMessage := fd.Cardinality() != pref.Repeated && fd.Message() != nil
|
||||
if isProto2Scalar || isSingularMessage {
|
||||
// Use invalid value to emit null.
|
||||
val = pref.Value{}
|
||||
}
|
||||
}
|
||||
|
||||
name := fd.JSONName()
|
||||
if e.opts.UseProtoNames {
|
||||
name = string(fd.Name())
|
||||
// Use type name for group field name.
|
||||
if fd.Kind() == pref.GroupKind {
|
||||
name = string(fd.Message().Name())
|
||||
}
|
||||
}
|
||||
if err := e.WriteName(name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.marshalValue(val, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal out extensions.
|
||||
if err := e.marshalExtensions(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshalValue marshals the given protoreflect.Value.
|
||||
func (e encoder) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
|
||||
switch {
|
||||
case fd.IsList():
|
||||
return e.marshalList(val.List(), fd)
|
||||
case fd.IsMap():
|
||||
return e.marshalMap(val.Map(), fd)
|
||||
default:
|
||||
return e.marshalSingular(val, fd)
|
||||
}
|
||||
}
|
||||
|
||||
// marshalSingular marshals the given non-repeated field value. This includes
|
||||
// all scalar types, enums, messages, and groups.
|
||||
func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
|
||||
if !val.IsValid() {
|
||||
e.WriteNull()
|
||||
return nil
|
||||
}
|
||||
|
||||
switch kind := fd.Kind(); kind {
|
||||
case pref.BoolKind:
|
||||
e.WriteBool(val.Bool())
|
||||
|
||||
case pref.StringKind:
|
||||
if e.WriteString(val.String()) != nil {
|
||||
return errors.InvalidUTF8(string(fd.FullName()))
|
||||
}
|
||||
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
e.WriteInt(val.Int())
|
||||
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
e.WriteUint(val.Uint())
|
||||
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
|
||||
pref.Sfixed64Kind, pref.Fixed64Kind:
|
||||
// 64-bit integers are written out as JSON string.
|
||||
e.WriteString(val.String())
|
||||
|
||||
case pref.FloatKind:
|
||||
// Encoder.WriteFloat handles the special numbers NaN and infinites.
|
||||
e.WriteFloat(val.Float(), 32)
|
||||
|
||||
case pref.DoubleKind:
|
||||
// Encoder.WriteFloat handles the special numbers NaN and infinites.
|
||||
e.WriteFloat(val.Float(), 64)
|
||||
|
||||
case pref.BytesKind:
|
||||
e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
|
||||
|
||||
case pref.EnumKind:
|
||||
if fd.Enum().FullName() == "google.protobuf.NullValue" {
|
||||
e.WriteNull()
|
||||
} else {
|
||||
desc := fd.Enum().Values().ByNumber(val.Enum())
|
||||
if e.opts.UseEnumNumbers || desc == nil {
|
||||
e.WriteInt(int64(val.Enum()))
|
||||
} else {
|
||||
e.WriteString(string(desc.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
if err := e.marshalMessage(val.Message()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshalList marshals the given protoreflect.List.
|
||||
func (e encoder) marshalList(list pref.List, fd pref.FieldDescriptor) error {
|
||||
e.StartArray()
|
||||
defer e.EndArray()
|
||||
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
item := list.Get(i)
|
||||
if err := e.marshalSingular(item, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mapEntry struct {
|
||||
key pref.MapKey
|
||||
value pref.Value
|
||||
}
|
||||
|
||||
// marshalMap marshals given protoreflect.Map.
|
||||
func (e encoder) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
|
||||
e.StartObject()
|
||||
defer e.EndObject()
|
||||
|
||||
// Get a sorted list based on keyType first.
|
||||
entries := make([]mapEntry, 0, mmap.Len())
|
||||
mmap.Range(func(key pref.MapKey, val pref.Value) bool {
|
||||
entries = append(entries, mapEntry{key: key, value: val})
|
||||
return true
|
||||
})
|
||||
sortMap(fd.MapKey().Kind(), entries)
|
||||
|
||||
// Write out sorted list.
|
||||
for _, entry := range entries {
|
||||
if err := e.WriteName(entry.key.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.marshalSingular(entry.value, fd.MapValue()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sortMap orders list based on value of key field for deterministic ordering.
|
||||
func sortMap(keyKind pref.Kind, values []mapEntry) {
|
||||
sort.Slice(values, func(i, j int) bool {
|
||||
switch keyKind {
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
|
||||
pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
return values[i].key.Int() < values[j].key.Int()
|
||||
|
||||
case pref.Uint32Kind, pref.Fixed32Kind,
|
||||
pref.Uint64Kind, pref.Fixed64Kind:
|
||||
return values[i].key.Uint() < values[j].key.Uint()
|
||||
}
|
||||
return values[i].key.String() < values[j].key.String()
|
||||
})
|
||||
}
|
||||
|
||||
// marshalExtensions marshals extension fields.
|
||||
func (e encoder) marshalExtensions(m pref.Message) error {
|
||||
type entry struct {
|
||||
key string
|
||||
value pref.Value
|
||||
desc pref.FieldDescriptor
|
||||
}
|
||||
|
||||
// Get a sorted list based on field key first.
|
||||
var entries []entry
|
||||
m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
|
||||
if !fd.IsExtension() {
|
||||
return true
|
||||
}
|
||||
|
||||
// For MessageSet extensions, the name used is the parent message.
|
||||
name := fd.FullName()
|
||||
if messageset.IsMessageSetExtension(fd) {
|
||||
name = name.Parent()
|
||||
}
|
||||
|
||||
// Use [name] format for JSON field name.
|
||||
entries = append(entries, entry{
|
||||
key: string(name),
|
||||
value: v,
|
||||
desc: fd,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
// Sort extensions lexicographically.
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
return entries[i].key < entries[j].key
|
||||
})
|
||||
|
||||
// Write out sorted list.
|
||||
for _, entry := range entries {
|
||||
// JSON field name is the proto field name enclosed in [], similar to
|
||||
// textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
|
||||
// marshal out extension fields.
|
||||
if err := e.WriteName("[" + entry.key + "]"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.marshalValue(entry.value, entry.desc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
903
vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go
generated
vendored
Normal file
903
vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go
generated
vendored
Normal file
@@ -0,0 +1,903 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package protojson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/internal/detectknown"
|
||||
"google.golang.org/protobuf/internal/encoding/json"
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
"google.golang.org/protobuf/internal/fieldnum"
|
||||
"google.golang.org/protobuf/internal/strs"
|
||||
"google.golang.org/protobuf/proto"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// isCustomType returns true if type name has special JSON conversion rules.
|
||||
// The list of custom types here has to match the ones in marshalCustomType and
|
||||
// unmarshalCustomType.
|
||||
func isCustomType(name pref.FullName) bool {
|
||||
switch detectknown.Which(name) {
|
||||
case detectknown.AnyProto:
|
||||
case detectknown.TimestampProto:
|
||||
case detectknown.DurationProto:
|
||||
case detectknown.WrappersProto:
|
||||
case detectknown.StructProto:
|
||||
case detectknown.FieldMaskProto:
|
||||
case detectknown.EmptyProto:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// marshalCustomType marshals given well-known type message that have special
|
||||
// JSON conversion rules. It needs to be a message type where isCustomType
|
||||
// returns true, else it will panic.
|
||||
func (e encoder) marshalCustomType(m pref.Message) error {
|
||||
name := m.Descriptor().FullName()
|
||||
switch detectknown.Which(name) {
|
||||
case detectknown.AnyProto:
|
||||
return e.marshalAny(m)
|
||||
case detectknown.TimestampProto:
|
||||
return e.marshalTimestamp(m)
|
||||
case detectknown.DurationProto:
|
||||
return e.marshalDuration(m)
|
||||
case detectknown.WrappersProto:
|
||||
return e.marshalWrapperType(m)
|
||||
case detectknown.StructProto:
|
||||
return e.marshalStructType(m)
|
||||
case detectknown.FieldMaskProto:
|
||||
return e.marshalFieldMask(m)
|
||||
case detectknown.EmptyProto:
|
||||
return e.marshalEmpty(m)
|
||||
default:
|
||||
panic(fmt.Sprintf("%s does not have a custom marshaler", name))
|
||||
}
|
||||
}
|
||||
|
||||
// unmarshalCustomType unmarshals given well-known type message that have
|
||||
// special JSON conversion rules. It needs to be a message type where
|
||||
// isCustomType returns true, else it will panic.
|
||||
func (d decoder) unmarshalCustomType(m pref.Message) error {
|
||||
name := m.Descriptor().FullName()
|
||||
switch detectknown.Which(name) {
|
||||
case detectknown.AnyProto:
|
||||
return d.unmarshalAny(m)
|
||||
case detectknown.TimestampProto:
|
||||
return d.unmarshalTimestamp(m)
|
||||
case detectknown.DurationProto:
|
||||
return d.unmarshalDuration(m)
|
||||
case detectknown.WrappersProto:
|
||||
return d.unmarshalWrapperType(m)
|
||||
case detectknown.StructProto:
|
||||
return d.unmarshalStructType(m)
|
||||
case detectknown.FieldMaskProto:
|
||||
return d.unmarshalFieldMask(m)
|
||||
case detectknown.EmptyProto:
|
||||
return d.unmarshalEmpty(m)
|
||||
default:
|
||||
panic(fmt.Sprintf("%s does not have a custom unmarshaler", name))
|
||||
}
|
||||
}
|
||||
|
||||
// The JSON representation of an Any message uses the regular representation of
|
||||
// the deserialized, embedded message, with an additional field `@type` which
|
||||
// contains the type URL. If the embedded message type is well-known and has a
|
||||
// custom JSON representation, that representation will be embedded adding a
|
||||
// field `value` which holds the custom JSON in addition to the `@type` field.
|
||||
|
||||
func (e encoder) marshalAny(m pref.Message) error {
|
||||
fds := m.Descriptor().Fields()
|
||||
fdType := fds.ByNumber(fieldnum.Any_TypeUrl)
|
||||
fdValue := fds.ByNumber(fieldnum.Any_Value)
|
||||
|
||||
// Start writing the JSON object.
|
||||
e.StartObject()
|
||||
defer e.EndObject()
|
||||
|
||||
if !m.Has(fdType) {
|
||||
if !m.Has(fdValue) {
|
||||
// If message is empty, marshal out empty JSON object.
|
||||
return nil
|
||||
} else {
|
||||
// Return error if type_url field is not set, but value is set.
|
||||
return errors.New("%s: type_url is not set", m.Descriptor().FullName())
|
||||
}
|
||||
}
|
||||
|
||||
typeVal := m.Get(fdType)
|
||||
valueVal := m.Get(fdValue)
|
||||
|
||||
// Marshal out @type field.
|
||||
typeURL := typeVal.String()
|
||||
e.WriteName("@type")
|
||||
if err := e.WriteString(typeURL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolve the type in order to unmarshal value field.
|
||||
emt, err := e.opts.Resolver.FindMessageByURL(typeURL)
|
||||
if err != nil {
|
||||
return errors.New("%s: unable to resolve %q: %v", m.Descriptor().FullName(), typeURL, err)
|
||||
}
|
||||
|
||||
em := emt.New()
|
||||
err = proto.UnmarshalOptions{
|
||||
AllowPartial: true, // never check required fields inside an Any
|
||||
Resolver: e.opts.Resolver,
|
||||
}.Unmarshal(valueVal.Bytes(), em.Interface())
|
||||
if err != nil {
|
||||
return errors.New("%s: unable to unmarshal %q: %v", m.Descriptor().FullName(), typeURL, err)
|
||||
}
|
||||
|
||||
// If type of value has custom JSON encoding, marshal out a field "value"
|
||||
// with corresponding custom JSON encoding of the embedded message as a
|
||||
// field.
|
||||
if isCustomType(emt.Descriptor().FullName()) {
|
||||
e.WriteName("value")
|
||||
return e.marshalCustomType(em)
|
||||
}
|
||||
|
||||
// Else, marshal out the embedded message's fields in this Any object.
|
||||
if err := e.marshalFields(em); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalAny(m pref.Message) error {
|
||||
// Peek to check for json.ObjectOpen to avoid advancing a read.
|
||||
start, err := d.Peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if start.Kind() != json.ObjectOpen {
|
||||
return d.unexpectedTokenError(start)
|
||||
}
|
||||
|
||||
// Use another decoder to parse the unread bytes for @type field. This
|
||||
// avoids advancing a read from current decoder because the current JSON
|
||||
// object may contain the fields of the embedded type.
|
||||
dec := decoder{d.Clone(), UnmarshalOptions{}}
|
||||
tok, err := findTypeURL(dec)
|
||||
switch err {
|
||||
case errEmptyObject:
|
||||
// An empty JSON object translates to an empty Any message.
|
||||
d.Read() // Read json.ObjectOpen.
|
||||
d.Read() // Read json.ObjectClose.
|
||||
return nil
|
||||
|
||||
case errMissingType:
|
||||
if d.opts.DiscardUnknown {
|
||||
// Treat all fields as unknowns, similar to an empty object.
|
||||
return d.skipJSONValue()
|
||||
}
|
||||
// Use start.Pos() for line position.
|
||||
return d.newError(start.Pos(), err.Error())
|
||||
|
||||
default:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
typeURL := tok.ParsedString()
|
||||
emt, err := d.opts.Resolver.FindMessageByURL(typeURL)
|
||||
if err != nil {
|
||||
return d.newError(tok.Pos(), "unable to resolve %v: %q", tok.RawString(), err)
|
||||
}
|
||||
|
||||
// Create new message for the embedded message type and unmarshal into it.
|
||||
em := emt.New()
|
||||
if isCustomType(emt.Descriptor().FullName()) {
|
||||
// If embedded message is a custom type,
|
||||
// unmarshal the JSON "value" field into it.
|
||||
if err := d.unmarshalAnyValue(em); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Else unmarshal the current JSON object into it.
|
||||
if err := d.unmarshalMessage(em, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Serialize the embedded message and assign the resulting bytes to the
|
||||
// proto value field.
|
||||
b, err := proto.MarshalOptions{
|
||||
AllowPartial: true, // No need to check required fields inside an Any.
|
||||
Deterministic: true,
|
||||
}.Marshal(em.Interface())
|
||||
if err != nil {
|
||||
return d.newError(start.Pos(), "error in marshaling Any.value field: %v", err)
|
||||
}
|
||||
|
||||
fds := m.Descriptor().Fields()
|
||||
fdType := fds.ByNumber(fieldnum.Any_TypeUrl)
|
||||
fdValue := fds.ByNumber(fieldnum.Any_Value)
|
||||
|
||||
m.Set(fdType, pref.ValueOfString(typeURL))
|
||||
m.Set(fdValue, pref.ValueOfBytes(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
var errEmptyObject = fmt.Errorf(`empty object`)
|
||||
var errMissingType = fmt.Errorf(`missing "@type" field`)
|
||||
|
||||
// findTypeURL returns the token for the "@type" field value from the given
|
||||
// JSON bytes. It is expected that the given bytes start with json.ObjectOpen.
|
||||
// It returns errEmptyObject if the JSON object is empty or errMissingType if
|
||||
// @type field does not exist. It returns other error if the @type field is not
|
||||
// valid or other decoding issues.
|
||||
func findTypeURL(d decoder) (json.Token, error) {
|
||||
var typeURL string
|
||||
var typeTok json.Token
|
||||
numFields := 0
|
||||
// Skip start object.
|
||||
d.Read()
|
||||
|
||||
Loop:
|
||||
for {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return json.Token{}, err
|
||||
}
|
||||
|
||||
switch tok.Kind() {
|
||||
case json.ObjectClose:
|
||||
if typeURL == "" {
|
||||
// Did not find @type field.
|
||||
if numFields > 0 {
|
||||
return json.Token{}, errMissingType
|
||||
}
|
||||
return json.Token{}, errEmptyObject
|
||||
}
|
||||
break Loop
|
||||
|
||||
case json.Name:
|
||||
numFields++
|
||||
if tok.Name() != "@type" {
|
||||
// Skip value.
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return json.Token{}, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Return error if this was previously set already.
|
||||
if typeURL != "" {
|
||||
return json.Token{}, d.newError(tok.Pos(), `duplicate "@type" field`)
|
||||
}
|
||||
// Read field value.
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return json.Token{}, err
|
||||
}
|
||||
if tok.Kind() != json.String {
|
||||
return json.Token{}, d.newError(tok.Pos(), `@type field value is not a string: %v`, tok.RawString())
|
||||
}
|
||||
typeURL = tok.ParsedString()
|
||||
if typeURL == "" {
|
||||
return json.Token{}, d.newError(tok.Pos(), `@type field contains empty value`)
|
||||
}
|
||||
typeTok = tok
|
||||
}
|
||||
}
|
||||
|
||||
return typeTok, nil
|
||||
}
|
||||
|
||||
// skipJSONValue parses a JSON value (null, boolean, string, number, object and
|
||||
// array) in order to advance the read to the next JSON value. It relies on
|
||||
// the decoder returning an error if the types are not in valid sequence.
|
||||
func (d decoder) skipJSONValue() error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Only need to continue reading for objects and arrays.
|
||||
switch tok.Kind() {
|
||||
case json.ObjectOpen:
|
||||
for {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
case json.ObjectClose:
|
||||
return nil
|
||||
case json.Name:
|
||||
// Skip object field value.
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case json.ArrayOpen:
|
||||
for {
|
||||
tok, err := d.Peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
case json.ArrayClose:
|
||||
d.Read()
|
||||
return nil
|
||||
default:
|
||||
// Skip array item.
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshalAnyValue unmarshals the given custom-type message from the JSON
|
||||
// object's "value" field.
|
||||
func (d decoder) unmarshalAnyValue(m pref.Message) error {
|
||||
// Skip ObjectOpen, and start reading the fields.
|
||||
d.Read()
|
||||
|
||||
var found bool // Used for detecting duplicate "value".
|
||||
for {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
case json.ObjectClose:
|
||||
if !found {
|
||||
return d.newError(tok.Pos(), `missing "value" field`)
|
||||
}
|
||||
return nil
|
||||
|
||||
case json.Name:
|
||||
switch tok.Name() {
|
||||
case "@type":
|
||||
// Skip the value as this was previously parsed already.
|
||||
d.Read()
|
||||
|
||||
case "value":
|
||||
if found {
|
||||
return d.newError(tok.Pos(), `duplicate "value" field`)
|
||||
}
|
||||
// Unmarshal the field value into the given message.
|
||||
if err := d.unmarshalCustomType(m); err != nil {
|
||||
return err
|
||||
}
|
||||
found = true
|
||||
|
||||
default:
|
||||
if d.opts.DiscardUnknown {
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return d.newError(tok.Pos(), "unknown field %v", tok.RawString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper types are encoded as JSON primitives like string, number or boolean.
|
||||
|
||||
// The "value" field has the same field number for all wrapper types.
|
||||
const wrapperFieldNumber = fieldnum.BoolValue_Value
|
||||
|
||||
func (e encoder) marshalWrapperType(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(wrapperFieldNumber)
|
||||
val := m.Get(fd)
|
||||
return e.marshalSingular(val, fd)
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalWrapperType(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(wrapperFieldNumber)
|
||||
val, err := d.unmarshalScalar(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Set(fd, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// The JSON representation for Empty is an empty JSON object.
|
||||
|
||||
func (e encoder) marshalEmpty(pref.Message) error {
|
||||
e.StartObject()
|
||||
e.EndObject()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalEmpty(pref.Message) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.ObjectOpen {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
for {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tok.Kind() {
|
||||
case json.ObjectClose:
|
||||
return nil
|
||||
|
||||
case json.Name:
|
||||
if d.opts.DiscardUnknown {
|
||||
if err := d.skipJSONValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return d.newError(tok.Pos(), "unknown field %v", tok.RawString())
|
||||
|
||||
default:
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e encoder) marshalStructType(m pref.Message) error {
|
||||
switch m.Descriptor().Name() {
|
||||
case "Struct":
|
||||
return e.marshalStruct(m)
|
||||
case "ListValue":
|
||||
return e.marshalListValue(m)
|
||||
case "Value":
|
||||
return e.marshalKnownValue(m)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid struct type: %v", m.Descriptor().FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalStructType(m pref.Message) error {
|
||||
switch m.Descriptor().Name() {
|
||||
case "Struct":
|
||||
return d.unmarshalStruct(m)
|
||||
case "ListValue":
|
||||
return d.unmarshalListValue(m)
|
||||
case "Value":
|
||||
return d.unmarshalKnownValue(m)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid struct type: %v", m.Descriptor().FullName()))
|
||||
}
|
||||
}
|
||||
|
||||
// The JSON representation for Struct is a JSON object that contains the encoded
|
||||
// Struct.fields map and follows the serialization rules for a map.
|
||||
|
||||
func (e encoder) marshalStruct(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.Struct_Fields)
|
||||
return e.marshalMap(m.Get(fd).Map(), fd)
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalStruct(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.Struct_Fields)
|
||||
return d.unmarshalMap(m.Mutable(fd).Map(), fd)
|
||||
}
|
||||
|
||||
// The JSON representation for ListValue is JSON array that contains the encoded
|
||||
// ListValue.values repeated field and follows the serialization rules for a
|
||||
// repeated field.
|
||||
|
||||
func (e encoder) marshalListValue(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.ListValue_Values)
|
||||
return e.marshalList(m.Get(fd).List(), fd)
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalListValue(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.ListValue_Values)
|
||||
return d.unmarshalList(m.Mutable(fd).List(), fd)
|
||||
}
|
||||
|
||||
// The JSON representation for a Value is dependent on the oneof field that is
|
||||
// set. Each of the field in the oneof has its own custom serialization rule. A
|
||||
// Value message needs to be a oneof field set, else it is an error.
|
||||
|
||||
func (e encoder) marshalKnownValue(m pref.Message) error {
|
||||
od := m.Descriptor().Oneofs().ByName("kind")
|
||||
fd := m.WhichOneof(od)
|
||||
if fd == nil {
|
||||
return errors.New("%s: none of the oneof fields is set", m.Descriptor().FullName())
|
||||
}
|
||||
return e.marshalSingular(m.Get(fd), fd)
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalKnownValue(m pref.Message) error {
|
||||
tok, err := d.Peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fd pref.FieldDescriptor
|
||||
var val pref.Value
|
||||
switch tok.Kind() {
|
||||
case json.Null:
|
||||
d.Read()
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_NullValue)
|
||||
val = pref.ValueOfEnum(0)
|
||||
|
||||
case json.Bool:
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_BoolValue)
|
||||
val = pref.ValueOfBool(tok.Bool())
|
||||
|
||||
case json.Number:
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_NumberValue)
|
||||
var ok bool
|
||||
val, ok = unmarshalFloat(tok, 64)
|
||||
if !ok {
|
||||
return d.newError(tok.Pos(), "invalid google.protobuf.Value: %v", tok.RawString())
|
||||
}
|
||||
|
||||
case json.String:
|
||||
// A JSON string may have been encoded from the number_value field,
|
||||
// e.g. "NaN", "Infinity", etc. Parsing a proto double type also allows
|
||||
// for it to be in JSON string form. Given this custom encoding spec,
|
||||
// however, there is no way to identify that and hence a JSON string is
|
||||
// always assigned to the string_value field, which means that certain
|
||||
// encoding cannot be parsed back to the same field.
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_StringValue)
|
||||
val = pref.ValueOfString(tok.ParsedString())
|
||||
|
||||
case json.ObjectOpen:
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_StructValue)
|
||||
val = m.NewField(fd)
|
||||
if err := d.unmarshalStruct(val.Message()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case json.ArrayOpen:
|
||||
fd = m.Descriptor().Fields().ByNumber(fieldnum.Value_ListValue)
|
||||
val = m.NewField(fd)
|
||||
if err := d.unmarshalListValue(val.Message()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return d.newError(tok.Pos(), "invalid google.protobuf.Value: %v", tok.RawString())
|
||||
}
|
||||
|
||||
m.Set(fd, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// The JSON representation for a Duration is a JSON string that ends in the
|
||||
// suffix "s" (indicating seconds) and is preceded by the number of seconds,
|
||||
// with nanoseconds expressed as fractional seconds.
|
||||
//
|
||||
// Durations less than one second are represented with a 0 seconds field and a
|
||||
// positive or negative nanos field. For durations of one second or more, a
|
||||
// non-zero value for the nanos field must be of the same sign as the seconds
|
||||
// field.
|
||||
//
|
||||
// Duration.seconds must be from -315,576,000,000 to +315,576,000,000 inclusive.
|
||||
// Duration.nanos must be from -999,999,999 to +999,999,999 inclusive.
|
||||
|
||||
const (
|
||||
secondsInNanos = 999999999
|
||||
maxSecondsInDuration = 315576000000
|
||||
)
|
||||
|
||||
func (e encoder) marshalDuration(m pref.Message) error {
|
||||
fds := m.Descriptor().Fields()
|
||||
fdSeconds := fds.ByNumber(fieldnum.Duration_Seconds)
|
||||
fdNanos := fds.ByNumber(fieldnum.Duration_Nanos)
|
||||
|
||||
secsVal := m.Get(fdSeconds)
|
||||
nanosVal := m.Get(fdNanos)
|
||||
secs := secsVal.Int()
|
||||
nanos := nanosVal.Int()
|
||||
if secs < -maxSecondsInDuration || secs > maxSecondsInDuration {
|
||||
return errors.New("%s: seconds out of range %v", m.Descriptor().FullName(), secs)
|
||||
}
|
||||
if nanos < -secondsInNanos || nanos > secondsInNanos {
|
||||
return errors.New("%s: nanos out of range %v", m.Descriptor().FullName(), nanos)
|
||||
}
|
||||
if (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) {
|
||||
return errors.New("%s: signs of seconds and nanos do not match", m.Descriptor().FullName())
|
||||
}
|
||||
// Generated output always contains 0, 3, 6, or 9 fractional digits,
|
||||
// depending on required precision, followed by the suffix "s".
|
||||
f := "%d.%09d"
|
||||
if nanos < 0 {
|
||||
nanos = -nanos
|
||||
if secs == 0 {
|
||||
f = "-%d.%09d"
|
||||
}
|
||||
}
|
||||
x := fmt.Sprintf(f, secs, nanos)
|
||||
x = strings.TrimSuffix(x, "000")
|
||||
x = strings.TrimSuffix(x, "000")
|
||||
x = strings.TrimSuffix(x, ".000")
|
||||
e.WriteString(x + "s")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalDuration(m pref.Message) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.String {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
secs, nanos, ok := parseDuration(tok.ParsedString())
|
||||
if !ok {
|
||||
return d.newError(tok.Pos(), "invalid google.protobuf.Duration value %v", tok.RawString())
|
||||
}
|
||||
// Validate seconds. No need to validate nanos because parseDuration would
|
||||
// have covered that already.
|
||||
if secs < -maxSecondsInDuration || secs > maxSecondsInDuration {
|
||||
return d.newError(tok.Pos(), "google.protobuf.Duration value out of range: %v", tok.RawString())
|
||||
}
|
||||
|
||||
fds := m.Descriptor().Fields()
|
||||
fdSeconds := fds.ByNumber(fieldnum.Duration_Seconds)
|
||||
fdNanos := fds.ByNumber(fieldnum.Duration_Nanos)
|
||||
|
||||
m.Set(fdSeconds, pref.ValueOfInt64(secs))
|
||||
m.Set(fdNanos, pref.ValueOfInt32(nanos))
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseDuration parses the given input string for seconds and nanoseconds value
|
||||
// for the Duration JSON format. The format is a decimal number with a suffix
|
||||
// 's'. It can have optional plus/minus sign. There needs to be at least an
|
||||
// integer or fractional part. Fractional part is limited to 9 digits only for
|
||||
// nanoseconds precision, regardless of whether there are trailing zero digits.
|
||||
// Example values are 1s, 0.1s, 1.s, .1s, +1s, -1s, -.1s.
|
||||
func parseDuration(input string) (int64, int32, bool) {
|
||||
b := []byte(input)
|
||||
size := len(b)
|
||||
if size < 2 {
|
||||
return 0, 0, false
|
||||
}
|
||||
if b[size-1] != 's' {
|
||||
return 0, 0, false
|
||||
}
|
||||
b = b[:size-1]
|
||||
|
||||
// Read optional plus/minus symbol.
|
||||
var neg bool
|
||||
switch b[0] {
|
||||
case '-':
|
||||
neg = true
|
||||
b = b[1:]
|
||||
case '+':
|
||||
b = b[1:]
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
// Read the integer part.
|
||||
var intp []byte
|
||||
switch {
|
||||
case b[0] == '0':
|
||||
b = b[1:]
|
||||
|
||||
case '1' <= b[0] && b[0] <= '9':
|
||||
intp = b[0:]
|
||||
b = b[1:]
|
||||
n := 1
|
||||
for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
|
||||
n++
|
||||
b = b[1:]
|
||||
}
|
||||
intp = intp[:n]
|
||||
|
||||
case b[0] == '.':
|
||||
// Continue below.
|
||||
|
||||
default:
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
hasFrac := false
|
||||
var frac [9]byte
|
||||
if len(b) > 0 {
|
||||
if b[0] != '.' {
|
||||
return 0, 0, false
|
||||
}
|
||||
// Read the fractional part.
|
||||
b = b[1:]
|
||||
n := 0
|
||||
for len(b) > 0 && n < 9 && '0' <= b[0] && b[0] <= '9' {
|
||||
frac[n] = b[0]
|
||||
n++
|
||||
b = b[1:]
|
||||
}
|
||||
// It is not valid if there are more bytes left.
|
||||
if len(b) > 0 {
|
||||
return 0, 0, false
|
||||
}
|
||||
// Pad fractional part with 0s.
|
||||
for i := n; i < 9; i++ {
|
||||
frac[i] = '0'
|
||||
}
|
||||
hasFrac = true
|
||||
}
|
||||
|
||||
var secs int64
|
||||
if len(intp) > 0 {
|
||||
var err error
|
||||
secs, err = strconv.ParseInt(string(intp), 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
var nanos int64
|
||||
if hasFrac {
|
||||
nanob := bytes.TrimLeft(frac[:], "0")
|
||||
if len(nanob) > 0 {
|
||||
var err error
|
||||
nanos, err = strconv.ParseInt(string(nanob), 10, 32)
|
||||
if err != nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
if secs > 0 {
|
||||
secs = -secs
|
||||
}
|
||||
if nanos > 0 {
|
||||
nanos = -nanos
|
||||
}
|
||||
}
|
||||
return secs, int32(nanos), true
|
||||
}
|
||||
|
||||
// The JSON representation for a Timestamp is a JSON string in the RFC 3339
|
||||
// format, i.e. "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where
|
||||
// {year} is always expressed using four digits while {month}, {day}, {hour},
|
||||
// {min}, and {sec} are zero-padded to two digits each. The fractional seconds,
|
||||
// which can go up to 9 digits, up to 1 nanosecond resolution, is optional. The
|
||||
// "Z" suffix indicates the timezone ("UTC"); the timezone is required. Encoding
|
||||
// should always use UTC (as indicated by "Z") and a decoder should be able to
|
||||
// accept both UTC and other timezones (as indicated by an offset).
|
||||
//
|
||||
// Timestamp.seconds must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z
|
||||
// inclusive.
|
||||
// Timestamp.nanos must be from 0 to 999,999,999 inclusive.
|
||||
|
||||
const (
|
||||
maxTimestampSeconds = 253402300799
|
||||
minTimestampSeconds = -62135596800
|
||||
)
|
||||
|
||||
func (e encoder) marshalTimestamp(m pref.Message) error {
|
||||
fds := m.Descriptor().Fields()
|
||||
fdSeconds := fds.ByNumber(fieldnum.Timestamp_Seconds)
|
||||
fdNanos := fds.ByNumber(fieldnum.Timestamp_Nanos)
|
||||
|
||||
secsVal := m.Get(fdSeconds)
|
||||
nanosVal := m.Get(fdNanos)
|
||||
secs := secsVal.Int()
|
||||
nanos := nanosVal.Int()
|
||||
if secs < minTimestampSeconds || secs > maxTimestampSeconds {
|
||||
return errors.New("%s: seconds out of range %v", m.Descriptor().FullName(), secs)
|
||||
}
|
||||
if nanos < 0 || nanos > secondsInNanos {
|
||||
return errors.New("%s: nanos out of range %v", m.Descriptor().FullName(), nanos)
|
||||
}
|
||||
// Uses RFC 3339, where generated output will be Z-normalized and uses 0, 3,
|
||||
// 6 or 9 fractional digits.
|
||||
t := time.Unix(secs, nanos).UTC()
|
||||
x := t.Format("2006-01-02T15:04:05.000000000")
|
||||
x = strings.TrimSuffix(x, "000")
|
||||
x = strings.TrimSuffix(x, "000")
|
||||
x = strings.TrimSuffix(x, ".000")
|
||||
e.WriteString(x + "Z")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalTimestamp(m pref.Message) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.String {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339Nano, tok.ParsedString())
|
||||
if err != nil {
|
||||
return d.newError(tok.Pos(), "invalid google.protobuf.Timestamp value %v", tok.RawString())
|
||||
}
|
||||
// Validate seconds. No need to validate nanos because time.Parse would have
|
||||
// covered that already.
|
||||
secs := t.Unix()
|
||||
if secs < minTimestampSeconds || secs > maxTimestampSeconds {
|
||||
return d.newError(tok.Pos(), "google.protobuf.Timestamp value out of range: %v", tok.RawString())
|
||||
}
|
||||
|
||||
fds := m.Descriptor().Fields()
|
||||
fdSeconds := fds.ByNumber(fieldnum.Timestamp_Seconds)
|
||||
fdNanos := fds.ByNumber(fieldnum.Timestamp_Nanos)
|
||||
|
||||
m.Set(fdSeconds, pref.ValueOfInt64(secs))
|
||||
m.Set(fdNanos, pref.ValueOfInt32(int32(t.Nanosecond())))
|
||||
return nil
|
||||
}
|
||||
|
||||
// The JSON representation for a FieldMask is a JSON string where paths are
|
||||
// separated by a comma. Fields name in each path are converted to/from
|
||||
// lower-camel naming conventions. Encoding should fail if the path name would
|
||||
// end up differently after a round-trip.
|
||||
|
||||
func (e encoder) marshalFieldMask(m pref.Message) error {
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.FieldMask_Paths)
|
||||
list := m.Get(fd).List()
|
||||
paths := make([]string, 0, list.Len())
|
||||
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
s := list.Get(i).String()
|
||||
// Return error if conversion to camelCase is not reversible.
|
||||
cc := strs.JSONCamelCase(s)
|
||||
if s != strs.JSONSnakeCase(cc) {
|
||||
return errors.New("%s.paths contains irreversible value %q", m.Descriptor().FullName(), s)
|
||||
}
|
||||
paths = append(paths, cc)
|
||||
}
|
||||
|
||||
e.WriteString(strings.Join(paths, ","))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d decoder) unmarshalFieldMask(m pref.Message) error {
|
||||
tok, err := d.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() != json.String {
|
||||
return d.unexpectedTokenError(tok)
|
||||
}
|
||||
str := strings.TrimSpace(tok.ParsedString())
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
paths := strings.Split(str, ",")
|
||||
|
||||
fd := m.Descriptor().Fields().ByNumber(fieldnum.FieldMask_Paths)
|
||||
list := m.Mutable(fd).List()
|
||||
|
||||
for _, s := range paths {
|
||||
s = strings.TrimSpace(s)
|
||||
// Convert to snake_case. Unlike encoding, no validation is done because
|
||||
// it is not possible to know the original path names.
|
||||
list.Append(pref.ValueOfString(strs.JSONSnakeCase(s)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user