2018-11-26 22:32:06 -08:00
|
|
|
// Copyright 2018 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 impl
|
|
|
|
|
|
|
|
import (
|
2019-09-03 15:33:00 -07:00
|
|
|
"fmt"
|
2019-05-01 12:29:25 -07:00
|
|
|
"reflect"
|
2019-03-16 00:05:34 -07:00
|
|
|
"strconv"
|
|
|
|
|
2019-05-14 12:44:37 -07:00
|
|
|
"google.golang.org/protobuf/encoding/prototext"
|
all: implement first-class WKT support
This CL introduces generation of specialized APIs directly into the
generated packages for certain well-known types. This follows the pattern
set forth by the other language implementations that have specialized
generated support for certain well-known types.
Overview of new API:
package anypb
func MarshalFrom(*Any, proto.Message, proto.MarshalOptions) error
func UnmarshalTo(*Any, proto.Message, proto.UnmarshalOptions) error
func UnmarshalNew(*Any, proto.UnmarshalOptions) (proto.Message, error)
func (*Any) MessageIs(proto.Message) bool
func (*Any) MessageName() protoreflect.FullName
func (*Any) MarshalFrom(proto.Message) error
func (*Any) UnmarshalTo(proto.Message) error
func (*Any) UnmarshalNew() (proto.Message, error)
package timestamppb
func Now() *Timestamp
func New(time.Time) *Timestamp
func (*Timestamp) AsTime() time.Time
func (*Timestamp) IsValid() bool
func (*Timestamp) CheckValid() error
package durationpb
func New(time.Duration) *Duration
func (*Duration) AsDuration() time.Duration
func (*Duration) IsValid() bool
func (*Duration) CheckValid() error
package structpb
func NewStruct(map[string]interface{}) (*Struct, error)
func (*Struct) AsMap() map[string]interface{}
func (*Struct) MarshalJSON() ([]byte, error)
func (*Struct) UnmarshalJSON(b []byte) error
func NewList([]interface{}) (*ListValue, error)
func (*ListValue) AsSlice() []interface{}
func (*ListValue) MarshalJSON() ([]byte, error)
func (*ListValue) UnmarshalJSON(b []byte) error
func NewValue(interface{}) (*Value, error)
func NewNullValue() *Value
func NewBoolValue(bool) *Value
func NewNumberValue(float64) *Value
func NewStringValue(string) *Value
func NewStructValue(*Struct) *Value
func NewListValue(*ListValue) *Value
func (*Value) AsInterface() interface{}
func (*Value) MarshalJSON() ([]byte, error)
func (*Value) UnmarshalJSON(b []byte) error
package fieldmaskpb
func New(proto.Message, ...string) (*FieldMask, error)
func Union(*FieldMask, *FieldMask, ...*FieldMask) *FieldMask
func Intersect(*FieldMask, *FieldMask, ...*FieldMask) *FieldMask
func (*FieldMask) IsValid(proto.Message) bool
func (*FieldMask) Append(proto.Message, ...string) error
func (*FieldMask) Normalize()
package wrapperspb
func Bool(bool) *BoolValue
func Int32(int32) *Int32Value
func Int64(int64) *Int64Value
func UInt32(uint32) *UInt32Value
func UInt64(uint64) *UInt64Value
func Float(float32) *FloatValue
func Double(float64) *DoubleValue
func String(string) *StringValue
func Bytes([]byte) *BytesValue
This functionality expands upon and supersedes the
older github.com/golang/protobuf/ptypes package,
which provided helpers for Any, Timestamp, and Duration.
Comparison with older ptypes package:
* ptypes.AnyMessageName is replaced by anypb.Any.MessageName.
The former returned an error for malformed type URLs,
while the latter simply returns an empty string.
* ptypes.Is is replaced by anypb.Any.MessageIs.
* ptypes.Empty has no direct replacement as it is equivalent to:
mt, err := protoregistry.GlobalTypes.FindMessageByURL(any.GetTypeUrl())
if err != nil {
return nil, err
}
return mt.New().Interface(), nil
Analysis of user code revealed that this function is seldom used.
* ptypes.MarshalAny is replaced by anypb.Any.MarshalFrom.
The former creates a new Any message and returns it,
while the latter is a method that modifies the receiver.
* ptypes.UnmarshalAny is replaced by anypb.Any.UnmarshalTo.
* ptypes.DynamicAny is loosely replaced by anypb.Any.UnmarshalNew.
The DynamicAny type is a custom proto.Message that is special
to ptypes.UnmarshalAny where it would allocate a new message
and store it into the DynamicAny instance. The UnmarshalNew method
accomplishes the equivalent functionality in a more direct fashion.
* ptypes.TimestampNow is replaced by timestamppb.Now.
* ptypes.TimestampProto is replaced by timestamppb.New.
The former returned an error if the timestamp was outside the
10000-year range recommended by timestamp.proto,
while the latter always succeeded. To preserve the behavior of
the former validation check, the replacement can additionally
call the timestamppb.Timestamp.CheckValid method.
* ptypes.Timestamp is replaced by timestamppb.Timestamp.AsTime.
The former returned an error if the timestamp was outside the
10000-year range recommended by timestamp.proto,
while the latter always succeeded. To preserve the behavior of
the former validation check, the replacement can additionally
call the timestamppb.Timestamp.CheckValid method.
* ptypes.TimestampString has no direct replacement as it is equivalent to:
ts.AsTime().Format(time.RFC3339Nano)
* ptypes.DurationProto is replaced by durationpb.New.
* ptypes.Duration is replaced by durationpb.Duration.AsDuration.
The former returned an error if the duration would overflow
when converting to a time.Duration, while the latter uses
saturation arithmetic (similiar to the time package itself).
Underflow resulted in time.Duration(math.MinInt64), while
overflow resulted in time.Duration(math.MaxInt64).
To preserve the behavior of former validation checks,
the replacement can call the durationpb.Duration.CheckValid method
and check whether the duration is fixed to one of the overflow values.
Change-Id: Ia996b1037a1fcafced7c7e10e9408ef7fa22863a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/225298
Reviewed-by: Damien Neil <dneil@google.com>
2020-03-24 12:22:13 -07:00
|
|
|
"google.golang.org/protobuf/internal/errors"
|
2019-09-03 15:33:00 -07:00
|
|
|
"google.golang.org/protobuf/proto"
|
2019-05-13 23:55:40 -07:00
|
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
2019-09-03 15:33:00 -07:00
|
|
|
piface "google.golang.org/protobuf/runtime/protoiface"
|
2018-11-26 22:32:06 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Export is a zero-length named type that exists only to export a set of
|
|
|
|
// functions that we do not want to appear in godoc.
|
|
|
|
type Export struct{}
|
|
|
|
|
all: implement first-class WKT support
This CL introduces generation of specialized APIs directly into the
generated packages for certain well-known types. This follows the pattern
set forth by the other language implementations that have specialized
generated support for certain well-known types.
Overview of new API:
package anypb
func MarshalFrom(*Any, proto.Message, proto.MarshalOptions) error
func UnmarshalTo(*Any, proto.Message, proto.UnmarshalOptions) error
func UnmarshalNew(*Any, proto.UnmarshalOptions) (proto.Message, error)
func (*Any) MessageIs(proto.Message) bool
func (*Any) MessageName() protoreflect.FullName
func (*Any) MarshalFrom(proto.Message) error
func (*Any) UnmarshalTo(proto.Message) error
func (*Any) UnmarshalNew() (proto.Message, error)
package timestamppb
func Now() *Timestamp
func New(time.Time) *Timestamp
func (*Timestamp) AsTime() time.Time
func (*Timestamp) IsValid() bool
func (*Timestamp) CheckValid() error
package durationpb
func New(time.Duration) *Duration
func (*Duration) AsDuration() time.Duration
func (*Duration) IsValid() bool
func (*Duration) CheckValid() error
package structpb
func NewStruct(map[string]interface{}) (*Struct, error)
func (*Struct) AsMap() map[string]interface{}
func (*Struct) MarshalJSON() ([]byte, error)
func (*Struct) UnmarshalJSON(b []byte) error
func NewList([]interface{}) (*ListValue, error)
func (*ListValue) AsSlice() []interface{}
func (*ListValue) MarshalJSON() ([]byte, error)
func (*ListValue) UnmarshalJSON(b []byte) error
func NewValue(interface{}) (*Value, error)
func NewNullValue() *Value
func NewBoolValue(bool) *Value
func NewNumberValue(float64) *Value
func NewStringValue(string) *Value
func NewStructValue(*Struct) *Value
func NewListValue(*ListValue) *Value
func (*Value) AsInterface() interface{}
func (*Value) MarshalJSON() ([]byte, error)
func (*Value) UnmarshalJSON(b []byte) error
package fieldmaskpb
func New(proto.Message, ...string) (*FieldMask, error)
func Union(*FieldMask, *FieldMask, ...*FieldMask) *FieldMask
func Intersect(*FieldMask, *FieldMask, ...*FieldMask) *FieldMask
func (*FieldMask) IsValid(proto.Message) bool
func (*FieldMask) Append(proto.Message, ...string) error
func (*FieldMask) Normalize()
package wrapperspb
func Bool(bool) *BoolValue
func Int32(int32) *Int32Value
func Int64(int64) *Int64Value
func UInt32(uint32) *UInt32Value
func UInt64(uint64) *UInt64Value
func Float(float32) *FloatValue
func Double(float64) *DoubleValue
func String(string) *StringValue
func Bytes([]byte) *BytesValue
This functionality expands upon and supersedes the
older github.com/golang/protobuf/ptypes package,
which provided helpers for Any, Timestamp, and Duration.
Comparison with older ptypes package:
* ptypes.AnyMessageName is replaced by anypb.Any.MessageName.
The former returned an error for malformed type URLs,
while the latter simply returns an empty string.
* ptypes.Is is replaced by anypb.Any.MessageIs.
* ptypes.Empty has no direct replacement as it is equivalent to:
mt, err := protoregistry.GlobalTypes.FindMessageByURL(any.GetTypeUrl())
if err != nil {
return nil, err
}
return mt.New().Interface(), nil
Analysis of user code revealed that this function is seldom used.
* ptypes.MarshalAny is replaced by anypb.Any.MarshalFrom.
The former creates a new Any message and returns it,
while the latter is a method that modifies the receiver.
* ptypes.UnmarshalAny is replaced by anypb.Any.UnmarshalTo.
* ptypes.DynamicAny is loosely replaced by anypb.Any.UnmarshalNew.
The DynamicAny type is a custom proto.Message that is special
to ptypes.UnmarshalAny where it would allocate a new message
and store it into the DynamicAny instance. The UnmarshalNew method
accomplishes the equivalent functionality in a more direct fashion.
* ptypes.TimestampNow is replaced by timestamppb.Now.
* ptypes.TimestampProto is replaced by timestamppb.New.
The former returned an error if the timestamp was outside the
10000-year range recommended by timestamp.proto,
while the latter always succeeded. To preserve the behavior of
the former validation check, the replacement can additionally
call the timestamppb.Timestamp.CheckValid method.
* ptypes.Timestamp is replaced by timestamppb.Timestamp.AsTime.
The former returned an error if the timestamp was outside the
10000-year range recommended by timestamp.proto,
while the latter always succeeded. To preserve the behavior of
the former validation check, the replacement can additionally
call the timestamppb.Timestamp.CheckValid method.
* ptypes.TimestampString has no direct replacement as it is equivalent to:
ts.AsTime().Format(time.RFC3339Nano)
* ptypes.DurationProto is replaced by durationpb.New.
* ptypes.Duration is replaced by durationpb.Duration.AsDuration.
The former returned an error if the duration would overflow
when converting to a time.Duration, while the latter uses
saturation arithmetic (similiar to the time package itself).
Underflow resulted in time.Duration(math.MinInt64), while
overflow resulted in time.Duration(math.MaxInt64).
To preserve the behavior of former validation checks,
the replacement can call the durationpb.Duration.CheckValid method
and check whether the duration is fixed to one of the overflow values.
Change-Id: Ia996b1037a1fcafced7c7e10e9408ef7fa22863a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/225298
Reviewed-by: Damien Neil <dneil@google.com>
2020-03-24 12:22:13 -07:00
|
|
|
// NewError formats a string according to the format specifier and arguments and
|
|
|
|
// returns an error that has a "proto" prefix.
|
|
|
|
func (Export) NewError(f string, x ...interface{}) error {
|
|
|
|
return errors.New(f, x...)
|
|
|
|
}
|
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
// enum is any enum type generated by protoc-gen-go
|
|
|
|
// and must be a named int32 type.
|
|
|
|
type enum = interface{}
|
|
|
|
|
2018-11-26 22:32:06 -08:00
|
|
|
// EnumOf returns the protoreflect.Enum interface over e.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if e is nil.
|
2019-05-01 12:29:25 -07:00
|
|
|
func (Export) EnumOf(e enum) pref.Enum {
|
2020-01-03 20:18:06 -08:00
|
|
|
switch e := e.(type) {
|
|
|
|
case nil:
|
|
|
|
return nil
|
|
|
|
case pref.Enum:
|
|
|
|
return e
|
|
|
|
default:
|
|
|
|
return legacyWrapEnum(reflect.ValueOf(e))
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
// EnumDescriptorOf returns the protoreflect.EnumDescriptor for e.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if e is nil.
|
2019-05-01 12:29:25 -07:00
|
|
|
func (Export) EnumDescriptorOf(e enum) pref.EnumDescriptor {
|
2020-01-03 20:18:06 -08:00
|
|
|
switch e := e.(type) {
|
|
|
|
case nil:
|
|
|
|
return nil
|
|
|
|
case pref.Enum:
|
|
|
|
return e.Descriptor()
|
|
|
|
default:
|
|
|
|
return LegacyLoadEnumDesc(reflect.TypeOf(e))
|
2019-05-01 12:29:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 15:33:00 -07:00
|
|
|
// EnumTypeOf returns the protoreflect.EnumType for e.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if e is nil.
|
2019-09-03 15:33:00 -07:00
|
|
|
func (Export) EnumTypeOf(e enum) pref.EnumType {
|
2020-01-03 20:18:06 -08:00
|
|
|
switch e := e.(type) {
|
|
|
|
case nil:
|
|
|
|
return nil
|
|
|
|
case pref.Enum:
|
|
|
|
return e.Type()
|
|
|
|
default:
|
|
|
|
return legacyLoadEnumType(reflect.TypeOf(e))
|
2019-09-03 15:33:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-16 00:05:34 -07:00
|
|
|
// EnumStringOf returns the enum value as a string, either as the name if
|
|
|
|
// the number is resolvable, or the number formatted as a string.
|
|
|
|
func (Export) EnumStringOf(ed pref.EnumDescriptor, n pref.EnumNumber) string {
|
|
|
|
ev := ed.Values().ByNumber(n)
|
|
|
|
if ev != nil {
|
|
|
|
return string(ev.Name())
|
|
|
|
}
|
|
|
|
return strconv.Itoa(int(n))
|
|
|
|
}
|
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
// message is any message type generated by protoc-gen-go
|
|
|
|
// and must be a pointer to a named struct type.
|
|
|
|
type message = interface{}
|
|
|
|
|
2019-09-03 15:33:00 -07:00
|
|
|
// legacyMessageWrapper wraps a v2 message as a v1 message.
|
2019-09-04 22:41:40 -07:00
|
|
|
type legacyMessageWrapper struct{ m pref.ProtoMessage }
|
2019-09-03 15:33:00 -07:00
|
|
|
|
|
|
|
func (m legacyMessageWrapper) Reset() { proto.Reset(m.m) }
|
|
|
|
func (m legacyMessageWrapper) String() string { return Export{}.MessageStringOf(m.m) }
|
|
|
|
func (m legacyMessageWrapper) ProtoMessage() {}
|
|
|
|
|
|
|
|
// ProtoMessageV1Of converts either a v1 or v2 message to a v1 message.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if m is nil.
|
2019-09-03 15:33:00 -07:00
|
|
|
func (Export) ProtoMessageV1Of(m message) piface.MessageV1 {
|
|
|
|
switch mv := m.(type) {
|
2019-09-06 00:30:59 -07:00
|
|
|
case nil:
|
|
|
|
return nil
|
2019-09-03 15:33:00 -07:00
|
|
|
case piface.MessageV1:
|
|
|
|
return mv
|
2019-09-03 16:30:39 -07:00
|
|
|
case unwrapper:
|
|
|
|
return Export{}.ProtoMessageV1Of(mv.protoUnwrap())
|
2019-09-04 22:41:40 -07:00
|
|
|
case pref.ProtoMessage:
|
2019-09-03 15:33:00 -07:00
|
|
|
return legacyMessageWrapper{mv}
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("message %T is neither a v1 or v2 Message", m))
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 22:41:40 -07:00
|
|
|
func (Export) protoMessageV2Of(m message) pref.ProtoMessage {
|
2019-09-03 15:33:00 -07:00
|
|
|
switch mv := m.(type) {
|
2019-09-06 00:30:59 -07:00
|
|
|
case nil:
|
|
|
|
return nil
|
2019-09-04 22:41:40 -07:00
|
|
|
case pref.ProtoMessage:
|
2019-09-03 15:33:00 -07:00
|
|
|
return mv
|
|
|
|
case legacyMessageWrapper:
|
|
|
|
return mv.m
|
|
|
|
case piface.MessageV1:
|
2019-09-04 22:41:40 -07:00
|
|
|
return nil
|
2019-09-03 15:33:00 -07:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("message %T is neither a v1 or v2 Message", m))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 22:41:40 -07:00
|
|
|
// ProtoMessageV2Of converts either a v1 or v2 message to a v2 message.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if m is nil.
|
2019-09-04 22:41:40 -07:00
|
|
|
func (Export) ProtoMessageV2Of(m message) pref.ProtoMessage {
|
2020-01-03 20:18:06 -08:00
|
|
|
if m == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
|
2019-09-04 22:41:40 -07:00
|
|
|
return mv
|
|
|
|
}
|
2020-04-01 11:47:49 -07:00
|
|
|
return legacyWrapMessage(reflect.ValueOf(m)).Interface()
|
2019-09-04 22:41:40 -07:00
|
|
|
}
|
|
|
|
|
2019-09-03 15:33:00 -07:00
|
|
|
// MessageOf returns the protoreflect.Message interface over m.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if m is nil.
|
2019-09-03 15:33:00 -07:00
|
|
|
func (Export) MessageOf(m message) pref.Message {
|
2020-01-03 20:18:06 -08:00
|
|
|
if m == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-09-04 22:41:40 -07:00
|
|
|
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
|
2019-09-03 15:33:00 -07:00
|
|
|
return mv.ProtoReflect()
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
2020-04-01 11:47:49 -07:00
|
|
|
return legacyWrapMessage(reflect.ValueOf(m))
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
|
|
|
|
2019-05-01 12:29:25 -07:00
|
|
|
// MessageDescriptorOf returns the protoreflect.MessageDescriptor for m.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if m is nil.
|
2019-05-01 12:29:25 -07:00
|
|
|
func (Export) MessageDescriptorOf(m message) pref.MessageDescriptor {
|
2020-01-03 20:18:06 -08:00
|
|
|
if m == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-09-04 22:41:40 -07:00
|
|
|
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
|
2019-05-01 12:29:25 -07:00
|
|
|
return mv.ProtoReflect().Descriptor()
|
2019-09-03 15:33:00 -07:00
|
|
|
}
|
2019-09-04 22:41:40 -07:00
|
|
|
return LegacyLoadMessageDesc(reflect.TypeOf(m))
|
2019-09-03 15:33:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// MessageTypeOf returns the protoreflect.MessageType for m.
|
2020-01-03 20:18:06 -08:00
|
|
|
// It returns nil if m is nil.
|
2019-09-03 15:33:00 -07:00
|
|
|
func (Export) MessageTypeOf(m message) pref.MessageType {
|
2020-01-03 20:18:06 -08:00
|
|
|
if m == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-09-04 22:41:40 -07:00
|
|
|
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
|
2019-09-03 15:33:00 -07:00
|
|
|
return mv.ProtoReflect().Type()
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
2019-09-04 22:41:40 -07:00
|
|
|
return legacyLoadMessageInfo(reflect.TypeOf(m), "")
|
2018-11-26 22:32:06 -08:00
|
|
|
}
|
2019-03-20 09:46:22 -07:00
|
|
|
|
|
|
|
// MessageStringOf returns the message value as a string,
|
|
|
|
// which is the message serialized in the protobuf text format.
|
|
|
|
func (Export) MessageStringOf(m pref.ProtoMessage) string {
|
2020-01-06 15:44:09 -08:00
|
|
|
return prototext.MarshalOptions{Multiline: false}.Format(m)
|
2019-03-20 09:46:22 -07:00
|
|
|
}
|