Update deps

This commit is contained in:
Frank Denis 2021-07-03 10:56:53 +02:00
parent f033bb3034
commit 5a091c6da4
1997 changed files with 368830 additions and 2045 deletions

View file

@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.22.0
// protoc v3.11.2
// protoc v3.12.3
// source: google/rpc/status.proto
package status

View file

@ -33,6 +33,9 @@ const (
OK Code = 0
// Canceled indicates the operation was canceled (typically by the caller).
//
// The gRPC framework will generate this error code when cancellation
// is requested.
Canceled Code = 1
// Unknown error. An example of where this error may be returned is
@ -40,12 +43,17 @@ const (
// an error-space that is not known in this address space. Also
// errors raised by APIs that do not return enough error information
// may be converted to this error.
//
// The gRPC framework will generate this error code in the above two
// mentioned cases.
Unknown Code = 2
// InvalidArgument indicates client specified an invalid argument.
// Note that this differs from FailedPrecondition. It indicates arguments
// that are problematic regardless of the state of the system
// (e.g., a malformed file name).
//
// This error code will not be generated by the gRPC framework.
InvalidArgument Code = 3
// DeadlineExceeded means operation expired before completion.
@ -53,14 +61,21 @@ const (
// returned even if the operation has completed successfully. For
// example, a successful response from a server could have been delayed
// long enough for the deadline to expire.
//
// The gRPC framework will generate this error code when the deadline is
// exceeded.
DeadlineExceeded Code = 4
// NotFound means some requested entity (e.g., file or directory) was
// not found.
//
// This error code will not be generated by the gRPC framework.
NotFound Code = 5
// AlreadyExists means an attempt to create an entity failed because one
// already exists.
//
// This error code will not be generated by the gRPC framework.
AlreadyExists Code = 6
// PermissionDenied indicates the caller does not have permission to
@ -69,10 +84,17 @@ const (
// instead for those errors). It must not be
// used if the caller cannot be identified (use Unauthenticated
// instead for those errors).
//
// This error code will not be generated by the gRPC core framework,
// but expect authentication middleware to use it.
PermissionDenied Code = 7
// ResourceExhausted indicates some resource has been exhausted, perhaps
// a per-user quota, or perhaps the entire file system is out of space.
//
// This error code will be generated by the gRPC framework in
// out-of-memory and server overload situations, or when a message is
// larger than the configured maximum size.
ResourceExhausted Code = 8
// FailedPrecondition indicates operation was rejected because the
@ -94,6 +116,8 @@ const (
// REST Get/Update/Delete on a resource and the resource on the
// server does not match the condition. E.g., conflicting
// read-modify-write on the same resource.
//
// This error code will not be generated by the gRPC framework.
FailedPrecondition Code = 9
// Aborted indicates the operation was aborted, typically due to a
@ -102,6 +126,8 @@ const (
//
// See litmus test above for deciding between FailedPrecondition,
// Aborted, and Unavailable.
//
// This error code will not be generated by the gRPC framework.
Aborted Code = 10
// OutOfRange means operation was attempted past the valid range.
@ -119,15 +145,26 @@ const (
// error) when it applies so that callers who are iterating through
// a space can easily look for an OutOfRange error to detect when
// they are done.
//
// This error code will not be generated by the gRPC framework.
OutOfRange Code = 11
// Unimplemented indicates operation is not implemented or not
// supported/enabled in this service.
//
// This error code will be generated by the gRPC framework. Most
// commonly, you will see this error code when a method implementation
// is missing on the server. It can also be generated for unknown
// compression algorithms or a disagreement as to whether an RPC should
// be streaming.
Unimplemented Code = 12
// Internal errors. Means some invariants expected by underlying
// system has been broken. If you see one of these errors,
// something is very broken.
//
// This error code will be generated by the gRPC framework in several
// internal error conditions.
Internal Code = 13
// Unavailable indicates the service is currently unavailable.
@ -137,13 +174,22 @@ const (
//
// See litmus test above for deciding between FailedPrecondition,
// Aborted, and Unavailable.
//
// This error code will be generated by the gRPC framework during
// abrupt shutdown of a server process or network connection.
Unavailable Code = 14
// DataLoss indicates unrecoverable data loss or corruption.
//
// This error code will not be generated by the gRPC framework.
DataLoss Code = 15
// Unauthenticated indicates the request does not have valid
// authentication credentials for the operation.
//
// The gRPC framework will generate this error code when the
// authentication metadata is invalid or a Credentials callback fails,
// but also expect authentication middleware to generate it.
Unauthenticated Code = 16
_maxCode = 17

View file

@ -1,73 +0,0 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package connectivity defines connectivity semantics.
// For details, see https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md.
// All APIs in this package are experimental.
package connectivity
import (
"context"
"google.golang.org/grpc/grpclog"
)
// State indicates the state of connectivity.
// It can be the state of a ClientConn or SubConn.
type State int
func (s State) String() string {
switch s {
case Idle:
return "IDLE"
case Connecting:
return "CONNECTING"
case Ready:
return "READY"
case TransientFailure:
return "TRANSIENT_FAILURE"
case Shutdown:
return "SHUTDOWN"
default:
grpclog.Errorf("unknown connectivity state: %d", s)
return "Invalid-State"
}
}
const (
// Idle indicates the ClientConn is idle.
Idle State = iota
// Connecting indicates the ClientConn is connecting.
Connecting
// Ready indicates the ClientConn is ready for work.
Ready
// TransientFailure indicates the ClientConn has seen a failure but expects to recover.
TransientFailure
// Shutdown indicates the ClientConn has started shutting down.
Shutdown
)
// Reporter reports the connectivity states.
type Reporter interface {
// CurrentState returns the current state of the reporter.
CurrentState() State
// WaitForStateChange blocks until the reporter's state is different from the given state,
// and returns true.
// It returns false if <-ctx.Done() can proceed (ctx got timeout or got canceled).
WaitForStateChange(context.Context, State) bool
}

View file

@ -1,126 +0,0 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package grpclog defines logging for grpc.
//
// All logs in transport and grpclb packages only go to verbose level 2.
// All logs in other packages in grpc are logged in spite of the verbosity level.
//
// In the default logger,
// severity level can be set by environment variable GRPC_GO_LOG_SEVERITY_LEVEL,
// verbosity level can be set by GRPC_GO_LOG_VERBOSITY_LEVEL.
package grpclog // import "google.golang.org/grpc/grpclog"
import "os"
var logger = newLoggerV2()
// V reports whether verbosity level l is at least the requested verbose level.
func V(l int) bool {
return logger.V(l)
}
// Info logs to the INFO log.
func Info(args ...interface{}) {
logger.Info(args...)
}
// Infof logs to the INFO log. Arguments are handled in the manner of fmt.Printf.
func Infof(format string, args ...interface{}) {
logger.Infof(format, args...)
}
// Infoln logs to the INFO log. Arguments are handled in the manner of fmt.Println.
func Infoln(args ...interface{}) {
logger.Infoln(args...)
}
// Warning logs to the WARNING log.
func Warning(args ...interface{}) {
logger.Warning(args...)
}
// Warningf logs to the WARNING log. Arguments are handled in the manner of fmt.Printf.
func Warningf(format string, args ...interface{}) {
logger.Warningf(format, args...)
}
// Warningln logs to the WARNING log. Arguments are handled in the manner of fmt.Println.
func Warningln(args ...interface{}) {
logger.Warningln(args...)
}
// Error logs to the ERROR log.
func Error(args ...interface{}) {
logger.Error(args...)
}
// Errorf logs to the ERROR log. Arguments are handled in the manner of fmt.Printf.
func Errorf(format string, args ...interface{}) {
logger.Errorf(format, args...)
}
// Errorln logs to the ERROR log. Arguments are handled in the manner of fmt.Println.
func Errorln(args ...interface{}) {
logger.Errorln(args...)
}
// Fatal logs to the FATAL log. Arguments are handled in the manner of fmt.Print.
// It calls os.Exit() with exit code 1.
func Fatal(args ...interface{}) {
logger.Fatal(args...)
// Make sure fatal logs will exit.
os.Exit(1)
}
// Fatalf logs to the FATAL log. Arguments are handled in the manner of fmt.Printf.
// It calls os.Exit() with exit code 1.
func Fatalf(format string, args ...interface{}) {
logger.Fatalf(format, args...)
// Make sure fatal logs will exit.
os.Exit(1)
}
// Fatalln logs to the FATAL log. Arguments are handled in the manner of fmt.Println.
// It calle os.Exit()) with exit code 1.
func Fatalln(args ...interface{}) {
logger.Fatalln(args...)
// Make sure fatal logs will exit.
os.Exit(1)
}
// Print prints to the logger. Arguments are handled in the manner of fmt.Print.
//
// Deprecated: use Info.
func Print(args ...interface{}) {
logger.Info(args...)
}
// Printf prints to the logger. Arguments are handled in the manner of fmt.Printf.
//
// Deprecated: use Infof.
func Printf(format string, args ...interface{}) {
logger.Infof(format, args...)
}
// Println prints to the logger. Arguments are handled in the manner of fmt.Println.
//
// Deprecated: use Infoln.
func Println(args ...interface{}) {
logger.Infoln(args...)
}

View file

@ -1,85 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package grpclog
// Logger mimics golang's standard Logger as an interface.
//
// Deprecated: use LoggerV2.
type Logger interface {
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Fatalln(args ...interface{})
Print(args ...interface{})
Printf(format string, args ...interface{})
Println(args ...interface{})
}
// SetLogger sets the logger that is used in grpc. Call only from
// init() functions.
//
// Deprecated: use SetLoggerV2.
func SetLogger(l Logger) {
logger = &loggerWrapper{Logger: l}
}
// loggerWrapper wraps Logger into a LoggerV2.
type loggerWrapper struct {
Logger
}
func (g *loggerWrapper) Info(args ...interface{}) {
g.Logger.Print(args...)
}
func (g *loggerWrapper) Infoln(args ...interface{}) {
g.Logger.Println(args...)
}
func (g *loggerWrapper) Infof(format string, args ...interface{}) {
g.Logger.Printf(format, args...)
}
func (g *loggerWrapper) Warning(args ...interface{}) {
g.Logger.Print(args...)
}
func (g *loggerWrapper) Warningln(args ...interface{}) {
g.Logger.Println(args...)
}
func (g *loggerWrapper) Warningf(format string, args ...interface{}) {
g.Logger.Printf(format, args...)
}
func (g *loggerWrapper) Error(args ...interface{}) {
g.Logger.Print(args...)
}
func (g *loggerWrapper) Errorln(args ...interface{}) {
g.Logger.Println(args...)
}
func (g *loggerWrapper) Errorf(format string, args ...interface{}) {
g.Logger.Printf(format, args...)
}
func (g *loggerWrapper) V(l int) bool {
// Returns true for all verbose level.
return true
}

View file

@ -1,195 +0,0 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package grpclog
import (
"io"
"io/ioutil"
"log"
"os"
"strconv"
)
// LoggerV2 does underlying logging work for grpclog.
type LoggerV2 interface {
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
Info(args ...interface{})
// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
Infoln(args ...interface{})
// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
Infof(format string, args ...interface{})
// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
Warning(args ...interface{})
// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
Warningln(args ...interface{})
// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
Warningf(format string, args ...interface{})
// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
Error(args ...interface{})
// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
Errorln(args ...interface{})
// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
Errorf(format string, args ...interface{})
// Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
Fatal(args ...interface{})
// Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
Fatalln(args ...interface{})
// Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
Fatalf(format string, args ...interface{})
// V reports whether verbosity level l is at least the requested verbose level.
V(l int) bool
}
// SetLoggerV2 sets logger that is used in grpc to a V2 logger.
// Not mutex-protected, should be called before any gRPC functions.
func SetLoggerV2(l LoggerV2) {
logger = l
}
const (
// infoLog indicates Info severity.
infoLog int = iota
// warningLog indicates Warning severity.
warningLog
// errorLog indicates Error severity.
errorLog
// fatalLog indicates Fatal severity.
fatalLog
)
// severityName contains the string representation of each severity.
var severityName = []string{
infoLog: "INFO",
warningLog: "WARNING",
errorLog: "ERROR",
fatalLog: "FATAL",
}
// loggerT is the default logger used by grpclog.
type loggerT struct {
m []*log.Logger
v int
}
// NewLoggerV2 creates a loggerV2 with the provided writers.
// Fatal logs will be written to errorW, warningW, infoW, followed by exit(1).
// Error logs will be written to errorW, warningW and infoW.
// Warning logs will be written to warningW and infoW.
// Info logs will be written to infoW.
func NewLoggerV2(infoW, warningW, errorW io.Writer) LoggerV2 {
return NewLoggerV2WithVerbosity(infoW, warningW, errorW, 0)
}
// NewLoggerV2WithVerbosity creates a loggerV2 with the provided writers and
// verbosity level.
func NewLoggerV2WithVerbosity(infoW, warningW, errorW io.Writer, v int) LoggerV2 {
var m []*log.Logger
m = append(m, log.New(infoW, severityName[infoLog]+": ", log.LstdFlags))
m = append(m, log.New(io.MultiWriter(infoW, warningW), severityName[warningLog]+": ", log.LstdFlags))
ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal.
m = append(m, log.New(ew, severityName[errorLog]+": ", log.LstdFlags))
m = append(m, log.New(ew, severityName[fatalLog]+": ", log.LstdFlags))
return &loggerT{m: m, v: v}
}
// newLoggerV2 creates a loggerV2 to be used as default logger.
// All logs are written to stderr.
func newLoggerV2() LoggerV2 {
errorW := ioutil.Discard
warningW := ioutil.Discard
infoW := ioutil.Discard
logLevel := os.Getenv("GRPC_GO_LOG_SEVERITY_LEVEL")
switch logLevel {
case "", "ERROR", "error": // If env is unset, set level to ERROR.
errorW = os.Stderr
case "WARNING", "warning":
warningW = os.Stderr
case "INFO", "info":
infoW = os.Stderr
}
var v int
vLevel := os.Getenv("GRPC_GO_LOG_VERBOSITY_LEVEL")
if vl, err := strconv.Atoi(vLevel); err == nil {
v = vl
}
return NewLoggerV2WithVerbosity(infoW, warningW, errorW, v)
}
func (g *loggerT) Info(args ...interface{}) {
g.m[infoLog].Print(args...)
}
func (g *loggerT) Infoln(args ...interface{}) {
g.m[infoLog].Println(args...)
}
func (g *loggerT) Infof(format string, args ...interface{}) {
g.m[infoLog].Printf(format, args...)
}
func (g *loggerT) Warning(args ...interface{}) {
g.m[warningLog].Print(args...)
}
func (g *loggerT) Warningln(args ...interface{}) {
g.m[warningLog].Println(args...)
}
func (g *loggerT) Warningf(format string, args ...interface{}) {
g.m[warningLog].Printf(format, args...)
}
func (g *loggerT) Error(args ...interface{}) {
g.m[errorLog].Print(args...)
}
func (g *loggerT) Errorln(args ...interface{}) {
g.m[errorLog].Println(args...)
}
func (g *loggerT) Errorf(format string, args ...interface{}) {
g.m[errorLog].Printf(format, args...)
}
func (g *loggerT) Fatal(args ...interface{}) {
g.m[fatalLog].Fatal(args...)
// No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit().
}
func (g *loggerT) Fatalln(args ...interface{}) {
g.m[fatalLog].Fatalln(args...)
// No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit().
}
func (g *loggerT) Fatalf(format string, args ...interface{}) {
g.m[fatalLog].Fatalf(format, args...)
// No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit().
}
func (g *loggerT) V(l int) bool {
return l <= g.v
}

View file

@ -1,72 +0,0 @@
/*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package internal contains gRPC-internal code, to avoid polluting
// the godoc of the top-level grpc package. It must not import any grpc
// symbols to avoid circular dependencies.
package internal
import (
"context"
"time"
"google.golang.org/grpc/connectivity"
)
var (
// WithHealthCheckFunc is set by dialoptions.go
WithHealthCheckFunc interface{} // func (HealthChecker) DialOption
// HealthCheckFunc is used to provide client-side LB channel health checking
HealthCheckFunc HealthChecker
// BalancerUnregister is exported by package balancer to unregister a balancer.
BalancerUnregister func(name string)
// KeepaliveMinPingTime is the minimum ping interval. This must be 10s by
// default, but tests may wish to set it lower for convenience.
KeepaliveMinPingTime = 10 * time.Second
// StatusRawProto is exported by status/status.go. This func returns a
// pointer to the wrapped Status proto for a given status.Status without a
// call to proto.Clone(). The returned Status proto should not be mutated by
// the caller.
StatusRawProto interface{} // func (*status.Status) *spb.Status
// NewRequestInfoContext creates a new context based on the argument context attaching
// the passed in RequestInfo to the new context.
NewRequestInfoContext interface{} // func(context.Context, credentials.RequestInfo) context.Context
// ParseServiceConfigForTesting is for creating a fake
// ClientConn for resolver testing only
ParseServiceConfigForTesting interface{} // func(string) *serviceconfig.ParseResult
)
// HealthChecker defines the signature of the client-side LB channel health checking function.
//
// The implementation is expected to create a health checking RPC stream by
// calling newStream(), watch for the health status of serviceName, and report
// it's health back by calling setConnectivityState().
//
// The health checking protocol is defined at:
// https://github.com/grpc/grpc/blob/master/doc/health-checking.md
type HealthChecker func(ctx context.Context, newStream func(string) (interface{}, error), setConnectivityState func(connectivity.State, error), serviceName string) error
const (
// CredsBundleModeFallback switches GoogleDefaultCreds to fallback mode.
CredsBundleModeFallback = "fallback"
// CredsBundleModeBalancer switches GoogleDefaultCreds to grpclb balancer
// mode.
CredsBundleModeBalancer = "balancer"
// CredsBundleModeBackendFromBalancer switches GoogleDefaultCreds to mode
// that supports backend returned by grpclb balancer.
CredsBundleModeBackendFromBalancer = "backend-from-balancer"
)

162
vendor/google.golang.org/grpc/internal/status/status.go generated vendored Normal file
View file

@ -0,0 +1,162 @@
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package status implements errors returned by gRPC. These errors are
// serialized and transmitted on the wire between server and client, and allow
// for additional data to be transmitted via the Details field in the status
// proto. gRPC service handlers should return an error created by this
// package, and gRPC clients should expect a corresponding error to be
// returned from the RPC call.
//
// This package upholds the invariants that a non-nil error may not
// contain an OK code, and an OK code must result in a nil error.
package status
import (
"errors"
"fmt"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
)
// Status represents an RPC status code, message, and details. It is immutable
// and should be created with New, Newf, or FromProto.
type Status struct {
s *spb.Status
}
// New returns a Status representing c and msg.
func New(c codes.Code, msg string) *Status {
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
}
// Newf returns New(c, fmt.Sprintf(format, a...)).
func Newf(c codes.Code, format string, a ...interface{}) *Status {
return New(c, fmt.Sprintf(format, a...))
}
// FromProto returns a Status representing s.
func FromProto(s *spb.Status) *Status {
return &Status{s: proto.Clone(s).(*spb.Status)}
}
// Err returns an error representing c and msg. If c is OK, returns nil.
func Err(c codes.Code, msg string) error {
return New(c, msg).Err()
}
// Errorf returns Error(c, fmt.Sprintf(format, a...)).
func Errorf(c codes.Code, format string, a ...interface{}) error {
return Err(c, fmt.Sprintf(format, a...))
}
// Code returns the status code contained in s.
func (s *Status) Code() codes.Code {
if s == nil || s.s == nil {
return codes.OK
}
return codes.Code(s.s.Code)
}
// Message returns the message contained in s.
func (s *Status) Message() string {
if s == nil || s.s == nil {
return ""
}
return s.s.Message
}
// Proto returns s's status as an spb.Status proto message.
func (s *Status) Proto() *spb.Status {
if s == nil {
return nil
}
return proto.Clone(s.s).(*spb.Status)
}
// Err returns an immutable error representing s; returns nil if s.Code() is OK.
func (s *Status) Err() error {
if s.Code() == codes.OK {
return nil
}
return &Error{e: s.Proto()}
}
// WithDetails returns a new status with the provided details messages appended to the status.
// If any errors are encountered, it returns nil and the first error encountered.
func (s *Status) WithDetails(details ...proto.Message) (*Status, error) {
if s.Code() == codes.OK {
return nil, errors.New("no error details for status with code OK")
}
// s.Code() != OK implies that s.Proto() != nil.
p := s.Proto()
for _, detail := range details {
any, err := ptypes.MarshalAny(detail)
if err != nil {
return nil, err
}
p.Details = append(p.Details, any)
}
return &Status{s: p}, nil
}
// Details returns a slice of details messages attached to the status.
// If a detail cannot be decoded, the error is returned in place of the detail.
func (s *Status) Details() []interface{} {
if s == nil || s.s == nil {
return nil
}
details := make([]interface{}, 0, len(s.s.Details))
for _, any := range s.s.Details {
detail := &ptypes.DynamicAny{}
if err := ptypes.UnmarshalAny(any, detail); err != nil {
details = append(details, err)
continue
}
details = append(details, detail.Message)
}
return details
}
// Error wraps a pointer of a status proto. It implements error and Status,
// and a nil *Error should never be returned by this package.
type Error struct {
e *spb.Status
}
func (e *Error) Error() string {
return fmt.Sprintf("rpc error: code = %s desc = %s", codes.Code(e.e.GetCode()), e.e.GetMessage())
}
// GRPCStatus returns the Status represented by se.
func (e *Error) GRPCStatus() *Status {
return FromProto(e.e)
}
// Is implements future error.Is functionality.
// A Error is equivalent if the code and message are identical.
func (e *Error) Is(target error) bool {
tse, ok := target.(*Error)
if !ok {
return false
}
return proto.Equal(e.e, tse.e)
}

View file

@ -29,88 +29,23 @@ package status
import (
"context"
"errors"
"fmt"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/status"
)
func init() {
internal.StatusRawProto = statusRawProto
}
func statusRawProto(s *Status) *spb.Status { return s.s }
// statusError is an alias of a status proto. It implements error and Status,
// and a nil statusError should never be returned by this package.
type statusError spb.Status
func (se *statusError) Error() string {
p := (*spb.Status)(se)
return fmt.Sprintf("rpc error: code = %s desc = %s", codes.Code(p.GetCode()), p.GetMessage())
}
func (se *statusError) GRPCStatus() *Status {
return &Status{s: (*spb.Status)(se)}
}
// Is implements future error.Is functionality.
// A statusError is equivalent if the code and message are identical.
func (se *statusError) Is(target error) bool {
tse, ok := target.(*statusError)
if !ok {
return false
}
return proto.Equal((*spb.Status)(se), (*spb.Status)(tse))
}
// Status represents an RPC status code, message, and details. It is immutable
// and should be created with New, Newf, or FromProto.
type Status struct {
s *spb.Status
}
// Code returns the status code contained in s.
func (s *Status) Code() codes.Code {
if s == nil || s.s == nil {
return codes.OK
}
return codes.Code(s.s.Code)
}
// Message returns the message contained in s.
func (s *Status) Message() string {
if s == nil || s.s == nil {
return ""
}
return s.s.Message
}
// Proto returns s's status as an spb.Status proto message.
func (s *Status) Proto() *spb.Status {
if s == nil {
return nil
}
return proto.Clone(s.s).(*spb.Status)
}
// Err returns an immutable error representing s; returns nil if s.Code() is
// OK.
func (s *Status) Err() error {
if s.Code() == codes.OK {
return nil
}
return (*statusError)(s.s)
}
// Status references google.golang.org/grpc/internal/status. It represents an
// RPC status code, message, and details. It is immutable and should be
// created with New, Newf, or FromProto.
// https://godoc.org/google.golang.org/grpc/internal/status
type Status = status.Status
// New returns a Status representing c and msg.
func New(c codes.Code, msg string) *Status {
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
return status.New(c, msg)
}
// Newf returns New(c, fmt.Sprintf(format, a...)).
@ -135,12 +70,14 @@ func ErrorProto(s *spb.Status) error {
// FromProto returns a Status representing s.
func FromProto(s *spb.Status) *Status {
return &Status{s: proto.Clone(s).(*spb.Status)}
return status.FromProto(s)
}
// FromError returns a Status representing err if it was produced from this
// package or has a method `GRPCStatus() *Status`. Otherwise, ok is false and a
// Status is returned with codes.Unknown and the original error message.
// FromError returns a Status representing err if it was produced by this
// package or has a method `GRPCStatus() *Status`.
// If err is nil, a Status is returned with codes.OK and no message.
// Otherwise, ok is false and a Status is returned with codes.Unknown and
// the original error message.
func FromError(err error) (s *Status, ok bool) {
if err == nil {
return nil, true
@ -160,42 +97,6 @@ func Convert(err error) *Status {
return s
}
// WithDetails returns a new status with the provided details messages appended to the status.
// If any errors are encountered, it returns nil and the first error encountered.
func (s *Status) WithDetails(details ...proto.Message) (*Status, error) {
if s.Code() == codes.OK {
return nil, errors.New("no error details for status with code OK")
}
// s.Code() != OK implies that s.Proto() != nil.
p := s.Proto()
for _, detail := range details {
any, err := ptypes.MarshalAny(detail)
if err != nil {
return nil, err
}
p.Details = append(p.Details, any)
}
return &Status{s: p}, nil
}
// Details returns a slice of details messages attached to the status.
// If a detail cannot be decoded, the error is returned in place of the detail.
func (s *Status) Details() []interface{} {
if s == nil || s.s == nil {
return nil
}
details := make([]interface{}, 0, len(s.s.Details))
for _, any := range s.s.Details {
detail := &ptypes.DynamicAny{}
if err := ptypes.UnmarshalAny(any, detail); err != nil {
details = append(details, err)
continue
}
details = append(details, detail.Message)
}
return details
}
// Code returns the Code of the error if it is a Status error, codes.OK if err
// is nil, or codes.Unknown otherwise.
func Code(err error) codes.Code {

View file

@ -6,7 +6,6 @@ package prototext
import (
"fmt"
"strings"
"unicode/utf8"
"google.golang.org/protobuf/internal/encoding/messageset"
@ -23,6 +22,7 @@ import (
)
// Unmarshal reads the given []byte into the given proto.Message.
// The provided message must be mutable (e.g., a non-nil pointer to a message).
func Unmarshal(b []byte, m proto.Message) error {
return UnmarshalOptions{}.Unmarshal(b, m)
}
@ -51,8 +51,9 @@ type UnmarshalOptions struct {
}
}
// Unmarshal reads the given []byte and populates the given proto.Message using options in
// UnmarshalOptions object.
// Unmarshal reads the given []byte and populates the given proto.Message
// using options in the UnmarshalOptions object.
// The provided message must be mutable (e.g., a non-nil pointer to a message).
func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
return o.unmarshal(b, m)
}
@ -158,21 +159,11 @@ func (d decoder) unmarshalMessage(m pref.Message, checkDelims bool) error {
switch tok.NameKind() {
case text.IdentName:
name = pref.Name(tok.IdentName())
fd = fieldDescs.ByName(name)
if fd == nil {
// The proto name of a group field is in all lowercase,
// while the textproto field name is the group message name.
gd := fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
if gd != nil && gd.Kind() == pref.GroupKind && gd.Message().Name() == name {
fd = gd
}
} else if fd.Kind() == pref.GroupKind && fd.Message().Name() != name {
fd = nil // reset since field name is actually the message name
}
fd = fieldDescs.ByTextName(string(name))
case text.TypeName:
// Handle extensions only. This code path is not for Any.
xt, xtErr = d.findExtension(pref.FullName(tok.TypeName()))
xt, xtErr = d.opts.Resolver.FindExtensionByName(pref.FullName(tok.TypeName()))
case text.FieldNumber:
isFieldNumberName = true
@ -269,15 +260,6 @@ func (d decoder) unmarshalMessage(m pref.Message, checkDelims bool) error {
return nil
}
// 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)
}
// unmarshalSingular unmarshals a non-repeated field value specified by the
// given FieldDescriptor.
func (d decoder) unmarshalSingular(fd pref.FieldDescriptor, m pref.Message) error {
@ -762,9 +744,6 @@ func (d decoder) skipValue() error {
// Skip items. This will not validate whether skipped values are
// of the same type or not, same behavior as C++
// TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
if err := d.skipValue(); err != nil {
return err
}
}
}
}

View file

@ -6,7 +6,6 @@ package prototext
import (
"fmt"
"sort"
"strconv"
"unicode/utf8"
@ -16,10 +15,11 @@ import (
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/mapsort"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
@ -169,35 +169,15 @@ func (e encoder) marshalMessage(m pref.Message, inclDelims bool) error {
// If unable to expand, continue on to marshal Any as a regular message.
}
// Marshal known fields.
fieldDescs := messageDesc.Fields()
size := fieldDescs.Len()
for i := 0; i < size; {
fd := fieldDescs.Get(i)
if od := fd.ContainingOneof(); od != nil {
fd = m.WhichOneof(od)
i += od.Fields().Len()
} else {
i++
// Marshal fields.
var err error
order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if err = e.marshalField(fd.TextName(), v, fd); err != nil {
return false
}
if fd == nil || !m.Has(fd) {
continue
}
name := fd.Name()
// Use type name for group field name.
if fd.Kind() == pref.GroupKind {
name = fd.Message().Name()
}
val := m.Get(fd)
if err := e.marshalField(string(name), val, fd); err != nil {
return err
}
}
// Marshal extensions.
if err := e.marshalExtensions(m); err != nil {
return true
})
if err != nil {
return err
}
@ -290,7 +270,7 @@ func (e encoder) marshalList(name string, list pref.List, fd pref.FieldDescripto
// marshalMap marshals the given protoreflect.Map as multiple name-value fields.
func (e encoder) marshalMap(name string, mmap pref.Map, fd pref.FieldDescriptor) error {
var err error
mapsort.Range(mmap, fd.MapKey().Kind(), func(key pref.MapKey, val pref.Value) bool {
order.RangeEntries(mmap, order.GenericKeyOrder, func(key pref.MapKey, val pref.Value) bool {
e.WriteName(name)
e.StartMessage()
defer e.EndMessage()
@ -311,48 +291,6 @@ func (e encoder) marshalMap(name string, mmap pref.Map, fd pref.FieldDescriptor)
return err
}
// 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()
}
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 {
// Extension field name is the proto field name enclosed in [].
name := "[" + entry.key + "]"
if err := e.marshalField(name, entry.value, entry.desc); err != nil {
return err
}
}
return nil
}
// marshalUnknown parses the given []byte and marshals fields out.
// This function assumes proper encoding in the given []byte.
func (e encoder) marshalUnknown(b []byte) {

View file

@ -42,6 +42,8 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string {
name = "FileImports"
case pref.Descriptor:
name = reflect.ValueOf(vs).MethodByName("Get").Type().Out(0).Name() + "s"
default:
name = reflect.ValueOf(vs).Elem().Type().Name()
}
start, end = name+"{", "}"
}

View file

@ -26,6 +26,14 @@ func Bool() bool {
return randSeed%2 == 1
}
// Intn returns a deterministically random integer between 0 and n-1, inclusive.
func Intn(n int) int {
if n <= 0 {
panic("must be positive")
}
return int(randSeed % uint64(n))
}
// randSeed is a best-effort at an approximate hash of the Go binary.
var randSeed = binaryHash()

View file

@ -11,10 +11,9 @@ import (
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
pref "google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
)
// The MessageSet wire format is equivalent to a message defiend as follows,
// The MessageSet wire format is equivalent to a message defined as follows,
// where each Item defines an extension field with a field number of 'type_id'
// and content of 'message'. MessageSet extensions must be non-repeated message
// fields.
@ -48,33 +47,17 @@ func IsMessageSet(md pref.MessageDescriptor) bool {
return ok && xmd.IsMessageSet()
}
// IsMessageSetExtension reports this field extends a MessageSet.
// IsMessageSetExtension reports this field properly extends a MessageSet.
func IsMessageSetExtension(fd pref.FieldDescriptor) bool {
if fd.Name() != ExtensionName {
switch {
case fd.Name() != ExtensionName:
return false
case !IsMessageSet(fd.ContainingMessage()):
return false
case fd.FullName().Parent() != fd.Message().FullName():
return false
}
if fd.FullName().Parent() != fd.Message().FullName() {
return false
}
return IsMessageSet(fd.ContainingMessage())
}
// FindMessageSetExtension locates a MessageSet extension field by name.
// In text and JSON formats, the extension name used is the message itself.
// The extension field name is derived by appending ExtensionName.
func FindMessageSetExtension(r preg.ExtensionTypeResolver, s pref.FullName) (pref.ExtensionType, error) {
name := s.Append(ExtensionName)
xt, err := r.FindExtensionByName(name)
if err != nil {
if err == preg.NotFound {
return nil, err
}
return nil, errors.Wrap(err, "%q", name)
}
if !IsMessageSetExtension(xt.TypeDescriptor()) {
return nil, preg.NotFound
}
return xt, nil
return true
}
// SizeField returns the size of a MessageSet item field containing an extension

View file

@ -104,7 +104,7 @@ func Unmarshal(tag string, goType reflect.Type, evs pref.EnumValueDescriptors) p
case strings.HasPrefix(s, "json="):
jsonName := s[len("json="):]
if jsonName != strs.JSONCamelCase(string(f.L0.FullName.Name())) {
f.L1.JSONName.Init(jsonName)
f.L1.StringName.InitJSON(jsonName)
}
case s == "packed":
f.L1.HasPacked = true

View file

@ -32,7 +32,6 @@ type Encoder struct {
encoderState
indent string
newline string // set to "\n" if len(indent) > 0
delims [2]byte
outputASCII bool
}
@ -61,7 +60,6 @@ func NewEncoder(indent string, delims [2]byte, outputASCII bool) (*Encoder, erro
return nil, errors.New("indent may only be composed of space and tab characters")
}
e.indent = indent
e.newline = "\n"
}
switch delims {
case [2]byte{0, 0}:
@ -126,7 +124,7 @@ func appendString(out []byte, in string, outputASCII bool) []byte {
// are used to represent both the proto string and bytes type.
r = rune(in[0])
fallthrough
case r < ' ' || r == '"' || r == '\\':
case r < ' ' || r == '"' || r == '\\' || r == 0x7f:
out = append(out, '\\')
switch r {
case '"', '\\':
@ -143,7 +141,7 @@ func appendString(out []byte, in string, outputASCII bool) []byte {
out = strconv.AppendUint(out, uint64(r), 16)
}
in = in[n:]
case outputASCII && r >= utf8.RuneSelf:
case r >= utf8.RuneSelf && (outputASCII || r <= 0x009f):
out = append(out, '\\')
if r <= math.MaxUint16 {
out = append(out, 'u')
@ -168,7 +166,7 @@ func appendString(out []byte, in string, outputASCII bool) []byte {
// escaping. If no characters need escaping, this returns the input length.
func indexNeedEscapeInString(s string) int {
for i := 0; i < len(s); i++ {
if c := s[i]; c < ' ' || c == '"' || c == '\'' || c == '\\' || c >= utf8.RuneSelf {
if c := s[i]; c < ' ' || c == '"' || c == '\'' || c == '\\' || c >= 0x7f {
return i
}
}
@ -265,3 +263,8 @@ func (e *Encoder) Snapshot() encoderState {
func (e *Encoder) Reset(es encoderState) {
e.encoderState = es
}
// AppendString appends the escaped form of the input string to b.
func AppendString(b []byte, s string) []byte {
return appendString(b, s, false)
}

View file

@ -1,40 +0,0 @@
// 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 fieldsort defines an ordering of fields.
//
// The ordering defined by this package matches the historic behavior of the proto
// package, placing extensions first and oneofs last.
//
// There is no guarantee about stability of the wire encoding, and users should not
// depend on the order defined in this package as it is subject to change without
// notice.
package fieldsort
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// Less returns true if field a comes before field j in ordered wire marshal output.
func Less(a, b protoreflect.FieldDescriptor) bool {
ea := a.IsExtension()
eb := b.IsExtension()
oa := a.ContainingOneof()
ob := b.ContainingOneof()
switch {
case ea != eb:
return ea
case oa != nil && ob != nil:
if oa == ob {
return a.Number() < b.Number()
}
return oa.Index() < ob.Index()
case oa != nil && !oa.IsSynthetic():
return false
case ob != nil && !ob.IsSynthetic():
return true
default:
return a.Number() < b.Number()
}
}

View file

@ -3,6 +3,9 @@
// license that can be found in the LICENSE file.
// Package filedesc provides functionality for constructing descriptors.
//
// The types in this package implement interfaces in the protoreflect package
// related to protobuf descripriptors.
package filedesc
import (

View file

@ -13,6 +13,7 @@ import (
"google.golang.org/protobuf/internal/descfmt"
"google.golang.org/protobuf/internal/descopts"
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/strs"
@ -99,15 +100,6 @@ func (fd *File) lazyInitOnce() {
fd.mu.Unlock()
}
// ProtoLegacyRawDesc is a pseudo-internal API for allowing the v1 code
// to be able to retrieve the raw descriptor.
//
// WARNING: This method is exempt from the compatibility promise and may be
// removed in the future without warning.
func (fd *File) ProtoLegacyRawDesc() []byte {
return fd.builder.RawDescriptor
}
// GoPackagePath is a pseudo-internal API for determining the Go package path
// that this file descriptor is declared in.
//
@ -207,7 +199,7 @@ type (
Number pref.FieldNumber
Cardinality pref.Cardinality // must be consistent with Message.RequiredNumbers
Kind pref.Kind
JSONName jsonName
StringName stringName
IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
IsWeak bool // promoted from google.protobuf.FieldOptions
HasPacked bool // promoted from google.protobuf.FieldOptions
@ -277,8 +269,9 @@ func (fd *Field) Options() pref.ProtoMessage {
func (fd *Field) Number() pref.FieldNumber { return fd.L1.Number }
func (fd *Field) Cardinality() pref.Cardinality { return fd.L1.Cardinality }
func (fd *Field) Kind() pref.Kind { return fd.L1.Kind }
func (fd *Field) HasJSONName() bool { return fd.L1.JSONName.has }
func (fd *Field) JSONName() string { return fd.L1.JSONName.get(fd) }
func (fd *Field) HasJSONName() bool { return fd.L1.StringName.hasJSON }
func (fd *Field) JSONName() string { return fd.L1.StringName.getJSON(fd) }
func (fd *Field) TextName() string { return fd.L1.StringName.getText(fd) }
func (fd *Field) HasPresence() bool {
return fd.L1.Cardinality != pref.Repeated && (fd.L0.ParentFile.L1.Syntax == pref.Proto2 || fd.L1.Message != nil || fd.L1.ContainingOneof != nil)
}
@ -373,7 +366,7 @@ type (
}
ExtensionL2 struct {
Options func() pref.ProtoMessage
JSONName jsonName
StringName stringName
IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
IsPacked bool // promoted from google.protobuf.FieldOptions
Default defaultValue
@ -391,8 +384,9 @@ func (xd *Extension) Options() pref.ProtoMessage {
func (xd *Extension) Number() pref.FieldNumber { return xd.L1.Number }
func (xd *Extension) Cardinality() pref.Cardinality { return xd.L1.Cardinality }
func (xd *Extension) Kind() pref.Kind { return xd.L1.Kind }
func (xd *Extension) HasJSONName() bool { return xd.lazyInit().JSONName.has }
func (xd *Extension) JSONName() string { return xd.lazyInit().JSONName.get(xd) }
func (xd *Extension) HasJSONName() bool { return xd.lazyInit().StringName.hasJSON }
func (xd *Extension) JSONName() string { return xd.lazyInit().StringName.getJSON(xd) }
func (xd *Extension) TextName() string { return xd.lazyInit().StringName.getText(xd) }
func (xd *Extension) HasPresence() bool { return xd.L1.Cardinality != pref.Repeated }
func (xd *Extension) HasOptionalKeyword() bool {
return (xd.L0.ParentFile.L1.Syntax == pref.Proto2 && xd.L1.Cardinality == pref.Optional) || xd.lazyInit().IsProto3Optional
@ -506,27 +500,50 @@ func (d *Base) Syntax() pref.Syntax { return d.L0.ParentFile.Syn
func (d *Base) IsPlaceholder() bool { return false }
func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
type jsonName struct {
has bool
once sync.Once
name string
type stringName struct {
hasJSON bool
once sync.Once
nameJSON string
nameText string
}
// Init initializes the name. It is exported for use by other internal packages.
func (js *jsonName) Init(s string) {
js.has = true
js.name = s
// InitJSON initializes the name. It is exported for use by other internal packages.
func (s *stringName) InitJSON(name string) {
s.hasJSON = true
s.nameJSON = name
}
func (js *jsonName) get(fd pref.FieldDescriptor) string {
if !js.has {
js.once.Do(func() {
js.name = strs.JSONCamelCase(string(fd.Name()))
})
}
return js.name
func (s *stringName) lazyInit(fd pref.FieldDescriptor) *stringName {
s.once.Do(func() {
if fd.IsExtension() {
// For extensions, JSON and text are formatted the same way.
var name string
if messageset.IsMessageSetExtension(fd) {
name = string("[" + fd.FullName().Parent() + "]")
} else {
name = string("[" + fd.FullName() + "]")
}
s.nameJSON = name
s.nameText = name
} else {
// Format the JSON name.
if !s.hasJSON {
s.nameJSON = strs.JSONCamelCase(string(fd.Name()))
}
// Format the text name.
s.nameText = string(fd.Name())
if fd.Kind() == pref.GroupKind {
s.nameText = string(fd.Message().Name())
}
}
})
return s
}
func (s *stringName) getJSON(fd pref.FieldDescriptor) string { return s.lazyInit(fd).nameJSON }
func (s *stringName) getText(fd pref.FieldDescriptor) string { return s.lazyInit(fd).nameText }
func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue {
dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
if b, ok := v.Interface().([]byte); ok {

View file

@ -451,7 +451,7 @@ func (fd *Field) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Des
case genid.FieldDescriptorProto_Name_field_number:
fd.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.FieldDescriptorProto_JsonName_field_number:
fd.L1.JSONName.Init(sb.MakeString(v))
fd.L1.StringName.InitJSON(sb.MakeString(v))
case genid.FieldDescriptorProto_DefaultValue_field_number:
fd.L1.Default.val = pref.ValueOfBytes(v) // temporarily store as bytes; later resolved in resolveMessages
case genid.FieldDescriptorProto_TypeName_field_number:
@ -551,7 +551,7 @@ func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) {
b = b[m:]
switch num {
case genid.FieldDescriptorProto_JsonName_field_number:
xd.L2.JSONName.Init(sb.MakeString(v))
xd.L2.StringName.InitJSON(sb.MakeString(v))
case genid.FieldDescriptorProto_DefaultValue_field_number:
xd.L2.Default.val = pref.ValueOfBytes(v) // temporarily store as bytes; later resolved in resolveExtensions
case genid.FieldDescriptorProto_TypeName_field_number:

View file

@ -6,9 +6,12 @@ package filedesc
import (
"fmt"
"math"
"sort"
"sync"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/descfmt"
"google.golang.org/protobuf/internal/errors"
@ -245,6 +248,7 @@ type OneofFields struct {
once sync.Once
byName map[pref.Name]pref.FieldDescriptor // protected by once
byJSON map[string]pref.FieldDescriptor // protected by once
byText map[string]pref.FieldDescriptor // protected by once
byNum map[pref.FieldNumber]pref.FieldDescriptor // protected by once
}
@ -252,6 +256,7 @@ func (p *OneofFields) Len() int { return
func (p *OneofFields) Get(i int) pref.FieldDescriptor { return p.List[i] }
func (p *OneofFields) ByName(s pref.Name) pref.FieldDescriptor { return p.lazyInit().byName[s] }
func (p *OneofFields) ByJSONName(s string) pref.FieldDescriptor { return p.lazyInit().byJSON[s] }
func (p *OneofFields) ByTextName(s string) pref.FieldDescriptor { return p.lazyInit().byText[s] }
func (p *OneofFields) ByNumber(n pref.FieldNumber) pref.FieldDescriptor { return p.lazyInit().byNum[n] }
func (p *OneofFields) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *OneofFields) ProtoInternal(pragma.DoNotImplement) {}
@ -261,11 +266,13 @@ func (p *OneofFields) lazyInit() *OneofFields {
if len(p.List) > 0 {
p.byName = make(map[pref.Name]pref.FieldDescriptor, len(p.List))
p.byJSON = make(map[string]pref.FieldDescriptor, len(p.List))
p.byText = make(map[string]pref.FieldDescriptor, len(p.List))
p.byNum = make(map[pref.FieldNumber]pref.FieldDescriptor, len(p.List))
for _, f := range p.List {
// Field names and numbers are guaranteed to be unique.
p.byName[f.Name()] = f
p.byJSON[f.JSONName()] = f
p.byText[f.TextName()] = f
p.byNum[f.Number()] = f
}
}
@ -274,9 +281,170 @@ func (p *OneofFields) lazyInit() *OneofFields {
}
type SourceLocations struct {
// List is a list of SourceLocations.
// The SourceLocation.Next field does not need to be populated
// as it will be lazily populated upon first need.
List []pref.SourceLocation
// File is the parent file descriptor that these locations are relative to.
// If non-nil, ByDescriptor verifies that the provided descriptor
// is a child of this file descriptor.
File pref.FileDescriptor
once sync.Once
byPath map[pathKey]int
}
func (p *SourceLocations) Len() int { return len(p.List) }
func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.List[i] }
func (p *SourceLocations) Len() int { return len(p.List) }
func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.lazyInit().List[i] }
func (p *SourceLocations) byKey(k pathKey) pref.SourceLocation {
if i, ok := p.lazyInit().byPath[k]; ok {
return p.List[i]
}
return pref.SourceLocation{}
}
func (p *SourceLocations) ByPath(path pref.SourcePath) pref.SourceLocation {
return p.byKey(newPathKey(path))
}
func (p *SourceLocations) ByDescriptor(desc pref.Descriptor) pref.SourceLocation {
if p.File != nil && desc != nil && p.File != desc.ParentFile() {
return pref.SourceLocation{} // mismatching parent files
}
var pathArr [16]int32
path := pathArr[:0]
for {
switch desc.(type) {
case pref.FileDescriptor:
// Reverse the path since it was constructed in reverse.
for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
path[i], path[j] = path[j], path[i]
}
return p.byKey(newPathKey(path))
case pref.MessageDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.FileDescriptor:
path = append(path, int32(genid.FileDescriptorProto_MessageType_field_number))
case pref.MessageDescriptor:
path = append(path, int32(genid.DescriptorProto_NestedType_field_number))
default:
return pref.SourceLocation{}
}
case pref.FieldDescriptor:
isExtension := desc.(pref.FieldDescriptor).IsExtension()
path = append(path, int32(desc.Index()))
desc = desc.Parent()
if isExtension {
switch desc.(type) {
case pref.FileDescriptor:
path = append(path, int32(genid.FileDescriptorProto_Extension_field_number))
case pref.MessageDescriptor:
path = append(path, int32(genid.DescriptorProto_Extension_field_number))
default:
return pref.SourceLocation{}
}
} else {
switch desc.(type) {
case pref.MessageDescriptor:
path = append(path, int32(genid.DescriptorProto_Field_field_number))
default:
return pref.SourceLocation{}
}
}
case pref.OneofDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.MessageDescriptor:
path = append(path, int32(genid.DescriptorProto_OneofDecl_field_number))
default:
return pref.SourceLocation{}
}
case pref.EnumDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.FileDescriptor:
path = append(path, int32(genid.FileDescriptorProto_EnumType_field_number))
case pref.MessageDescriptor:
path = append(path, int32(genid.DescriptorProto_EnumType_field_number))
default:
return pref.SourceLocation{}
}
case pref.EnumValueDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.EnumDescriptor:
path = append(path, int32(genid.EnumDescriptorProto_Value_field_number))
default:
return pref.SourceLocation{}
}
case pref.ServiceDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.FileDescriptor:
path = append(path, int32(genid.FileDescriptorProto_Service_field_number))
default:
return pref.SourceLocation{}
}
case pref.MethodDescriptor:
path = append(path, int32(desc.Index()))
desc = desc.Parent()
switch desc.(type) {
case pref.ServiceDescriptor:
path = append(path, int32(genid.ServiceDescriptorProto_Method_field_number))
default:
return pref.SourceLocation{}
}
default:
return pref.SourceLocation{}
}
}
}
func (p *SourceLocations) lazyInit() *SourceLocations {
p.once.Do(func() {
if len(p.List) > 0 {
// Collect all the indexes for a given path.
pathIdxs := make(map[pathKey][]int, len(p.List))
for i, l := range p.List {
k := newPathKey(l.Path)
pathIdxs[k] = append(pathIdxs[k], i)
}
// Update the next index for all locations.
p.byPath = make(map[pathKey]int, len(p.List))
for k, idxs := range pathIdxs {
for i := 0; i < len(idxs)-1; i++ {
p.List[idxs[i]].Next = idxs[i+1]
}
p.List[idxs[len(idxs)-1]].Next = 0
p.byPath[k] = idxs[0] // record the first location for this path
}
}
})
return p
}
func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}
// pathKey is a comparable representation of protoreflect.SourcePath.
type pathKey struct {
arr [16]uint8 // first n-1 path segments; last element is the length
str string // used if the path does not fit in arr
}
func newPathKey(p pref.SourcePath) (k pathKey) {
if len(p) < len(k.arr) {
for i, ps := range p {
if ps < 0 || math.MaxUint8 <= ps {
return pathKey{str: p.String()}
}
k.arr[i] = uint8(ps)
}
k.arr[len(k.arr)-1] = uint8(len(p))
return k
}
return pathKey{str: p.String()}
}

View file

@ -142,6 +142,7 @@ type Fields struct {
once sync.Once
byName map[protoreflect.Name]*Field // protected by once
byJSON map[string]*Field // protected by once
byText map[string]*Field // protected by once
byNum map[protoreflect.FieldNumber]*Field // protected by once
}
@ -163,6 +164,12 @@ func (p *Fields) ByJSONName(s string) protoreflect.FieldDescriptor {
}
return nil
}
func (p *Fields) ByTextName(s string) protoreflect.FieldDescriptor {
if d := p.lazyInit().byText[s]; d != nil {
return d
}
return nil
}
func (p *Fields) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {
if d := p.lazyInit().byNum[n]; d != nil {
return d
@ -178,6 +185,7 @@ func (p *Fields) lazyInit() *Fields {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Field, len(p.List))
p.byJSON = make(map[string]*Field, len(p.List))
p.byText = make(map[string]*Field, len(p.List))
p.byNum = make(map[protoreflect.FieldNumber]*Field, len(p.List))
for i := range p.List {
d := &p.List[i]
@ -187,6 +195,9 @@ func (p *Fields) lazyInit() *Fields {
if _, ok := p.byJSON[d.JSONName()]; !ok {
p.byJSON[d.JSONName()] = d
}
if _, ok := p.byText[d.TextName()]; !ok {
p.byText[d.TextName()] = d
}
if _, ok := p.byNum[d.Number()]; !ok {
p.byNum[d.Number()] = d
}

View file

@ -167,7 +167,7 @@ func (Export) MessageTypeOf(m message) pref.MessageType {
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect().Type()
}
return legacyLoadMessageInfo(reflect.TypeOf(m), "")
return legacyLoadMessageType(reflect.TypeOf(m), "")
}
// MessageStringOf returns the message value as a string,

View file

@ -10,6 +10,7 @@ import (
"sync"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
@ -20,6 +21,7 @@ type errInvalidUTF8 struct{}
func (errInvalidUTF8) Error() string { return "string field contains invalid UTF-8" }
func (errInvalidUTF8) InvalidUTF8() bool { return true }
func (errInvalidUTF8) Unwrap() error { return errors.Error }
// initOneofFieldCoders initializes the fast-path functions for the fields in a oneof.
//
@ -242,7 +244,7 @@ func consumeMessageInfo(b []byte, p pointer, wtyp protowire.Type, f *coderFieldI
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
if p.Elem().IsNil() {
p.SetPointer(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())))
@ -276,7 +278,7 @@ func consumeMessage(b []byte, m proto.Message, wtyp protowire.Type, opts unmarsh
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: v,
@ -420,7 +422,7 @@ func consumeGroup(b []byte, m proto.Message, num protowire.Number, wtyp protowir
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: b,
@ -494,7 +496,7 @@ func consumeMessageSliceInfo(b []byte, p pointer, wtyp protowire.Type, f *coderF
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
m := reflect.New(f.mi.GoReflectType.Elem()).Interface()
mp := pointerOfIface(m)
@ -550,7 +552,7 @@ func consumeMessageSlice(b []byte, p pointer, goType reflect.Type, wtyp protowir
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
mp := reflect.New(goType.Elem())
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
@ -613,7 +615,7 @@ func consumeMessageSliceValue(b []byte, listv pref.Value, _ protowire.Number, wt
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return pref.Value{}, out, protowire.ParseError(n)
return pref.Value{}, out, errDecode
}
m := list.NewElement()
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
@ -681,7 +683,7 @@ func consumeGroupSliceValue(b []byte, listv pref.Value, num protowire.Number, wt
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return pref.Value{}, out, protowire.ParseError(n)
return pref.Value{}, out, errDecode
}
m := list.NewElement()
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
@ -767,7 +769,7 @@ func consumeGroupSlice(b []byte, p pointer, num protowire.Number, wtyp protowire
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
mp := reflect.New(goType.Elem())
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@
package impl
import (
"errors"
"reflect"
"sort"
@ -118,7 +117,7 @@ func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo
}
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
var (
key = mapi.keyZero
@ -127,10 +126,10 @@ func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
if num > protowire.MaxValidNumber {
return out, errors.New("invalid field number")
return out, errDecode
}
b = b[n:]
err := errUnknown
@ -157,7 +156,7 @@ func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo
if err == errUnknown {
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
} else if err != nil {
return out, err
@ -175,7 +174,7 @@ func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi
}
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
var (
key = mapi.keyZero
@ -184,10 +183,10 @@ func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
if num > protowire.MaxValidNumber {
return out, errors.New("invalid field number")
return out, errDecode
}
b = b[n:]
err := errUnknown
@ -208,7 +207,7 @@ func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi
var v []byte
v, n = protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
var o unmarshalOutput
o, err = f.mi.unmarshalPointer(v, pointerOfValue(val), 0, opts)
@ -221,7 +220,7 @@ func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi
if err == errUnknown {
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
} else if err != nil {
return out, err

View file

@ -11,7 +11,7 @@ import (
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/fieldsort"
"google.golang.org/protobuf/internal/order"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
@ -27,6 +27,7 @@ type coderMessageInfo struct {
coderFields map[protowire.Number]*coderFieldInfo
sizecacheOffset offset
unknownOffset offset
unknownPtrKind bool
extensionOffset offset
needsInitCheck bool
isMessageSet bool
@ -47,9 +48,20 @@ type coderFieldInfo struct {
}
func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
mi.sizecacheOffset = si.sizecacheOffset
mi.unknownOffset = si.unknownOffset
mi.extensionOffset = si.extensionOffset
mi.sizecacheOffset = invalidOffset
mi.unknownOffset = invalidOffset
mi.extensionOffset = invalidOffset
if si.sizecacheOffset.IsValid() && si.sizecacheType == sizecacheType {
mi.sizecacheOffset = si.sizecacheOffset
}
if si.unknownOffset.IsValid() && (si.unknownType == unknownFieldsAType || si.unknownType == unknownFieldsBType) {
mi.unknownOffset = si.unknownOffset
mi.unknownPtrKind = si.unknownType.Kind() == reflect.Ptr
}
if si.extensionOffset.IsValid() && si.extensionType == extensionFieldsType {
mi.extensionOffset = si.extensionOffset
}
mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
fields := mi.Desc.Fields()
@ -73,6 +85,27 @@ func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
var funcs pointerCoderFuncs
var childMessage *MessageInfo
switch {
case ft == nil:
// This never occurs for generated message types.
// It implies that a hand-crafted type has missing Go fields
// for specific protobuf message fields.
funcs = pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return 0
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
return nil, nil
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
panic("missing Go struct field for " + string(fd.FullName()))
},
isInit: func(p pointer, f *coderFieldInfo) error {
panic("missing Go struct field for " + string(fd.FullName()))
},
merge: func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
panic("missing Go struct field for " + string(fd.FullName()))
},
}
case isOneof:
fieldOffset = offsetOf(fs, mi.Exporter)
case fd.IsWeak():
@ -136,7 +169,7 @@ func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
fi := fields.ByNumber(mi.orderedCoderFields[i].num)
fj := fields.ByNumber(mi.orderedCoderFields[j].num)
return fieldsort.Less(fi, fj)
return order.LegacyFieldOrder(fi, fj)
})
}
@ -157,3 +190,28 @@ func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
mi.methods.Merge = mi.merge
}
}
// getUnknownBytes returns a *[]byte for the unknown fields.
// It is the caller's responsibility to check whether the pointer is nil.
// This function is specially designed to be inlineable.
func (mi *MessageInfo) getUnknownBytes(p pointer) *[]byte {
if mi.unknownPtrKind {
return *p.Apply(mi.unknownOffset).BytesPtr()
} else {
return p.Apply(mi.unknownOffset).Bytes()
}
}
// mutableUnknownBytes returns a *[]byte for the unknown fields.
// The returned pointer is guaranteed to not be nil.
func (mi *MessageInfo) mutableUnknownBytes(p pointer) *[]byte {
if mi.unknownPtrKind {
bp := p.Apply(mi.unknownOffset).BytesPtr()
if *bp == nil {
*bp = new([]byte)
}
return *bp
} else {
return p.Apply(mi.unknownOffset).Bytes()
}
}

View file

@ -29,8 +29,9 @@ func sizeMessageSet(mi *MessageInfo, p pointer, opts marshalOptions) (size int)
size += xi.funcs.size(x.Value(), protowire.SizeTag(messageset.FieldMessage), opts)
}
unknown := *p.Apply(mi.unknownOffset).Bytes()
size += messageset.SizeUnknown(unknown)
if u := mi.getUnknownBytes(p); u != nil {
size += messageset.SizeUnknown(*u)
}
return size
}
@ -69,10 +70,12 @@ func marshalMessageSet(mi *MessageInfo, b []byte, p pointer, opts marshalOptions
}
}
unknown := *p.Apply(mi.unknownOffset).Bytes()
b, err := messageset.AppendUnknown(b, unknown)
if err != nil {
return b, err
if u := mi.getUnknownBytes(p); u != nil {
var err error
b, err = messageset.AppendUnknown(b, *u)
if err != nil {
return b, err
}
}
return b, nil
@ -100,13 +103,13 @@ func unmarshalMessageSet(mi *MessageInfo, b []byte, p pointer, opts unmarshalOpt
*ep = make(map[int32]ExtensionField)
}
ext := *ep
unknown := p.Apply(mi.unknownOffset).Bytes()
initialized := true
err = messageset.Unmarshal(b, true, func(num protowire.Number, v []byte) error {
o, err := mi.unmarshalExtension(v, num, protowire.BytesType, ext, opts)
if err == errUnknown {
*unknown = protowire.AppendTag(*unknown, num, protowire.BytesType)
*unknown = append(*unknown, v...)
u := mi.mutableUnknownBytes(p)
*u = protowire.AppendTag(*u, num, protowire.BytesType)
*u = append(*u, v...)
return nil
}
if !o.initialized {

View file

@ -30,7 +30,7 @@ func consumeEnum(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, _
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
p.v.Elem().SetInt(int64(v))
out.n = n
@ -130,12 +130,12 @@ func consumeEnumSlice(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInf
if wtyp == protowire.BytesType {
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
for len(b) > 0 {
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
rv := reflect.New(s.Type().Elem()).Elem()
rv.SetInt(int64(v))
@ -150,7 +150,7 @@ func consumeEnumSlice(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInf
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
rv := reflect.New(s.Type().Elem()).Elem()
rv.SetInt(int64(v))

View file

@ -423,6 +423,13 @@ func (c *messageConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
if c.isNonPointer() {
if v.CanAddr() {
v = v.Addr() // T => *T
} else {
v = reflect.Zero(reflect.PtrTo(v.Type()))
}
}
if m, ok := v.Interface().(pref.ProtoMessage); ok {
return pref.ValueOfMessage(m.ProtoReflect())
}
@ -437,6 +444,16 @@ func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
} else {
rv = reflect.ValueOf(m.Interface())
}
if c.isNonPointer() {
if rv.Type() != reflect.PtrTo(c.goType) {
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), reflect.PtrTo(c.goType)))
}
if !rv.IsNil() {
rv = rv.Elem() // *T => T
} else {
rv = reflect.Zero(rv.Type().Elem())
}
}
if rv.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
}
@ -451,6 +468,9 @@ func (c *messageConverter) IsValidPB(v pref.Value) bool {
} else {
rv = reflect.ValueOf(m.Interface())
}
if c.isNonPointer() {
return rv.Type() == reflect.PtrTo(c.goType)
}
return rv.Type() == c.goType
}
@ -459,9 +479,18 @@ func (c *messageConverter) IsValidGo(v reflect.Value) bool {
}
func (c *messageConverter) New() pref.Value {
if c.isNonPointer() {
return c.PBValueOf(reflect.New(c.goType).Elem())
}
return c.PBValueOf(reflect.New(c.goType.Elem()))
}
func (c *messageConverter) Zero() pref.Value {
return c.PBValueOf(reflect.Zero(c.goType))
}
// isNonPointer reports whether the type is a non-pointer type.
// This never occurs for generated message types.
func (c *messageConverter) isNonPointer() bool {
return c.goType.Kind() != reflect.Ptr
}

View file

@ -17,6 +17,8 @@ import (
piface "google.golang.org/protobuf/runtime/protoiface"
)
var errDecode = errors.New("cannot parse invalid wire-format data")
type unmarshalOptions struct {
flags protoiface.UnmarshalInputFlags
resolver interface {
@ -100,13 +102,13 @@ func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.
var n int
tag, n = protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
b = b[n:]
}
var num protowire.Number
if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) {
return out, errors.New("invalid field number")
return out, errDecode
} else {
num = protowire.Number(n)
}
@ -114,7 +116,7 @@ func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.
if wtyp == protowire.EndGroupType {
if num != groupTag {
return out, errors.New("mismatching end group marker")
return out, errDecode
}
groupTag = 0
break
@ -170,10 +172,10 @@ func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.
}
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
return out, errDecode
}
if !opts.DiscardUnknown() && mi.unknownOffset.IsValid() {
u := p.Apply(mi.unknownOffset).Bytes()
u := mi.mutableUnknownBytes(p)
*u = protowire.AppendTag(*u, num, wtyp)
*u = append(*u, b[:n]...)
}
@ -181,7 +183,7 @@ func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.
b = b[n:]
}
if groupTag != 0 {
return out, errors.New("missing end group marker")
return out, errDecode
}
if mi.numRequiredFields > 0 && bits.OnesCount64(requiredMask) != int(mi.numRequiredFields) {
initialized = false
@ -221,7 +223,7 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num protowire.Number, wtyp p
return out, nil
}
case ValidationInvalid:
return out, errors.New("invalid wire format")
return out, errDecode
case ValidationUnknown:
}
}

View file

@ -79,8 +79,9 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int
size += f.funcs.size(fptr, f, opts)
}
if mi.unknownOffset.IsValid() {
u := *p.Apply(mi.unknownOffset).Bytes()
size += len(u)
if u := mi.getUnknownBytes(p); u != nil {
size += len(*u)
}
}
if mi.sizecacheOffset.IsValid() {
if size > math.MaxInt32 {
@ -141,8 +142,9 @@ func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOpt
}
}
if mi.unknownOffset.IsValid() && !mi.isMessageSet {
u := *p.Apply(mi.unknownOffset).Bytes()
b = append(b, u...)
if u := mi.getUnknownBytes(p); u != nil {
b = append(b, (*u)...)
}
}
return b, nil
}

View file

@ -30,7 +30,7 @@ func (Export) LegacyMessageTypeOf(m piface.MessageV1, name pref.FullName) pref.M
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect().Type()
}
return legacyLoadMessageInfo(reflect.TypeOf(m), name)
return legacyLoadMessageType(reflect.TypeOf(m), name)
}
// UnmarshalJSONEnum unmarshals an enum from a JSON-encoded input.

View file

@ -154,7 +154,8 @@ func (x placeholderExtension) Number() pref.FieldNumber { retu
func (x placeholderExtension) Cardinality() pref.Cardinality { return 0 }
func (x placeholderExtension) Kind() pref.Kind { return 0 }
func (x placeholderExtension) HasJSONName() bool { return false }
func (x placeholderExtension) JSONName() string { return "" }
func (x placeholderExtension) JSONName() string { return "[" + string(x.name) + "]" }
func (x placeholderExtension) TextName() string { return "[" + string(x.name) + "]" }
func (x placeholderExtension) HasPresence() bool { return false }
func (x placeholderExtension) HasOptionalKeyword() bool { return false }
func (x placeholderExtension) IsExtension() bool { return true }

View file

@ -24,14 +24,24 @@ import (
// legacyWrapMessage wraps v as a protoreflect.Message,
// where v must be a *struct kind and not implement the v2 API already.
func legacyWrapMessage(v reflect.Value) pref.Message {
typ := v.Type()
if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct {
t := v.Type()
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
return aberrantMessage{v: v}
}
mt := legacyLoadMessageInfo(typ, "")
mt := legacyLoadMessageInfo(t, "")
return mt.MessageOf(v.Interface())
}
// legacyLoadMessageType dynamically loads a protoreflect.Type for t,
// where t must be not implement the v2 API already.
// The provided name is used if it cannot be determined from the message.
func legacyLoadMessageType(t reflect.Type, name pref.FullName) protoreflect.MessageType {
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
return aberrantMessageType{t}
}
return legacyLoadMessageInfo(t, name)
}
var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo
// legacyLoadMessageInfo dynamically loads a *MessageInfo for t,
@ -49,8 +59,9 @@ func legacyLoadMessageInfo(t reflect.Type, name pref.FullName) *MessageInfo {
GoReflectType: t,
}
var hasMarshal, hasUnmarshal bool
v := reflect.Zero(t).Interface()
if _, ok := v.(legacyMarshaler); ok {
if _, hasMarshal = v.(legacyMarshaler); hasMarshal {
mi.methods.Marshal = legacyMarshal
// We have no way to tell whether the type's Marshal method
@ -59,10 +70,10 @@ func legacyLoadMessageInfo(t reflect.Type, name pref.FullName) *MessageInfo {
// calling Marshal methods when present.
mi.methods.Flags |= piface.SupportMarshalDeterministic
}
if _, ok := v.(legacyUnmarshaler); ok {
if _, hasUnmarshal = v.(legacyUnmarshaler); hasUnmarshal {
mi.methods.Unmarshal = legacyUnmarshal
}
if _, ok := v.(legacyMerger); ok {
if _, hasMerge := v.(legacyMerger); hasMerge || (hasMarshal && hasUnmarshal) {
mi.methods.Merge = legacyMerge
}
@ -75,7 +86,7 @@ func legacyLoadMessageInfo(t reflect.Type, name pref.FullName) *MessageInfo {
var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
// LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
// which must be a *struct kind and not implement the v2 API already.
// which should be a *struct kind and must not implement the v2 API already.
//
// This is exported for testing purposes.
func LegacyLoadMessageDesc(t reflect.Type) pref.MessageDescriptor {
@ -114,17 +125,19 @@ func legacyLoadMessageDesc(t reflect.Type, name pref.FullName) pref.MessageDescr
// If the Go type has no fields, then this might be a proto3 empty message
// from before the size cache was added. If there are any fields, check to
// see that at least one of them looks like something we generated.
if nfield := t.Elem().NumField(); nfield > 0 {
hasProtoField := false
for i := 0; i < nfield; i++ {
f := t.Elem().Field(i)
if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") {
hasProtoField = true
break
if t.Elem().Kind() == reflect.Struct {
if nfield := t.Elem().NumField(); nfield > 0 {
hasProtoField := false
for i := 0; i < nfield; i++ {
f := t.Elem().Field(i)
if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") {
hasProtoField = true
break
}
}
if !hasProtoField {
return aberrantLoadMessageDesc(t, name)
}
}
if !hasProtoField {
return aberrantLoadMessageDesc(t, name)
}
}
@ -370,7 +383,7 @@ type legacyMerger interface {
Merge(protoiface.MessageV1)
}
var legacyProtoMethods = &piface.Methods{
var aberrantProtoMethods = &piface.Methods{
Marshal: legacyMarshal,
Unmarshal: legacyUnmarshal,
Merge: legacyMerge,
@ -401,18 +414,47 @@ func legacyUnmarshal(in piface.UnmarshalInput) (piface.UnmarshalOutput, error) {
v := in.Message.(unwrapper).protoUnwrap()
unmarshaler, ok := v.(legacyUnmarshaler)
if !ok {
return piface.UnmarshalOutput{}, errors.New("%T does not implement Marshal", v)
return piface.UnmarshalOutput{}, errors.New("%T does not implement Unmarshal", v)
}
return piface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf)
}
func legacyMerge(in piface.MergeInput) piface.MergeOutput {
// Check whether this supports the legacy merger.
dstv := in.Destination.(unwrapper).protoUnwrap()
merger, ok := dstv.(legacyMerger)
if ok {
merger.Merge(Export{}.ProtoMessageV1Of(in.Source))
return piface.MergeOutput{Flags: piface.MergeComplete}
}
// If legacy merger is unavailable, implement merge in terms of
// a marshal and unmarshal operation.
srcv := in.Source.(unwrapper).protoUnwrap()
marshaler, ok := srcv.(legacyMarshaler)
if !ok {
return piface.MergeOutput{}
}
merger.Merge(Export{}.ProtoMessageV1Of(in.Source))
dstv = in.Destination.(unwrapper).protoUnwrap()
unmarshaler, ok := dstv.(legacyUnmarshaler)
if !ok {
return piface.MergeOutput{}
}
if !in.Source.IsValid() {
// Legacy Marshal methods may not function on nil messages.
// Check for a typed nil source only after we confirm that
// legacy Marshal/Unmarshal methods are present, for
// consistency.
return piface.MergeOutput{Flags: piface.MergeComplete}
}
b, err := marshaler.Marshal()
if err != nil {
return piface.MergeOutput{}
}
err = unmarshaler.Unmarshal(b)
if err != nil {
return piface.MergeOutput{}
}
return piface.MergeOutput{Flags: piface.MergeComplete}
}
@ -422,6 +464,9 @@ type aberrantMessageType struct {
}
func (mt aberrantMessageType) New() pref.Message {
if mt.t.Kind() == reflect.Ptr {
return aberrantMessage{reflect.New(mt.t.Elem())}
}
return aberrantMessage{reflect.Zero(mt.t)}
}
func (mt aberrantMessageType) Zero() pref.Message {
@ -443,6 +488,17 @@ type aberrantMessage struct {
v reflect.Value
}
// Reset implements the v1 proto.Message.Reset method.
func (m aberrantMessage) Reset() {
if mr, ok := m.v.Interface().(interface{ Reset() }); ok {
mr.Reset()
return
}
if m.v.Kind() == reflect.Ptr && !m.v.IsNil() {
m.v.Elem().Set(reflect.Zero(m.v.Type().Elem()))
}
}
func (m aberrantMessage) ProtoReflect() pref.Message {
return m
}
@ -454,33 +510,40 @@ func (m aberrantMessage) Type() pref.MessageType {
return aberrantMessageType{m.v.Type()}
}
func (m aberrantMessage) New() pref.Message {
if m.v.Type().Kind() == reflect.Ptr {
return aberrantMessage{reflect.New(m.v.Type().Elem())}
}
return aberrantMessage{reflect.Zero(m.v.Type())}
}
func (m aberrantMessage) Interface() pref.ProtoMessage {
return m
}
func (m aberrantMessage) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
return
}
func (m aberrantMessage) Has(pref.FieldDescriptor) bool {
panic("invalid field descriptor")
return false
}
func (m aberrantMessage) Clear(pref.FieldDescriptor) {
panic("invalid field descriptor")
panic("invalid Message.Clear on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) Get(pref.FieldDescriptor) pref.Value {
panic("invalid field descriptor")
func (m aberrantMessage) Get(fd pref.FieldDescriptor) pref.Value {
if fd.Default().IsValid() {
return fd.Default()
}
panic("invalid Message.Get on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) Set(pref.FieldDescriptor, pref.Value) {
panic("invalid field descriptor")
panic("invalid Message.Set on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) Mutable(pref.FieldDescriptor) pref.Value {
panic("invalid field descriptor")
panic("invalid Message.Mutable on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) NewField(pref.FieldDescriptor) pref.Value {
panic("invalid field descriptor")
panic("invalid Message.NewField on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) WhichOneof(pref.OneofDescriptor) pref.FieldDescriptor {
panic("invalid oneof descriptor")
panic("invalid Message.WhichOneof descriptor on " + string(m.Descriptor().FullName()))
}
func (m aberrantMessage) GetUnknown() pref.RawFields {
return nil
@ -489,13 +552,13 @@ func (m aberrantMessage) SetUnknown(pref.RawFields) {
// SetUnknown discards its input on messages which don't support unknown field storage.
}
func (m aberrantMessage) IsValid() bool {
// An invalid message is a read-only, empty message. Since we don't know anything
// about the alleged contents of this message, we can't say with confidence that
// it is invalid in this sense. Therefore, report it as valid.
return true
if m.v.Kind() == reflect.Ptr {
return !m.v.IsNil()
}
return false
}
func (m aberrantMessage) ProtoMethods() *piface.Methods {
return legacyProtoMethods
return aberrantProtoMethods
}
func (m aberrantMessage) protoUnwrap() interface{} {
return m.v.Interface()

View file

@ -77,9 +77,9 @@ func (mi *MessageInfo) mergePointer(dst, src pointer, opts mergeOptions) {
}
}
if mi.unknownOffset.IsValid() {
du := dst.Apply(mi.unknownOffset).Bytes()
su := src.Apply(mi.unknownOffset).Bytes()
if len(*su) > 0 {
su := mi.getUnknownBytes(src)
if su != nil && len(*su) > 0 {
du := mi.mutableUnknownBytes(dst)
*du = append(*du, *su...)
}
}

View file

@ -15,6 +15,7 @@ import (
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/reflect/protoreflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
)
// MessageInfo provides protobuf related functionality for a given Go type
@ -109,22 +110,29 @@ func (mi *MessageInfo) getPointer(m pref.Message) (p pointer, ok bool) {
type (
SizeCache = int32
WeakFields = map[int32]protoreflect.ProtoMessage
UnknownFields = []byte
UnknownFields = unknownFieldsA // TODO: switch to unknownFieldsB
unknownFieldsA = []byte
unknownFieldsB = *[]byte
ExtensionFields = map[int32]ExtensionField
)
var (
sizecacheType = reflect.TypeOf(SizeCache(0))
weakFieldsType = reflect.TypeOf(WeakFields(nil))
unknownFieldsType = reflect.TypeOf(UnknownFields(nil))
unknownFieldsAType = reflect.TypeOf(unknownFieldsA(nil))
unknownFieldsBType = reflect.TypeOf(unknownFieldsB(nil))
extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
)
type structInfo struct {
sizecacheOffset offset
sizecacheType reflect.Type
weakOffset offset
weakType reflect.Type
unknownOffset offset
unknownType reflect.Type
extensionOffset offset
extensionType reflect.Type
fieldsByNumber map[pref.FieldNumber]reflect.StructField
oneofsByName map[pref.Name]reflect.StructField
@ -151,18 +159,22 @@ fieldLoop:
case genid.SizeCache_goname, genid.SizeCacheA_goname:
if f.Type == sizecacheType {
si.sizecacheOffset = offsetOf(f, mi.Exporter)
si.sizecacheType = f.Type
}
case genid.WeakFields_goname, genid.WeakFieldsA_goname:
if f.Type == weakFieldsType {
si.weakOffset = offsetOf(f, mi.Exporter)
si.weakType = f.Type
}
case genid.UnknownFields_goname, genid.UnknownFieldsA_goname:
if f.Type == unknownFieldsType {
if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType {
si.unknownOffset = offsetOf(f, mi.Exporter)
si.unknownType = f.Type
}
case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname:
if f.Type == extensionFieldsType {
si.extensionOffset = offsetOf(f, mi.Exporter)
si.extensionType = f.Type
}
default:
for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
@ -212,4 +224,53 @@ func (mi *MessageInfo) New() protoreflect.Message {
func (mi *MessageInfo) Zero() protoreflect.Message {
return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
}
func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor { return mi.Desc }
func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor {
return mi.Desc
}
func (mi *MessageInfo) Enum(i int) protoreflect.EnumType {
mi.init()
fd := mi.Desc.Fields().Get(i)
return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()])
}
func (mi *MessageInfo) Message(i int) protoreflect.MessageType {
mi.init()
fd := mi.Desc.Fields().Get(i)
switch {
case fd.IsWeak():
mt, _ := preg.GlobalTypes.FindMessageByName(fd.Message().FullName())
return mt
case fd.IsMap():
return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]}
default:
return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()])
}
}
type mapEntryType struct {
desc protoreflect.MessageDescriptor
valType interface{} // zero value of enum or message type
}
func (mt mapEntryType) New() protoreflect.Message {
return nil
}
func (mt mapEntryType) Zero() protoreflect.Message {
return nil
}
func (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor {
return mt.desc
}
func (mt mapEntryType) Enum(i int) protoreflect.EnumType {
fd := mt.desc.Fields().Get(i)
if fd.Enum() == nil {
return nil
}
return Export{}.EnumTypeOf(mt.valType)
}
func (mt mapEntryType) Message(i int) protoreflect.MessageType {
fd := mt.desc.Fields().Get(i)
if fd.Message() == nil {
return nil
}
return Export{}.MessageTypeOf(mt.valType)
}

View file

@ -8,6 +8,7 @@ import (
"fmt"
"reflect"
"google.golang.org/protobuf/internal/detrand"
"google.golang.org/protobuf/internal/pragma"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
@ -16,6 +17,11 @@ type reflectMessageInfo struct {
fields map[pref.FieldNumber]*fieldInfo
oneofs map[pref.Name]*oneofInfo
// fieldTypes contains the zero value of an enum or message field.
// For lists, it contains the element type.
// For maps, it contains the entry value type.
fieldTypes map[pref.FieldNumber]interface{}
// denseFields is a subset of fields where:
// 0 < fieldDesc.Number() < len(denseFields)
// It provides faster access to the fieldInfo, but may be incomplete.
@ -36,6 +42,7 @@ func (mi *MessageInfo) makeReflectFuncs(t reflect.Type, si structInfo) {
mi.makeKnownFieldsFunc(si)
mi.makeUnknownFieldsFunc(t, si)
mi.makeExtensionFieldsFunc(t, si)
mi.makeFieldTypes(si)
}
// makeKnownFieldsFunc generates functions for operations that can be performed
@ -51,17 +58,23 @@ func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
for i := 0; i < fds.Len(); i++ {
fd := fds.Get(i)
fs := si.fieldsByNumber[fd.Number()]
isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
if isOneof {
fs = si.oneofsByName[fd.ContainingOneof().Name()]
}
var fi fieldInfo
switch {
case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
case fs.Type == nil:
fi = fieldInfoForMissing(fd) // never occurs for officially generated message types
case isOneof:
fi = fieldInfoForOneof(fd, fs, mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
case fd.IsMap():
fi = fieldInfoForMap(fd, fs, mi.Exporter)
case fd.IsList():
fi = fieldInfoForList(fd, fs, mi.Exporter)
case fd.IsWeak():
fi = fieldInfoForWeakMessage(fd, si.weakOffset)
case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
case fd.Message() != nil:
fi = fieldInfoForMessage(fd, fs, mi.Exporter)
default:
fi = fieldInfoForScalar(fd, fs, mi.Exporter)
@ -92,27 +105,53 @@ func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
i++
}
}
// Introduce instability to iteration order, but keep it deterministic.
if len(mi.rangeInfos) > 1 && detrand.Bool() {
i := detrand.Intn(len(mi.rangeInfos) - 1)
mi.rangeInfos[i], mi.rangeInfos[i+1] = mi.rangeInfos[i+1], mi.rangeInfos[i]
}
}
func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) {
mi.getUnknown = func(pointer) pref.RawFields { return nil }
mi.setUnknown = func(pointer, pref.RawFields) { return }
if si.unknownOffset.IsValid() {
switch {
case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsAType:
// Handle as []byte.
mi.getUnknown = func(p pointer) pref.RawFields {
if p.IsNil() {
return nil
}
rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
return pref.RawFields(*rv.Interface().(*[]byte))
return *p.Apply(mi.unknownOffset).Bytes()
}
mi.setUnknown = func(p pointer, b pref.RawFields) {
if p.IsNil() {
panic("invalid SetUnknown on nil Message")
}
rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
*rv.Interface().(*[]byte) = []byte(b)
*p.Apply(mi.unknownOffset).Bytes() = b
}
} else {
case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsBType:
// Handle as *[]byte.
mi.getUnknown = func(p pointer) pref.RawFields {
if p.IsNil() {
return nil
}
bp := p.Apply(mi.unknownOffset).BytesPtr()
if *bp == nil {
return nil
}
return **bp
}
mi.setUnknown = func(p pointer, b pref.RawFields) {
if p.IsNil() {
panic("invalid SetUnknown on nil Message")
}
bp := p.Apply(mi.unknownOffset).BytesPtr()
if *bp == nil {
*bp = new([]byte)
}
**bp = b
}
default:
mi.getUnknown = func(pointer) pref.RawFields {
return nil
}
@ -139,6 +178,58 @@ func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) {
}
}
}
func (mi *MessageInfo) makeFieldTypes(si structInfo) {
md := mi.Desc
fds := md.Fields()
for i := 0; i < fds.Len(); i++ {
var ft reflect.Type
fd := fds.Get(i)
fs := si.fieldsByNumber[fd.Number()]
isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
if isOneof {
fs = si.oneofsByName[fd.ContainingOneof().Name()]
}
var isMessage bool
switch {
case fs.Type == nil:
continue // never occurs for officially generated message types
case isOneof:
if fd.Enum() != nil || fd.Message() != nil {
ft = si.oneofWrappersByNumber[fd.Number()].Field(0).Type
}
case fd.IsMap():
if fd.MapValue().Enum() != nil || fd.MapValue().Message() != nil {
ft = fs.Type.Elem()
}
isMessage = fd.MapValue().Message() != nil
case fd.IsList():
if fd.Enum() != nil || fd.Message() != nil {
ft = fs.Type.Elem()
}
isMessage = fd.Message() != nil
case fd.Enum() != nil:
ft = fs.Type
if fd.HasPresence() && ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
case fd.Message() != nil:
ft = fs.Type
if fd.IsWeak() {
ft = nil
}
isMessage = true
}
if isMessage && ft != nil && ft.Kind() != reflect.Ptr {
ft = reflect.PtrTo(ft) // never occurs for officially generated message types
}
if ft != nil {
if mi.fieldTypes == nil {
mi.fieldTypes = make(map[pref.FieldNumber]interface{})
}
mi.fieldTypes[fd.Number()] = reflect.Zero(ft).Interface()
}
}
}
type extensionMap map[int32]ExtensionField
@ -306,7 +397,6 @@ var (
// pointer to a named Go struct. If the provided type has a ProtoReflect method,
// it must be implemented by calling this method.
func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
// TODO: Switch the input to be an opaque Pointer.
if reflect.TypeOf(m) != mi.GoReflectType {
panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
}
@ -320,6 +410,17 @@ func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
func (m *messageReflectWrapper) pointer() pointer { return m.p }
func (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi }
// Reset implements the v1 proto.Message.Reset method.
func (m *messageIfaceWrapper) Reset() {
if mr, ok := m.protoUnwrap().(interface{ Reset() }); ok {
mr.Reset()
return
}
rv := reflect.ValueOf(m.protoUnwrap())
if rv.Kind() == reflect.Ptr && !rv.IsNil() {
rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
}
}
func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
return (*messageReflectWrapper)(m)
}

View file

@ -28,6 +28,39 @@ type fieldInfo struct {
newField func() pref.Value
}
func fieldInfoForMissing(fd pref.FieldDescriptor) fieldInfo {
// This never occurs for generated message types.
// It implies that a hand-crafted type has missing Go fields
// for specific protobuf message fields.
return fieldInfo{
fieldDesc: fd,
has: func(p pointer) bool {
return false
},
clear: func(p pointer) {
panic("missing Go struct field for " + string(fd.FullName()))
},
get: func(p pointer) pref.Value {
return fd.Default()
},
set: func(p pointer, v pref.Value) {
panic("missing Go struct field for " + string(fd.FullName()))
},
mutable: func(p pointer) pref.Value {
panic("missing Go struct field for " + string(fd.FullName()))
},
newMessage: func() pref.Message {
panic("missing Go struct field for " + string(fd.FullName()))
},
newField: func() pref.Value {
if v := fd.Default(); v.IsValid() {
return v
}
panic("missing Go struct field for " + string(fd.FullName()))
},
}
}
func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
ft := fs.Type
if ft.Kind() != reflect.Interface {
@ -97,7 +130,7 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x export
rv.Set(reflect.New(ot))
}
rv = rv.Elem().Elem().Field(0)
if rv.IsNil() {
if rv.Kind() == reflect.Ptr && rv.IsNil() {
rv.Set(conv.GoValueOf(pref.ValueOfMessage(conv.New().Message())))
}
return conv.PBValueOf(rv)
@ -225,7 +258,10 @@ func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x expor
isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
if nullable {
if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
panic(fmt.Sprintf("field %v has invalid type: got %v, want pointer", fd.FullName(), ft))
// This never occurs for generated message types.
// Despite the protobuf type system specifying presence,
// the Go field type cannot represent it.
nullable = false
}
if ft.Kind() == reflect.Ptr {
ft = ft.Elem()
@ -388,6 +424,9 @@ func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x expo
return false
}
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
if fs.Type.Kind() != reflect.Ptr {
return !isZero(rv)
}
return !rv.IsNil()
},
clear: func(p pointer) {
@ -404,13 +443,13 @@ func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x expo
set: func(p pointer, v pref.Value) {
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
rv.Set(conv.GoValueOf(v))
if rv.IsNil() {
if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
}
},
mutable: func(p pointer) pref.Value {
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
if rv.IsNil() {
if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
rv.Set(conv.GoValueOf(conv.New()))
}
return conv.PBValueOf(rv)
@ -464,3 +503,41 @@ func makeOneofInfo(od pref.OneofDescriptor, si structInfo, x exporter) *oneofInf
}
return oi
}
// isZero is identical to reflect.Value.IsZero.
// TODO: Remove this when Go1.13 is the minimally supported Go version.
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return math.Float64bits(v.Float()) == 0
case reflect.Complex64, reflect.Complex128:
c := v.Complex()
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i)) {
return false
}
}
return true
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
return v.IsNil()
case reflect.String:
return v.Len() == 0
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if !isZero(v.Field(i)) {
return false
}
}
return true
default:
panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()})
}
}

View file

@ -121,6 +121,7 @@ func (p pointer) String() *string { return p.v.Interface().(*string) }
func (p pointer) StringPtr() **string { return p.v.Interface().(**string) }
func (p pointer) StringSlice() *[]string { return p.v.Interface().(*[]string) }
func (p pointer) Bytes() *[]byte { return p.v.Interface().(*[]byte) }
func (p pointer) BytesPtr() **[]byte { return p.v.Interface().(**[]byte) }
func (p pointer) BytesSlice() *[][]byte { return p.v.Interface().(*[][]byte) }
func (p pointer) WeakFields() *weakFields { return (*weakFields)(p.v.Interface().(*WeakFields)) }
func (p pointer) Extensions() *map[int32]ExtensionField {

View file

@ -109,6 +109,7 @@ func (p pointer) String() *string { return (*string)(p.p)
func (p pointer) StringPtr() **string { return (**string)(p.p) }
func (p pointer) StringSlice() *[]string { return (*[]string)(p.p) }
func (p pointer) Bytes() *[]byte { return (*[]byte)(p.p) }
func (p pointer) BytesPtr() **[]byte { return (**[]byte)(p.p) }
func (p pointer) BytesSlice() *[][]byte { return (*[][]byte)(p.p) }
func (p pointer) WeakFields() *weakFields { return (*weakFields)(p.p) }
func (p pointer) Extensions() *map[int32]ExtensionField { return (*map[int32]ExtensionField)(p.p) }

View file

@ -1,43 +0,0 @@
// 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 mapsort provides sorted access to maps.
package mapsort
import (
"sort"
"google.golang.org/protobuf/reflect/protoreflect"
)
// Range iterates over every map entry in sorted key order,
// calling f for each key and value encountered.
func Range(mapv protoreflect.Map, keyKind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
var keys []protoreflect.MapKey
mapv.Range(func(key protoreflect.MapKey, _ protoreflect.Value) bool {
keys = append(keys, key)
return true
})
sort.Slice(keys, func(i, j int) bool {
switch keyKind {
case protoreflect.BoolKind:
return !keys[i].Bool() && keys[j].Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind,
protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return keys[i].Int() < keys[j].Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind,
protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return keys[i].Uint() < keys[j].Uint()
case protoreflect.StringKind:
return keys[i].String() < keys[j].String()
default:
panic("invalid kind: " + keyKind.String())
}
})
for _, key := range keys {
if !f(key, mapv.Get(key)) {
break
}
}
}

View file

@ -0,0 +1,89 @@
// Copyright 2020 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 order
import (
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// FieldOrder specifies the ordering to visit message fields.
// It is a function that reports whether x is ordered before y.
type FieldOrder func(x, y pref.FieldDescriptor) bool
var (
// AnyFieldOrder specifies no specific field ordering.
AnyFieldOrder FieldOrder = nil
// LegacyFieldOrder sorts fields in the same ordering as emitted by
// wire serialization in the github.com/golang/protobuf implementation.
LegacyFieldOrder FieldOrder = func(x, y pref.FieldDescriptor) bool {
ox, oy := x.ContainingOneof(), y.ContainingOneof()
inOneof := func(od pref.OneofDescriptor) bool {
return od != nil && !od.IsSynthetic()
}
// Extension fields sort before non-extension fields.
if x.IsExtension() != y.IsExtension() {
return x.IsExtension() && !y.IsExtension()
}
// Fields not within a oneof sort before those within a oneof.
if inOneof(ox) != inOneof(oy) {
return !inOneof(ox) && inOneof(oy)
}
// Fields in disjoint oneof sets are sorted by declaration index.
if ox != nil && oy != nil && ox != oy {
return ox.Index() < oy.Index()
}
// Fields sorted by field number.
return x.Number() < y.Number()
}
// NumberFieldOrder sorts fields by their field number.
NumberFieldOrder FieldOrder = func(x, y pref.FieldDescriptor) bool {
return x.Number() < y.Number()
}
// IndexNameFieldOrder sorts non-extension fields before extension fields.
// Non-extensions are sorted according to their declaration index.
// Extensions are sorted according to their full name.
IndexNameFieldOrder FieldOrder = func(x, y pref.FieldDescriptor) bool {
// Non-extension fields sort before extension fields.
if x.IsExtension() != y.IsExtension() {
return !x.IsExtension() && y.IsExtension()
}
// Extensions sorted by fullname.
if x.IsExtension() && y.IsExtension() {
return x.FullName() < y.FullName()
}
// Non-extensions sorted by declaration index.
return x.Index() < y.Index()
}
)
// KeyOrder specifies the ordering to visit map entries.
// It is a function that reports whether x is ordered before y.
type KeyOrder func(x, y pref.MapKey) bool
var (
// AnyKeyOrder specifies no specific key ordering.
AnyKeyOrder KeyOrder = nil
// GenericKeyOrder sorts false before true, numeric keys in ascending order,
// and strings in lexicographical ordering according to UTF-8 codepoints.
GenericKeyOrder KeyOrder = func(x, y pref.MapKey) bool {
switch x.Interface().(type) {
case bool:
return !x.Bool() && y.Bool()
case int32, int64:
return x.Int() < y.Int()
case uint32, uint64:
return x.Uint() < y.Uint()
case string:
return x.String() < y.String()
default:
panic("invalid map key type")
}
}
)

View file

@ -0,0 +1,115 @@
// Copyright 2020 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 order provides ordered access to messages and maps.
package order
import (
"sort"
"sync"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type messageField struct {
fd pref.FieldDescriptor
v pref.Value
}
var messageFieldPool = sync.Pool{
New: func() interface{} { return new([]messageField) },
}
type (
// FieldRnger is an interface for visiting all fields in a message.
// The protoreflect.Message type implements this interface.
FieldRanger interface{ Range(VisitField) }
// VisitField is called everytime a message field is visited.
VisitField = func(pref.FieldDescriptor, pref.Value) bool
)
// RangeFields iterates over the fields of fs according to the specified order.
func RangeFields(fs FieldRanger, less FieldOrder, fn VisitField) {
if less == nil {
fs.Range(fn)
return
}
// Obtain a pre-allocated scratch buffer.
p := messageFieldPool.Get().(*[]messageField)
fields := (*p)[:0]
defer func() {
if cap(fields) < 1024 {
*p = fields
messageFieldPool.Put(p)
}
}()
// Collect all fields in the message and sort them.
fs.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
fields = append(fields, messageField{fd, v})
return true
})
sort.Slice(fields, func(i, j int) bool {
return less(fields[i].fd, fields[j].fd)
})
// Visit the fields in the specified ordering.
for _, f := range fields {
if !fn(f.fd, f.v) {
return
}
}
}
type mapEntry struct {
k pref.MapKey
v pref.Value
}
var mapEntryPool = sync.Pool{
New: func() interface{} { return new([]mapEntry) },
}
type (
// EntryRanger is an interface for visiting all fields in a message.
// The protoreflect.Map type implements this interface.
EntryRanger interface{ Range(VisitEntry) }
// VisitEntry is called everytime a map entry is visited.
VisitEntry = func(pref.MapKey, pref.Value) bool
)
// RangeEntries iterates over the entries of es according to the specified order.
func RangeEntries(es EntryRanger, less KeyOrder, fn VisitEntry) {
if less == nil {
es.Range(fn)
return
}
// Obtain a pre-allocated scratch buffer.
p := mapEntryPool.Get().(*[]mapEntry)
entries := (*p)[:0]
defer func() {
if cap(entries) < 1024 {
*p = entries
mapEntryPool.Put(p)
}
}()
// Collect all entries in the map and sort them.
es.Range(func(k pref.MapKey, v pref.Value) bool {
entries = append(entries, mapEntry{k, v})
return true
})
sort.Slice(entries, func(i, j int) bool {
return less(entries[i].k, entries[j].k)
})
// Visit the entries in the specified ordering.
for _, e := range entries {
if !fn(e.k, e.v) {
return
}
}
}

View file

@ -52,7 +52,7 @@ import (
// 10. Send out the CL for review and submit it.
const (
Major = 1
Minor = 25
Minor = 27
Patch = 0
PreRelease = ""
)

View file

@ -45,12 +45,14 @@ type UnmarshalOptions struct {
}
// Unmarshal parses the wire-format message in b and places the result in m.
// The provided message must be mutable (e.g., a non-nil pointer to a message).
func Unmarshal(b []byte, m Message) error {
_, err := UnmarshalOptions{}.unmarshal(b, m.ProtoReflect())
return err
}
// Unmarshal parses the wire-format message in b and places the result in m.
// The provided message must be mutable (e.g., a non-nil pointer to a message).
func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
_, err := o.unmarshal(b, m.ProtoReflect())
return err
@ -116,10 +118,10 @@ func (o UnmarshalOptions) unmarshalMessageSlow(b []byte, m protoreflect.Message)
// Parse the tag (field number and wire type).
num, wtyp, tagLen := protowire.ConsumeTag(b)
if tagLen < 0 {
return protowire.ParseError(tagLen)
return errDecode
}
if num > protowire.MaxValidNumber {
return errors.New("invalid field number")
return errDecode
}
// Find the field descriptor for this field number.
@ -159,7 +161,7 @@ func (o UnmarshalOptions) unmarshalMessageSlow(b []byte, m protoreflect.Message)
}
valLen = protowire.ConsumeFieldValue(num, wtyp, b[tagLen:])
if valLen < 0 {
return protowire.ParseError(valLen)
return errDecode
}
if !o.DiscardUnknown {
m.SetUnknown(append(m.GetUnknown(), b[:tagLen+valLen]...))
@ -194,7 +196,7 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto
}
b, n = protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
var (
keyField = fd.MapKey()
@ -213,10 +215,10 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
if num > protowire.MaxValidNumber {
return 0, errors.New("invalid field number")
return 0, errDecode
}
b = b[n:]
err = errUnknown
@ -246,7 +248,7 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto
if err == errUnknown {
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
} else if err != nil {
return 0, err
@ -272,3 +274,5 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto
// to the unknown field set of a message. It is never returned from an exported
// function.
var errUnknown = errors.New("BUG: internal error (unknown)")
var errDecode = errors.New("cannot parse invalid wire-format data")

View file

@ -27,7 +27,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfBool(protowire.DecodeBool(v)), n, nil
case protoreflect.EnumKind:
@ -36,7 +36,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfEnum(protoreflect.EnumNumber(v)), n, nil
case protoreflect.Int32Kind:
@ -45,7 +45,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt32(int32(v)), n, nil
case protoreflect.Sint32Kind:
@ -54,7 +54,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt32(int32(protowire.DecodeZigZag(v & math.MaxUint32))), n, nil
case protoreflect.Uint32Kind:
@ -63,7 +63,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfUint32(uint32(v)), n, nil
case protoreflect.Int64Kind:
@ -72,7 +72,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt64(int64(v)), n, nil
case protoreflect.Sint64Kind:
@ -81,7 +81,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt64(protowire.DecodeZigZag(v)), n, nil
case protoreflect.Uint64Kind:
@ -90,7 +90,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfUint64(v), n, nil
case protoreflect.Sfixed32Kind:
@ -99,7 +99,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt32(int32(v)), n, nil
case protoreflect.Fixed32Kind:
@ -108,7 +108,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfUint32(uint32(v)), n, nil
case protoreflect.FloatKind:
@ -117,7 +117,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfFloat32(math.Float32frombits(uint32(v))), n, nil
case protoreflect.Sfixed64Kind:
@ -126,7 +126,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfInt64(int64(v)), n, nil
case protoreflect.Fixed64Kind:
@ -135,7 +135,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfUint64(v), n, nil
case protoreflect.DoubleKind:
@ -144,7 +144,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfFloat64(math.Float64frombits(v)), n, nil
case protoreflect.StringKind:
@ -153,7 +153,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
if strs.EnforceUTF8(fd) && !utf8.Valid(v) {
return protoreflect.Value{}, 0, errors.InvalidUTF8(string(fd.FullName()))
@ -165,7 +165,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfBytes(append(emptyBuf[:], v...)), n, nil
case protoreflect.MessageKind:
@ -174,7 +174,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfBytes(v), n, nil
case protoreflect.GroupKind:
@ -183,7 +183,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp protowire.Type, fd prot
}
v, n := protowire.ConsumeGroup(fd.Number(), b)
if n < 0 {
return val, 0, protowire.ParseError(n)
return val, 0, errDecode
}
return protoreflect.ValueOfBytes(v), n, nil
default:
@ -197,12 +197,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfBool(protowire.DecodeBool(v)))
@ -214,7 +214,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfBool(protowire.DecodeBool(v)))
return n, nil
@ -222,12 +222,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfEnum(protoreflect.EnumNumber(v)))
@ -239,7 +239,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfEnum(protoreflect.EnumNumber(v)))
return n, nil
@ -247,12 +247,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt32(int32(v)))
@ -264,7 +264,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt32(int32(v)))
return n, nil
@ -272,12 +272,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt32(int32(protowire.DecodeZigZag(v & math.MaxUint32))))
@ -289,7 +289,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt32(int32(protowire.DecodeZigZag(v & math.MaxUint32))))
return n, nil
@ -297,12 +297,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfUint32(uint32(v)))
@ -314,7 +314,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfUint32(uint32(v)))
return n, nil
@ -322,12 +322,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt64(int64(v)))
@ -339,7 +339,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt64(int64(v)))
return n, nil
@ -347,12 +347,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt64(protowire.DecodeZigZag(v)))
@ -364,7 +364,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt64(protowire.DecodeZigZag(v)))
return n, nil
@ -372,12 +372,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeVarint(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfUint64(v))
@ -389,7 +389,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfUint64(v))
return n, nil
@ -397,12 +397,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed32(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt32(int32(v)))
@ -414,7 +414,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt32(int32(v)))
return n, nil
@ -422,12 +422,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed32(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfUint32(uint32(v)))
@ -439,7 +439,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfUint32(uint32(v)))
return n, nil
@ -447,12 +447,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed32(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfFloat32(math.Float32frombits(uint32(v))))
@ -464,7 +464,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfFloat32(math.Float32frombits(uint32(v))))
return n, nil
@ -472,12 +472,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed64(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfInt64(int64(v)))
@ -489,7 +489,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfInt64(int64(v)))
return n, nil
@ -497,12 +497,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed64(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfUint64(v))
@ -514,7 +514,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfUint64(v))
return n, nil
@ -522,12 +522,12 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
if wtyp == protowire.BytesType {
buf, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
for len(buf) > 0 {
v, n := protowire.ConsumeFixed64(buf)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
buf = buf[n:]
list.Append(protoreflect.ValueOfFloat64(math.Float64frombits(v)))
@ -539,7 +539,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfFloat64(math.Float64frombits(v)))
return n, nil
@ -549,7 +549,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
if strs.EnforceUTF8(fd) && !utf8.Valid(v) {
return 0, errors.InvalidUTF8(string(fd.FullName()))
@ -562,7 +562,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
list.Append(protoreflect.ValueOfBytes(append(emptyBuf[:], v...)))
return n, nil
@ -572,7 +572,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
m := list.NewElement()
if err := o.unmarshalMessage(v, m.Message()); err != nil {
@ -586,7 +586,7 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp protowire.Type, list prot
}
v, n := protowire.ConsumeGroup(fd.Number(), b)
if n < 0 {
return 0, protowire.ParseError(n)
return 0, errDecode
}
m := list.NewElement()
if err := o.unmarshalMessage(v, m.Message()); err != nil {

View file

@ -5,12 +5,9 @@
package proto
import (
"sort"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/fieldsort"
"google.golang.org/protobuf/internal/mapsort"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
@ -211,14 +208,15 @@ func (o MarshalOptions) marshalMessageSlow(b []byte, m protoreflect.Message) ([]
if messageset.IsMessageSet(m.Descriptor()) {
return o.marshalMessageSet(b, m)
}
// There are many choices for what order we visit fields in. The default one here
// is chosen for reasonable efficiency and simplicity given the protoreflect API.
// It is not deterministic, since Message.Range does not return fields in any
// defined order.
//
// When using deterministic serialization, we sort the known fields.
fieldOrder := order.AnyFieldOrder
if o.Deterministic {
// TODO: This should use a more natural ordering like NumberFieldOrder,
// but doing so breaks golden tests that make invalid assumption about
// output stability of this implementation.
fieldOrder = order.LegacyFieldOrder
}
var err error
o.rangeFields(m, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
order.RangeFields(m, fieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
b, err = o.marshalField(b, fd, v)
return err == nil
})
@ -229,27 +227,6 @@ func (o MarshalOptions) marshalMessageSlow(b []byte, m protoreflect.Message) ([]
return b, nil
}
// rangeFields visits fields in a defined order when deterministic serialization is enabled.
func (o MarshalOptions) rangeFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
if !o.Deterministic {
m.Range(f)
return
}
var fds []protoreflect.FieldDescriptor
m.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
fds = append(fds, fd)
return true
})
sort.Slice(fds, func(a, b int) bool {
return fieldsort.Less(fds[a], fds[b])
})
for _, fd := range fds {
if !f(fd, m.Get(fd)) {
break
}
}
}
func (o MarshalOptions) marshalField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
switch {
case fd.IsList():
@ -292,8 +269,12 @@ func (o MarshalOptions) marshalList(b []byte, fd protoreflect.FieldDescriptor, l
func (o MarshalOptions) marshalMap(b []byte, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) ([]byte, error) {
keyf := fd.MapKey()
valf := fd.MapValue()
keyOrder := order.AnyKeyOrder
if o.Deterministic {
keyOrder = order.GenericKeyOrder
}
var err error
o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
order.RangeEntries(mapv, keyOrder, func(key protoreflect.MapKey, value protoreflect.Value) bool {
b = protowire.AppendTag(b, fd.Number(), protowire.BytesType)
var pos int
b, pos = appendSpeculativeLength(b)
@ -312,14 +293,6 @@ func (o MarshalOptions) marshalMap(b []byte, fd protoreflect.FieldDescriptor, ma
return b, err
}
func (o MarshalOptions) rangeMap(mapv protoreflect.Map, kind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
if !o.Deterministic {
mapv.Range(f)
return
}
mapsort.Range(mapv, kind, f)
}
// When encoding length-prefixed fields, we speculatively set aside some number of bytes
// for the length, encode the data, and then encode the length (shifting the data if necessary
// to make room).

View file

@ -111,18 +111,31 @@ func equalList(fd pref.FieldDescriptor, x, y pref.List) bool {
// equalValue compares two singular values.
func equalValue(fd pref.FieldDescriptor, x, y pref.Value) bool {
switch {
case fd.Message() != nil:
return equalMessage(x.Message(), y.Message())
case fd.Kind() == pref.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case fd.Kind() == pref.FloatKind, fd.Kind() == pref.DoubleKind:
switch fd.Kind() {
case pref.BoolKind:
return x.Bool() == y.Bool()
case pref.EnumKind:
return x.Enum() == y.Enum()
case pref.Int32Kind, pref.Sint32Kind,
pref.Int64Kind, pref.Sint64Kind,
pref.Sfixed32Kind, pref.Sfixed64Kind:
return x.Int() == y.Int()
case pref.Uint32Kind, pref.Uint64Kind,
pref.Fixed32Kind, pref.Fixed64Kind:
return x.Uint() == y.Uint()
case pref.FloatKind, pref.DoubleKind:
fx := x.Float()
fy := y.Float()
if math.IsNaN(fx) || math.IsNaN(fy) {
return math.IsNaN(fx) && math.IsNaN(fy)
}
return fx == fy
case pref.StringKind:
return x.String() == y.String()
case pref.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case pref.MessageKind, pref.GroupKind:
return equalMessage(x.Message(), y.Message())
default:
return x.Interface() == y.Interface()
}

View file

@ -9,6 +9,7 @@ import (
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
@ -28,8 +29,12 @@ func (o MarshalOptions) marshalMessageSet(b []byte, m protoreflect.Message) ([]b
if !flags.ProtoLegacy {
return b, errors.New("no support for message_set_wire_format")
}
fieldOrder := order.AnyFieldOrder
if o.Deterministic {
fieldOrder = order.NumberFieldOrder
}
var err error
o.rangeFields(m, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
order.RangeFields(m, fieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
b, err = o.marshalMessageSetField(b, fd, v)
return err == nil
})

View file

@ -32,3 +32,12 @@ var Error error
func init() {
Error = errors.Error
}
// MessageName returns the full name of m.
// If m is nil, it returns an empty string.
func MessageName(m Message) protoreflect.FullName {
if m == nil {
return ""
}
return m.ProtoReflect().Descriptor().FullName()
}

View file

@ -0,0 +1,276 @@
// 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 protodesc provides functionality for converting
// FileDescriptorProto messages to/from protoreflect.FileDescriptor values.
//
// The google.protobuf.FileDescriptorProto is a protobuf message that describes
// the type information for a .proto file in a form that is easily serializable.
// The protoreflect.FileDescriptor is a more structured representation of
// the FileDescriptorProto message where references and remote dependencies
// can be directly followed.
package protodesc
import (
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)
// Resolver is the resolver used by NewFile to resolve dependencies.
// The enums and messages provided must belong to some parent file,
// which is also registered.
//
// It is implemented by protoregistry.Files.
type Resolver interface {
FindFileByPath(string) (protoreflect.FileDescriptor, error)
FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
}
// FileOptions configures the construction of file descriptors.
type FileOptions struct {
pragma.NoUnkeyedLiterals
// AllowUnresolvable configures New to permissively allow unresolvable
// file, enum, or message dependencies. Unresolved dependencies are replaced
// by placeholder equivalents.
//
// The following dependencies may be left unresolved:
// • Resolving an imported file.
// • Resolving the type for a message field or extension field.
// If the kind of the field is unknown, then a placeholder is used for both
// the Enum and Message accessors on the protoreflect.FieldDescriptor.
// • Resolving an enum value set as the default for an optional enum field.
// If unresolvable, the protoreflect.FieldDescriptor.Default is set to the
// first value in the associated enum (or zero if the also enum dependency
// is also unresolvable). The protoreflect.FieldDescriptor.DefaultEnumValue
// is populated with a placeholder.
// • Resolving the extended message type for an extension field.
// • Resolving the input or output message type for a service method.
//
// If the unresolved dependency uses a relative name,
// then the placeholder will contain an invalid FullName with a "*." prefix,
// indicating that the starting prefix of the full name is unknown.
AllowUnresolvable bool
}
// NewFile creates a new protoreflect.FileDescriptor from the provided
// file descriptor message. See FileOptions.New for more information.
func NewFile(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
return FileOptions{}.New(fd, r)
}
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. See FileOptions.NewFiles for more information.
func NewFiles(fd *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
return FileOptions{}.NewFiles(fd)
}
// New creates a new protoreflect.FileDescriptor from the provided
// file descriptor message. The file must represent a valid proto file according
// to protobuf semantics. The returned descriptor is a deep copy of the input.
//
// Any imported files, enum types, or message types referenced in the file are
// resolved using the provided registry. When looking up an import file path,
// the path must be unique. The newly created file descriptor is not registered
// back into the provided file registry.
func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
if r == nil {
r = (*protoregistry.Files)(nil) // empty resolver
}
// Handle the file descriptor content.
f := &filedesc.File{L2: &filedesc.FileL2{}}
switch fd.GetSyntax() {
case "proto2", "":
f.L1.Syntax = protoreflect.Proto2
case "proto3":
f.L1.Syntax = protoreflect.Proto3
default:
return nil, errors.New("invalid syntax: %q", fd.GetSyntax())
}
f.L1.Path = fd.GetName()
if f.L1.Path == "" {
return nil, errors.New("file path must be populated")
}
f.L1.Package = protoreflect.FullName(fd.GetPackage())
if !f.L1.Package.IsValid() && f.L1.Package != "" {
return nil, errors.New("invalid package: %q", f.L1.Package)
}
if opts := fd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FileOptions)
f.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
f.L2.Imports = make(filedesc.FileImports, len(fd.GetDependency()))
for _, i := range fd.GetPublicDependency() {
if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsPublic {
return nil, errors.New("invalid or duplicate public import index: %d", i)
}
f.L2.Imports[i].IsPublic = true
}
for _, i := range fd.GetWeakDependency() {
if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsWeak {
return nil, errors.New("invalid or duplicate weak import index: %d", i)
}
f.L2.Imports[i].IsWeak = true
}
imps := importSet{f.Path(): true}
for i, path := range fd.GetDependency() {
imp := &f.L2.Imports[i]
f, err := r.FindFileByPath(path)
if err == protoregistry.NotFound && (o.AllowUnresolvable || imp.IsWeak) {
f = filedesc.PlaceholderFile(path)
} else if err != nil {
return nil, errors.New("could not resolve import %q: %v", path, err)
}
imp.FileDescriptor = f
if imps[imp.Path()] {
return nil, errors.New("already imported %q", path)
}
imps[imp.Path()] = true
}
for i := range fd.GetDependency() {
imp := &f.L2.Imports[i]
imps.importPublic(imp.Imports())
}
// Handle source locations.
f.L2.Locations.File = f
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
var l protoreflect.SourceLocation
// TODO: Validate that the path points to an actual declaration?
l.Path = protoreflect.SourcePath(loc.GetPath())
s := loc.GetSpan()
switch len(s) {
case 3:
l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[0]), int(s[2])
case 4:
l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[2]), int(s[3])
default:
return nil, errors.New("invalid span: %v", s)
}
// TODO: Validate that the span information is sensible?
// See https://github.com/protocolbuffers/protobuf/issues/6378.
if false && (l.EndLine < l.StartLine || l.StartLine < 0 || l.StartColumn < 0 || l.EndColumn < 0 ||
(l.StartLine == l.EndLine && l.EndColumn <= l.StartColumn)) {
return nil, errors.New("invalid span: %v", s)
}
l.LeadingDetachedComments = loc.GetLeadingDetachedComments()
l.LeadingComments = loc.GetLeadingComments()
l.TrailingComments = loc.GetTrailingComments()
f.L2.Locations.List = append(f.L2.Locations.List, l)
}
// Step 1: Allocate and derive the names for all declarations.
// This copies all fields from the descriptor proto except:
// google.protobuf.FieldDescriptorProto.type_name
// google.protobuf.FieldDescriptorProto.default_value
// google.protobuf.FieldDescriptorProto.oneof_index
// google.protobuf.FieldDescriptorProto.extendee
// google.protobuf.MethodDescriptorProto.input
// google.protobuf.MethodDescriptorProto.output
var err error
sb := new(strs.Builder)
r1 := make(descsByName)
if f.L1.Enums.List, err = r1.initEnumDeclarations(fd.GetEnumType(), f, sb); err != nil {
return nil, err
}
if f.L1.Messages.List, err = r1.initMessagesDeclarations(fd.GetMessageType(), f, sb); err != nil {
return nil, err
}
if f.L1.Extensions.List, err = r1.initExtensionDeclarations(fd.GetExtension(), f, sb); err != nil {
return nil, err
}
if f.L1.Services.List, err = r1.initServiceDeclarations(fd.GetService(), f, sb); err != nil {
return nil, err
}
// Step 2: Resolve every dependency reference not handled by step 1.
r2 := &resolver{local: r1, remote: r, imports: imps, allowUnresolvable: o.AllowUnresolvable}
if err := r2.resolveMessageDependencies(f.L1.Messages.List, fd.GetMessageType()); err != nil {
return nil, err
}
if err := r2.resolveExtensionDependencies(f.L1.Extensions.List, fd.GetExtension()); err != nil {
return nil, err
}
if err := r2.resolveServiceDependencies(f.L1.Services.List, fd.GetService()); err != nil {
return nil, err
}
// Step 3: Validate every enum, message, and extension declaration.
if err := validateEnumDeclarations(f.L1.Enums.List, fd.GetEnumType()); err != nil {
return nil, err
}
if err := validateMessageDeclarations(f.L1.Messages.List, fd.GetMessageType()); err != nil {
return nil, err
}
if err := validateExtensionDeclarations(f.L1.Extensions.List, fd.GetExtension()); err != nil {
return nil, err
}
return f, nil
}
type importSet map[string]bool
func (is importSet) importPublic(imps protoreflect.FileImports) {
for i := 0; i < imps.Len(); i++ {
if imp := imps.Get(i); imp.IsPublic {
is[imp.Path()] = true
is.importPublic(imp.Imports())
}
}
}
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. The descriptor set must include only
// valid files according to protobuf semantics. The returned descriptors
// are a deep copy of the input.
func (o FileOptions) NewFiles(fds *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
files := make(map[string]*descriptorpb.FileDescriptorProto)
for _, fd := range fds.File {
if _, ok := files[fd.GetName()]; ok {
return nil, errors.New("file appears multiple times: %q", fd.GetName())
}
files[fd.GetName()] = fd
}
r := &protoregistry.Files{}
for _, fd := range files {
if err := o.addFileDeps(r, fd, files); err != nil {
return nil, err
}
}
return r, nil
}
func (o FileOptions) addFileDeps(r *protoregistry.Files, fd *descriptorpb.FileDescriptorProto, files map[string]*descriptorpb.FileDescriptorProto) error {
// Set the entry to nil while descending into a file's dependencies to detect cycles.
files[fd.GetName()] = nil
for _, dep := range fd.Dependency {
depfd, ok := files[dep]
if depfd == nil {
if ok {
return errors.New("import cycle in file: %q", dep)
}
continue
}
if err := o.addFileDeps(r, depfd, files); err != nil {
return err
}
}
// Delete the entry once dependencies are processed.
delete(files, fd.GetName())
f, err := o.New(fd, r)
if err != nil {
return err
}
return r.RegisterFile(f)
}

View file

@ -0,0 +1,248 @@
// 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 protodesc
import (
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
type descsByName map[protoreflect.FullName]protoreflect.Descriptor
func (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (es []filedesc.Enum, err error) {
es = make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers
for i, ed := range eds {
e := &es[i]
e.L2 = new(filedesc.EnumL2)
if e.L0, err = r.makeBase(e, parent, ed.GetName(), i, sb); err != nil {
return nil, err
}
if opts := ed.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.EnumOptions)
e.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
for _, s := range ed.GetReservedName() {
e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s))
}
for _, rr := range ed.GetReservedRange() {
e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{
protoreflect.EnumNumber(rr.GetStart()),
protoreflect.EnumNumber(rr.GetEnd()),
})
}
if e.L2.Values.List, err = r.initEnumValuesFromDescriptorProto(ed.GetValue(), e, sb); err != nil {
return nil, err
}
}
return es, nil
}
func (r descsByName) initEnumValuesFromDescriptorProto(vds []*descriptorpb.EnumValueDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (vs []filedesc.EnumValue, err error) {
vs = make([]filedesc.EnumValue, len(vds)) // allocate up-front to ensure stable pointers
for i, vd := range vds {
v := &vs[i]
if v.L0, err = r.makeBase(v, parent, vd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := vd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.EnumValueOptions)
v.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
v.L1.Number = protoreflect.EnumNumber(vd.GetNumber())
}
return vs, nil
}
func (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Message, err error) {
ms = make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers
for i, md := range mds {
m := &ms[i]
m.L2 = new(filedesc.MessageL2)
if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
return nil, err
}
if opts := md.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.MessageOptions)
m.L2.Options = func() protoreflect.ProtoMessage { return opts }
m.L1.IsMapEntry = opts.GetMapEntry()
m.L1.IsMessageSet = opts.GetMessageSetWireFormat()
}
for _, s := range md.GetReservedName() {
m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s))
}
for _, rr := range md.GetReservedRange() {
m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{
protoreflect.FieldNumber(rr.GetStart()),
protoreflect.FieldNumber(rr.GetEnd()),
})
}
for _, xr := range md.GetExtensionRange() {
m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
protoreflect.FieldNumber(xr.GetStart()),
protoreflect.FieldNumber(xr.GetEnd()),
})
var optsFunc func() protoreflect.ProtoMessage
if opts := xr.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.ExtensionRangeOptions)
optsFunc = func() protoreflect.ProtoMessage { return opts }
}
m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc)
}
if m.L2.Fields.List, err = r.initFieldsFromDescriptorProto(md.GetField(), m, sb); err != nil {
return nil, err
}
if m.L2.Oneofs.List, err = r.initOneofsFromDescriptorProto(md.GetOneofDecl(), m, sb); err != nil {
return nil, err
}
if m.L1.Enums.List, err = r.initEnumDeclarations(md.GetEnumType(), m, sb); err != nil {
return nil, err
}
if m.L1.Messages.List, err = r.initMessagesDeclarations(md.GetNestedType(), m, sb); err != nil {
return nil, err
}
if m.L1.Extensions.List, err = r.initExtensionDeclarations(md.GetExtension(), m, sb); err != nil {
return nil, err
}
}
return ms, nil
}
func (r descsByName) initFieldsFromDescriptorProto(fds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (fs []filedesc.Field, err error) {
fs = make([]filedesc.Field, len(fds)) // allocate up-front to ensure stable pointers
for i, fd := range fds {
f := &fs[i]
if f.L0, err = r.makeBase(f, parent, fd.GetName(), i, sb); err != nil {
return nil, err
}
f.L1.IsProto3Optional = fd.GetProto3Optional()
if opts := fd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
f.L1.Options = func() protoreflect.ProtoMessage { return opts }
f.L1.IsWeak = opts.GetWeak()
f.L1.HasPacked = opts.Packed != nil
f.L1.IsPacked = opts.GetPacked()
}
f.L1.Number = protoreflect.FieldNumber(fd.GetNumber())
f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel())
if fd.Type != nil {
f.L1.Kind = protoreflect.Kind(fd.GetType())
}
if fd.JsonName != nil {
f.L1.StringName.InitJSON(fd.GetJsonName())
}
}
return fs, nil
}
func (r descsByName) initOneofsFromDescriptorProto(ods []*descriptorpb.OneofDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (os []filedesc.Oneof, err error) {
os = make([]filedesc.Oneof, len(ods)) // allocate up-front to ensure stable pointers
for i, od := range ods {
o := &os[i]
if o.L0, err = r.makeBase(o, parent, od.GetName(), i, sb); err != nil {
return nil, err
}
if opts := od.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.OneofOptions)
o.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
}
return os, nil
}
func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (xs []filedesc.Extension, err error) {
xs = make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers
for i, xd := range xds {
x := &xs[i]
x.L2 = new(filedesc.ExtensionL2)
if x.L0, err = r.makeBase(x, parent, xd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := xd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
x.L2.Options = func() protoreflect.ProtoMessage { return opts }
x.L2.IsPacked = opts.GetPacked()
}
x.L1.Number = protoreflect.FieldNumber(xd.GetNumber())
x.L1.Cardinality = protoreflect.Cardinality(xd.GetLabel())
if xd.Type != nil {
x.L1.Kind = protoreflect.Kind(xd.GetType())
}
if xd.JsonName != nil {
x.L2.StringName.InitJSON(xd.GetJsonName())
}
}
return xs, nil
}
func (r descsByName) initServiceDeclarations(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ss []filedesc.Service, err error) {
ss = make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers
for i, sd := range sds {
s := &ss[i]
s.L2 = new(filedesc.ServiceL2)
if s.L0, err = r.makeBase(s, parent, sd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := sd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.ServiceOptions)
s.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
if s.L2.Methods.List, err = r.initMethodsFromDescriptorProto(sd.GetMethod(), s, sb); err != nil {
return nil, err
}
}
return ss, nil
}
func (r descsByName) initMethodsFromDescriptorProto(mds []*descriptorpb.MethodDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Method, err error) {
ms = make([]filedesc.Method, len(mds)) // allocate up-front to ensure stable pointers
for i, md := range mds {
m := &ms[i]
if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
return nil, err
}
if opts := md.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.MethodOptions)
m.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
m.L1.IsStreamingClient = md.GetClientStreaming()
m.L1.IsStreamingServer = md.GetServerStreaming()
}
return ms, nil
}
func (r descsByName) makeBase(child, parent protoreflect.Descriptor, name string, idx int, sb *strs.Builder) (filedesc.BaseL0, error) {
if !protoreflect.Name(name).IsValid() {
return filedesc.BaseL0{}, errors.New("descriptor %q has an invalid nested name: %q", parent.FullName(), name)
}
// Derive the full name of the child.
// Note that enum values are a sibling to the enum parent in the namespace.
var fullName protoreflect.FullName
if _, ok := parent.(protoreflect.EnumDescriptor); ok {
fullName = sb.AppendFullName(parent.FullName().Parent(), protoreflect.Name(name))
} else {
fullName = sb.AppendFullName(parent.FullName(), protoreflect.Name(name))
}
if _, ok := r[fullName]; ok {
return filedesc.BaseL0{}, errors.New("descriptor %q already declared", fullName)
}
r[fullName] = child
// TODO: Verify that the full name does not already exist in the resolver?
// This is not as critical since most usages of NewFile will register
// the created file back into the registry, which will perform this check.
return filedesc.BaseL0{
FullName: fullName,
ParentFile: parent.ParentFile().(*filedesc.File),
Parent: parent,
Index: idx,
}, nil
}

View file

@ -0,0 +1,286 @@
// 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 protodesc
import (
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)
// resolver is a wrapper around a local registry of declarations within the file
// and the remote resolver. The remote resolver is restricted to only return
// descriptors that have been imported.
type resolver struct {
local descsByName
remote Resolver
imports importSet
allowUnresolvable bool
}
func (r *resolver) resolveMessageDependencies(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) (err error) {
for i, md := range mds {
m := &ms[i]
for j, fd := range md.GetField() {
f := &m.L2.Fields.List[j]
if f.L1.Cardinality == protoreflect.Required {
m.L2.RequiredNumbers.List = append(m.L2.RequiredNumbers.List, f.L1.Number)
}
if fd.OneofIndex != nil {
k := int(fd.GetOneofIndex())
if !(0 <= k && k < len(md.GetOneofDecl())) {
return errors.New("message field %q has an invalid oneof index: %d", f.FullName(), k)
}
o := &m.L2.Oneofs.List[k]
f.L1.ContainingOneof = o
o.L1.Fields.List = append(o.L1.Fields.List, f)
}
if f.L1.Kind, f.L1.Enum, f.L1.Message, err = r.findTarget(f.Kind(), f.Parent().FullName(), partialName(fd.GetTypeName()), f.IsWeak()); err != nil {
return errors.New("message field %q cannot resolve type: %v", f.FullName(), err)
}
if fd.DefaultValue != nil {
v, ev, err := unmarshalDefault(fd.GetDefaultValue(), f, r.allowUnresolvable)
if err != nil {
return errors.New("message field %q has invalid default: %v", f.FullName(), err)
}
f.L1.Default = filedesc.DefaultValue(v, ev)
}
}
if err := r.resolveMessageDependencies(m.L1.Messages.List, md.GetNestedType()); err != nil {
return err
}
if err := r.resolveExtensionDependencies(m.L1.Extensions.List, md.GetExtension()); err != nil {
return err
}
}
return nil
}
func (r *resolver) resolveExtensionDependencies(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) (err error) {
for i, xd := range xds {
x := &xs[i]
if x.L1.Extendee, err = r.findMessageDescriptor(x.Parent().FullName(), partialName(xd.GetExtendee()), false); err != nil {
return errors.New("extension field %q cannot resolve extendee: %v", x.FullName(), err)
}
if x.L1.Kind, x.L2.Enum, x.L2.Message, err = r.findTarget(x.Kind(), x.Parent().FullName(), partialName(xd.GetTypeName()), false); err != nil {
return errors.New("extension field %q cannot resolve type: %v", x.FullName(), err)
}
if xd.DefaultValue != nil {
v, ev, err := unmarshalDefault(xd.GetDefaultValue(), x, r.allowUnresolvable)
if err != nil {
return errors.New("extension field %q has invalid default: %v", x.FullName(), err)
}
x.L2.Default = filedesc.DefaultValue(v, ev)
}
}
return nil
}
func (r *resolver) resolveServiceDependencies(ss []filedesc.Service, sds []*descriptorpb.ServiceDescriptorProto) (err error) {
for i, sd := range sds {
s := &ss[i]
for j, md := range sd.GetMethod() {
m := &s.L2.Methods.List[j]
m.L1.Input, err = r.findMessageDescriptor(m.Parent().FullName(), partialName(md.GetInputType()), false)
if err != nil {
return errors.New("service method %q cannot resolve input: %v", m.FullName(), err)
}
m.L1.Output, err = r.findMessageDescriptor(s.FullName(), partialName(md.GetOutputType()), false)
if err != nil {
return errors.New("service method %q cannot resolve output: %v", m.FullName(), err)
}
}
}
return nil
}
// findTarget finds an enum or message descriptor if k is an enum, message,
// group, or unknown. If unknown, and the name could be resolved, the kind
// returned kind is set based on the type of the resolved descriptor.
func (r *resolver) findTarget(k protoreflect.Kind, scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.Kind, protoreflect.EnumDescriptor, protoreflect.MessageDescriptor, error) {
switch k {
case protoreflect.EnumKind:
ed, err := r.findEnumDescriptor(scope, ref, isWeak)
if err != nil {
return 0, nil, nil, err
}
return k, ed, nil, nil
case protoreflect.MessageKind, protoreflect.GroupKind:
md, err := r.findMessageDescriptor(scope, ref, isWeak)
if err != nil {
return 0, nil, nil, err
}
return k, nil, md, nil
case 0:
// Handle unspecified kinds (possible with parsers that operate
// on a per-file basis without knowledge of dependencies).
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return k, filedesc.PlaceholderEnum(ref.FullName()), filedesc.PlaceholderMessage(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return 0, nil, nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return 0, nil, nil, err
}
switch d := d.(type) {
case protoreflect.EnumDescriptor:
return protoreflect.EnumKind, d, nil, nil
case protoreflect.MessageDescriptor:
return protoreflect.MessageKind, nil, d, nil
default:
return 0, nil, nil, errors.New("unknown kind")
}
default:
if ref != "" {
return 0, nil, nil, errors.New("target name cannot be specified for %v", k)
}
if !k.IsValid() {
return 0, nil, nil, errors.New("invalid kind: %d", k)
}
return k, nil, nil, nil
}
}
// findDescriptor finds the descriptor by name,
// which may be a relative name within some scope.
//
// Suppose the scope was "fizz.buzz" and the reference was "Foo.Bar",
// then the following full names are searched:
// * fizz.buzz.Foo.Bar
// * fizz.Foo.Bar
// * Foo.Bar
func (r *resolver) findDescriptor(scope protoreflect.FullName, ref partialName) (protoreflect.Descriptor, error) {
if !ref.IsValid() {
return nil, errors.New("invalid name reference: %q", ref)
}
if ref.IsFull() {
scope, ref = "", ref[1:]
}
var foundButNotImported protoreflect.Descriptor
for {
// Derive the full name to search.
s := protoreflect.FullName(ref)
if scope != "" {
s = scope + "." + s
}
// Check the current file for the descriptor.
if d, ok := r.local[s]; ok {
return d, nil
}
// Check the remote registry for the descriptor.
d, err := r.remote.FindDescriptorByName(s)
if err == nil {
// Only allow descriptors covered by one of the imports.
if r.imports[d.ParentFile().Path()] {
return d, nil
}
foundButNotImported = d
} else if err != protoregistry.NotFound {
return nil, errors.Wrap(err, "%q", s)
}
// Continue on at a higher level of scoping.
if scope == "" {
if d := foundButNotImported; d != nil {
return nil, errors.New("resolved %q, but %q is not imported", d.FullName(), d.ParentFile().Path())
}
return nil, protoregistry.NotFound
}
scope = scope.Parent()
}
}
func (r *resolver) findEnumDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.EnumDescriptor, error) {
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return filedesc.PlaceholderEnum(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return nil, err
}
ed, ok := d.(protoreflect.EnumDescriptor)
if !ok {
return nil, errors.New("resolved %q, but it is not an enum", d.FullName())
}
return ed, nil
}
func (r *resolver) findMessageDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.MessageDescriptor, error) {
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return filedesc.PlaceholderMessage(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return nil, err
}
md, ok := d.(protoreflect.MessageDescriptor)
if !ok {
return nil, errors.New("resolved %q, but it is not an message", d.FullName())
}
return md, nil
}
// partialName is the partial name. A leading dot means that the name is full,
// otherwise the name is relative to some current scope.
// See google.protobuf.FieldDescriptorProto.type_name.
type partialName string
func (s partialName) IsFull() bool {
return len(s) > 0 && s[0] == '.'
}
func (s partialName) IsValid() bool {
if s.IsFull() {
return protoreflect.FullName(s[1:]).IsValid()
}
return protoreflect.FullName(s).IsValid()
}
const unknownPrefix = "*."
// FullName converts the partial name to a full name on a best-effort basis.
// If relative, it creates an invalid full name, using a "*." prefix
// to indicate that the start of the full name is unknown.
func (s partialName) FullName() protoreflect.FullName {
if s.IsFull() {
return protoreflect.FullName(s[1:])
}
return protoreflect.FullName(unknownPrefix + s)
}
func unmarshalDefault(s string, fd protoreflect.FieldDescriptor, allowUnresolvable bool) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
var evs protoreflect.EnumValueDescriptors
if fd.Enum() != nil {
evs = fd.Enum().Values()
}
v, ev, err := defval.Unmarshal(s, fd.Kind(), evs, defval.Descriptor)
if err != nil && allowUnresolvable && evs != nil && protoreflect.Name(s).IsValid() {
v = protoreflect.ValueOfEnum(0)
if evs.Len() > 0 {
v = protoreflect.ValueOfEnum(evs.Get(0).Number())
}
ev = filedesc.PlaceholderEnumValue(fd.Enum().FullName().Parent().Append(protoreflect.Name(s)))
} else if err != nil {
return v, ev, err
}
if fd.Syntax() == protoreflect.Proto3 {
return v, ev, errors.New("cannot be specified under proto3 semantics")
}
if fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind || fd.Cardinality() == protoreflect.Repeated {
return v, ev, errors.New("cannot be specified on composite types")
}
return v, ev, nil
}

View file

@ -0,0 +1,374 @@
// 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 protodesc
import (
"strings"
"unicode"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
func validateEnumDeclarations(es []filedesc.Enum, eds []*descriptorpb.EnumDescriptorProto) error {
for i, ed := range eds {
e := &es[i]
if err := e.L2.ReservedNames.CheckValid(); err != nil {
return errors.New("enum %q reserved names has %v", e.FullName(), err)
}
if err := e.L2.ReservedRanges.CheckValid(); err != nil {
return errors.New("enum %q reserved ranges has %v", e.FullName(), err)
}
if len(ed.GetValue()) == 0 {
return errors.New("enum %q must contain at least one value declaration", e.FullName())
}
allowAlias := ed.GetOptions().GetAllowAlias()
foundAlias := false
for i := 0; i < e.Values().Len(); i++ {
v1 := e.Values().Get(i)
if v2 := e.Values().ByNumber(v1.Number()); v1 != v2 {
foundAlias = true
if !allowAlias {
return errors.New("enum %q has conflicting non-aliased values on number %d: %q with %q", e.FullName(), v1.Number(), v1.Name(), v2.Name())
}
}
}
if allowAlias && !foundAlias {
return errors.New("enum %q allows aliases, but none were found", e.FullName())
}
if e.Syntax() == protoreflect.Proto3 {
if v := e.Values().Get(0); v.Number() != 0 {
return errors.New("enum %q using proto3 semantics must have zero number for the first value", v.FullName())
}
// Verify that value names in proto3 do not conflict if the
// case-insensitive prefix is removed.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:4991-5055
names := map[string]protoreflect.EnumValueDescriptor{}
prefix := strings.Replace(strings.ToLower(string(e.Name())), "_", "", -1)
for i := 0; i < e.Values().Len(); i++ {
v1 := e.Values().Get(i)
s := strs.EnumValueName(strs.TrimEnumPrefix(string(v1.Name()), prefix))
if v2, ok := names[s]; ok && v1.Number() != v2.Number() {
return errors.New("enum %q using proto3 semantics has conflict: %q with %q", e.FullName(), v1.Name(), v2.Name())
}
names[s] = v1
}
}
for j, vd := range ed.GetValue() {
v := &e.L2.Values.List[j]
if vd.Number == nil {
return errors.New("enum value %q must have a specified number", v.FullName())
}
if e.L2.ReservedNames.Has(v.Name()) {
return errors.New("enum value %q must not use reserved name", v.FullName())
}
if e.L2.ReservedRanges.Has(v.Number()) {
return errors.New("enum value %q must not use reserved number %d", v.FullName(), v.Number())
}
}
}
return nil
}
func validateMessageDeclarations(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error {
for i, md := range mds {
m := &ms[i]
// Handle the message descriptor itself.
isMessageSet := md.GetOptions().GetMessageSetWireFormat()
if err := m.L2.ReservedNames.CheckValid(); err != nil {
return errors.New("message %q reserved names has %v", m.FullName(), err)
}
if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil {
return errors.New("message %q reserved ranges has %v", m.FullName(), err)
}
if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil {
return errors.New("message %q extension ranges has %v", m.FullName(), err)
}
if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil {
return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err)
}
for i := 0; i < m.Fields().Len(); i++ {
f1 := m.Fields().Get(i)
if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 {
return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
}
}
if isMessageSet && !flags.ProtoLegacy {
return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
}
if isMessageSet && (m.Syntax() != protoreflect.Proto2 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
}
if m.Syntax() == protoreflect.Proto3 {
if m.ExtensionRanges().Len() > 0 {
return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName())
}
// Verify that field names in proto3 do not conflict if lowercased
// with all underscores removed.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:5830-5847
names := map[string]protoreflect.FieldDescriptor{}
for i := 0; i < m.Fields().Len(); i++ {
f1 := m.Fields().Get(i)
s := strings.Replace(strings.ToLower(string(f1.Name())), "_", "", -1)
if f2, ok := names[s]; ok {
return errors.New("message %q using proto3 semantics has conflict: %q with %q", m.FullName(), f1.Name(), f2.Name())
}
names[s] = f1
}
}
for j, fd := range md.GetField() {
f := &m.L2.Fields.List[j]
if m.L2.ReservedNames.Has(f.Name()) {
return errors.New("message field %q must not use reserved name", f.FullName())
}
if !f.Number().IsValid() {
return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number())
}
if !f.Cardinality().IsValid() {
return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality())
}
if m.L2.ReservedRanges.Has(f.Number()) {
return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number())
}
if m.L2.ExtensionRanges.Has(f.Number()) {
return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number())
}
if fd.Extendee != nil {
return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
}
if f.L1.IsProto3Optional {
if f.Syntax() != protoreflect.Proto3 {
return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName())
}
if f.Cardinality() != protoreflect.Optional {
return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName())
}
if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 {
return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName())
}
}
if f.IsWeak() && !flags.ProtoLegacy {
return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName())
}
if f.IsWeak() && (f.Syntax() != protoreflect.Proto2 || !isOptionalMessage(f) || f.ContainingOneof() != nil) {
return errors.New("message field %q may only be weak for an optional message", f.FullName())
}
if f.IsPacked() && !isPackable(f) {
return errors.New("message field %q is not packable", f.FullName())
}
if err := checkValidGroup(f); err != nil {
return errors.New("message field %q is an invalid group: %v", f.FullName(), err)
}
if err := checkValidMap(f); err != nil {
return errors.New("message field %q is an invalid map: %v", f.FullName(), err)
}
if f.Syntax() == protoreflect.Proto3 {
if f.Cardinality() == protoreflect.Required {
return errors.New("message field %q using proto3 semantics cannot be required", f.FullName())
}
if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().Syntax() != protoreflect.Proto3 {
return errors.New("message field %q using proto3 semantics may only depend on a proto3 enum", f.FullName())
}
}
}
seenSynthetic := false // synthetic oneofs for proto3 optional must come after real oneofs
for j := range md.GetOneofDecl() {
o := &m.L2.Oneofs.List[j]
if o.Fields().Len() == 0 {
return errors.New("message oneof %q must contain at least one field declaration", o.FullName())
}
if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) {
return errors.New("message oneof %q must have consecutively declared fields", o.FullName())
}
if o.IsSynthetic() {
seenSynthetic = true
continue
}
if !o.IsSynthetic() && seenSynthetic {
return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName())
}
for i := 0; i < o.Fields().Len(); i++ {
f := o.Fields().Get(i)
if f.Cardinality() != protoreflect.Optional {
return errors.New("message field %q belongs in a oneof and must be optional", f.FullName())
}
if f.IsWeak() {
return errors.New("message field %q belongs in a oneof and must not be a weak reference", f.FullName())
}
}
}
if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil {
return err
}
if err := validateMessageDeclarations(m.L1.Messages.List, md.GetNestedType()); err != nil {
return err
}
if err := validateExtensionDeclarations(m.L1.Extensions.List, md.GetExtension()); err != nil {
return err
}
}
return nil
}
func validateExtensionDeclarations(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
for i, xd := range xds {
x := &xs[i]
// NOTE: Avoid using the IsValid method since extensions to MessageSet
// may have a field number higher than normal. This check only verifies
// that the number is not negative or reserved. We check again later
// if we know that the extendee is definitely not a MessageSet.
if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) {
return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
}
if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required {
return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality())
}
if xd.JsonName != nil {
// A bug in older versions of protoc would always populate the
// "json_name" option for extensions when it is meaningless.
// When it did so, it would always use the camel-cased field name.
if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) {
return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName())
}
}
if xd.OneofIndex != nil {
return errors.New("extension field %q may not be part of a oneof", x.FullName())
}
if md := x.ContainingMessage(); !md.IsPlaceholder() {
if !md.ExtensionRanges().Has(x.Number()) {
return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number())
}
isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
if isMessageSet && !isOptionalMessage(x) {
return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName())
}
if !isMessageSet && !x.Number().IsValid() {
return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
}
}
if xd.GetOptions().GetWeak() {
return errors.New("extension field %q cannot be a weak reference", x.FullName())
}
if x.IsPacked() && !isPackable(x) {
return errors.New("extension field %q is not packable", x.FullName())
}
if err := checkValidGroup(x); err != nil {
return errors.New("extension field %q is an invalid group: %v", x.FullName(), err)
}
if md := x.Message(); md != nil && md.IsMapEntry() {
return errors.New("extension field %q cannot be a map entry", x.FullName())
}
if x.Syntax() == protoreflect.Proto3 {
switch x.ContainingMessage().FullName() {
case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
default:
return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName())
}
}
}
return nil
}
// isOptionalMessage reports whether this is an optional message.
// If the kind is unknown, it is assumed to be a message.
func isOptionalMessage(fd protoreflect.FieldDescriptor) bool {
return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional
}
// isPackable checks whether the pack option can be specified.
func isPackable(fd protoreflect.FieldDescriptor) bool {
switch fd.Kind() {
case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
return false
}
return fd.IsList()
}
// checkValidGroup reports whether fd is a valid group according to the same
// rules that protoc imposes.
func checkValidGroup(fd protoreflect.FieldDescriptor) error {
md := fd.Message()
switch {
case fd.Kind() != protoreflect.GroupKind:
return nil
case fd.Syntax() != protoreflect.Proto2:
return errors.New("invalid under proto2 semantics")
case md == nil || md.IsPlaceholder():
return errors.New("message must be resolvable")
case fd.FullName().Parent() != md.FullName().Parent():
return errors.New("message and field must be declared in the same scope")
case !unicode.IsUpper(rune(md.Name()[0])):
return errors.New("message name must start with an uppercase")
case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))):
return errors.New("field name must be lowercased form of the message name")
}
return nil
}
// checkValidMap checks whether the field is a valid map according to the same
// rules that protoc imposes.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115
func checkValidMap(fd protoreflect.FieldDescriptor) error {
md := fd.Message()
switch {
case md == nil || !md.IsMapEntry():
return nil
case fd.FullName().Parent() != md.FullName().Parent():
return errors.New("message and field must be declared in the same scope")
case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))):
return errors.New("incorrect implicit map entry name")
case fd.Cardinality() != protoreflect.Repeated:
return errors.New("field must be repeated")
case md.Fields().Len() != 2:
return errors.New("message must have exactly two fields")
case md.ExtensionRanges().Len() > 0:
return errors.New("message must not have any extension ranges")
case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0:
return errors.New("message must not have any nested declarations")
}
kf := md.Fields().Get(0)
vf := md.Fields().Get(1)
switch {
case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault():
return errors.New("invalid key field")
case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault():
return errors.New("invalid value field")
}
switch kf.Kind() {
case protoreflect.BoolKind: // bool
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64
case protoreflect.StringKind: // string
default:
return errors.New("invalid key kind: %v", kf.Kind())
}
if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 {
return errors.New("map enum value must have zero number for the first value")
}
return nil
}

View file

@ -0,0 +1,252 @@
// 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 protodesc
import (
"fmt"
"strings"
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
// ToFileDescriptorProto copies a protoreflect.FileDescriptor into a
// google.protobuf.FileDescriptorProto message.
func ToFileDescriptorProto(file protoreflect.FileDescriptor) *descriptorpb.FileDescriptorProto {
p := &descriptorpb.FileDescriptorProto{
Name: proto.String(file.Path()),
Options: proto.Clone(file.Options()).(*descriptorpb.FileOptions),
}
if file.Package() != "" {
p.Package = proto.String(string(file.Package()))
}
for i, imports := 0, file.Imports(); i < imports.Len(); i++ {
imp := imports.Get(i)
p.Dependency = append(p.Dependency, imp.Path())
if imp.IsPublic {
p.PublicDependency = append(p.PublicDependency, int32(i))
}
if imp.IsWeak {
p.WeakDependency = append(p.WeakDependency, int32(i))
}
}
for i, locs := 0, file.SourceLocations(); i < locs.Len(); i++ {
loc := locs.Get(i)
l := &descriptorpb.SourceCodeInfo_Location{}
l.Path = append(l.Path, loc.Path...)
if loc.StartLine == loc.EndLine {
l.Span = []int32{int32(loc.StartLine), int32(loc.StartColumn), int32(loc.EndColumn)}
} else {
l.Span = []int32{int32(loc.StartLine), int32(loc.StartColumn), int32(loc.EndLine), int32(loc.EndColumn)}
}
l.LeadingDetachedComments = append([]string(nil), loc.LeadingDetachedComments...)
if loc.LeadingComments != "" {
l.LeadingComments = proto.String(loc.LeadingComments)
}
if loc.TrailingComments != "" {
l.TrailingComments = proto.String(loc.TrailingComments)
}
if p.SourceCodeInfo == nil {
p.SourceCodeInfo = &descriptorpb.SourceCodeInfo{}
}
p.SourceCodeInfo.Location = append(p.SourceCodeInfo.Location, l)
}
for i, messages := 0, file.Messages(); i < messages.Len(); i++ {
p.MessageType = append(p.MessageType, ToDescriptorProto(messages.Get(i)))
}
for i, enums := 0, file.Enums(); i < enums.Len(); i++ {
p.EnumType = append(p.EnumType, ToEnumDescriptorProto(enums.Get(i)))
}
for i, services := 0, file.Services(); i < services.Len(); i++ {
p.Service = append(p.Service, ToServiceDescriptorProto(services.Get(i)))
}
for i, exts := 0, file.Extensions(); i < exts.Len(); i++ {
p.Extension = append(p.Extension, ToFieldDescriptorProto(exts.Get(i)))
}
if syntax := file.Syntax(); syntax != protoreflect.Proto2 {
p.Syntax = proto.String(file.Syntax().String())
}
return p
}
// ToDescriptorProto copies a protoreflect.MessageDescriptor into a
// google.protobuf.DescriptorProto message.
func ToDescriptorProto(message protoreflect.MessageDescriptor) *descriptorpb.DescriptorProto {
p := &descriptorpb.DescriptorProto{
Name: proto.String(string(message.Name())),
Options: proto.Clone(message.Options()).(*descriptorpb.MessageOptions),
}
for i, fields := 0, message.Fields(); i < fields.Len(); i++ {
p.Field = append(p.Field, ToFieldDescriptorProto(fields.Get(i)))
}
for i, exts := 0, message.Extensions(); i < exts.Len(); i++ {
p.Extension = append(p.Extension, ToFieldDescriptorProto(exts.Get(i)))
}
for i, messages := 0, message.Messages(); i < messages.Len(); i++ {
p.NestedType = append(p.NestedType, ToDescriptorProto(messages.Get(i)))
}
for i, enums := 0, message.Enums(); i < enums.Len(); i++ {
p.EnumType = append(p.EnumType, ToEnumDescriptorProto(enums.Get(i)))
}
for i, xranges := 0, message.ExtensionRanges(); i < xranges.Len(); i++ {
xrange := xranges.Get(i)
p.ExtensionRange = append(p.ExtensionRange, &descriptorpb.DescriptorProto_ExtensionRange{
Start: proto.Int32(int32(xrange[0])),
End: proto.Int32(int32(xrange[1])),
Options: proto.Clone(message.ExtensionRangeOptions(i)).(*descriptorpb.ExtensionRangeOptions),
})
}
for i, oneofs := 0, message.Oneofs(); i < oneofs.Len(); i++ {
p.OneofDecl = append(p.OneofDecl, ToOneofDescriptorProto(oneofs.Get(i)))
}
for i, ranges := 0, message.ReservedRanges(); i < ranges.Len(); i++ {
rrange := ranges.Get(i)
p.ReservedRange = append(p.ReservedRange, &descriptorpb.DescriptorProto_ReservedRange{
Start: proto.Int32(int32(rrange[0])),
End: proto.Int32(int32(rrange[1])),
})
}
for i, names := 0, message.ReservedNames(); i < names.Len(); i++ {
p.ReservedName = append(p.ReservedName, string(names.Get(i)))
}
return p
}
// ToFieldDescriptorProto copies a protoreflect.FieldDescriptor into a
// google.protobuf.FieldDescriptorProto message.
func ToFieldDescriptorProto(field protoreflect.FieldDescriptor) *descriptorpb.FieldDescriptorProto {
p := &descriptorpb.FieldDescriptorProto{
Name: proto.String(string(field.Name())),
Number: proto.Int32(int32(field.Number())),
Label: descriptorpb.FieldDescriptorProto_Label(field.Cardinality()).Enum(),
Options: proto.Clone(field.Options()).(*descriptorpb.FieldOptions),
}
if field.IsExtension() {
p.Extendee = fullNameOf(field.ContainingMessage())
}
if field.Kind().IsValid() {
p.Type = descriptorpb.FieldDescriptorProto_Type(field.Kind()).Enum()
}
if field.Enum() != nil {
p.TypeName = fullNameOf(field.Enum())
}
if field.Message() != nil {
p.TypeName = fullNameOf(field.Message())
}
if field.HasJSONName() {
// A bug in older versions of protoc would always populate the
// "json_name" option for extensions when it is meaningless.
// When it did so, it would always use the camel-cased field name.
if field.IsExtension() {
p.JsonName = proto.String(strs.JSONCamelCase(string(field.Name())))
} else {
p.JsonName = proto.String(field.JSONName())
}
}
if field.Syntax() == protoreflect.Proto3 && field.HasOptionalKeyword() {
p.Proto3Optional = proto.Bool(true)
}
if field.HasDefault() {
def, err := defval.Marshal(field.Default(), field.DefaultEnumValue(), field.Kind(), defval.Descriptor)
if err != nil && field.DefaultEnumValue() != nil {
def = string(field.DefaultEnumValue().Name()) // occurs for unresolved enum values
} else if err != nil {
panic(fmt.Sprintf("%v: %v", field.FullName(), err))
}
p.DefaultValue = proto.String(def)
}
if oneof := field.ContainingOneof(); oneof != nil {
p.OneofIndex = proto.Int32(int32(oneof.Index()))
}
return p
}
// ToOneofDescriptorProto copies a protoreflect.OneofDescriptor into a
// google.protobuf.OneofDescriptorProto message.
func ToOneofDescriptorProto(oneof protoreflect.OneofDescriptor) *descriptorpb.OneofDescriptorProto {
return &descriptorpb.OneofDescriptorProto{
Name: proto.String(string(oneof.Name())),
Options: proto.Clone(oneof.Options()).(*descriptorpb.OneofOptions),
}
}
// ToEnumDescriptorProto copies a protoreflect.EnumDescriptor into a
// google.protobuf.EnumDescriptorProto message.
func ToEnumDescriptorProto(enum protoreflect.EnumDescriptor) *descriptorpb.EnumDescriptorProto {
p := &descriptorpb.EnumDescriptorProto{
Name: proto.String(string(enum.Name())),
Options: proto.Clone(enum.Options()).(*descriptorpb.EnumOptions),
}
for i, values := 0, enum.Values(); i < values.Len(); i++ {
p.Value = append(p.Value, ToEnumValueDescriptorProto(values.Get(i)))
}
for i, ranges := 0, enum.ReservedRanges(); i < ranges.Len(); i++ {
rrange := ranges.Get(i)
p.ReservedRange = append(p.ReservedRange, &descriptorpb.EnumDescriptorProto_EnumReservedRange{
Start: proto.Int32(int32(rrange[0])),
End: proto.Int32(int32(rrange[1])),
})
}
for i, names := 0, enum.ReservedNames(); i < names.Len(); i++ {
p.ReservedName = append(p.ReservedName, string(names.Get(i)))
}
return p
}
// ToEnumValueDescriptorProto copies a protoreflect.EnumValueDescriptor into a
// google.protobuf.EnumValueDescriptorProto message.
func ToEnumValueDescriptorProto(value protoreflect.EnumValueDescriptor) *descriptorpb.EnumValueDescriptorProto {
return &descriptorpb.EnumValueDescriptorProto{
Name: proto.String(string(value.Name())),
Number: proto.Int32(int32(value.Number())),
Options: proto.Clone(value.Options()).(*descriptorpb.EnumValueOptions),
}
}
// ToServiceDescriptorProto copies a protoreflect.ServiceDescriptor into a
// google.protobuf.ServiceDescriptorProto message.
func ToServiceDescriptorProto(service protoreflect.ServiceDescriptor) *descriptorpb.ServiceDescriptorProto {
p := &descriptorpb.ServiceDescriptorProto{
Name: proto.String(string(service.Name())),
Options: proto.Clone(service.Options()).(*descriptorpb.ServiceOptions),
}
for i, methods := 0, service.Methods(); i < methods.Len(); i++ {
p.Method = append(p.Method, ToMethodDescriptorProto(methods.Get(i)))
}
return p
}
// ToMethodDescriptorProto copies a protoreflect.MethodDescriptor into a
// google.protobuf.MethodDescriptorProto message.
func ToMethodDescriptorProto(method protoreflect.MethodDescriptor) *descriptorpb.MethodDescriptorProto {
p := &descriptorpb.MethodDescriptorProto{
Name: proto.String(string(method.Name())),
InputType: fullNameOf(method.Input()),
OutputType: fullNameOf(method.Output()),
Options: proto.Clone(method.Options()).(*descriptorpb.MethodOptions),
}
if method.IsStreamingClient() {
p.ClientStreaming = proto.Bool(true)
}
if method.IsStreamingServer() {
p.ServerStreaming = proto.Bool(true)
}
return p
}
func fullNameOf(d protoreflect.Descriptor) *string {
if d == nil {
return nil
}
if strings.HasPrefix(string(d.FullName()), unknownPrefix) {
return proto.String(string(d.FullName()[len(unknownPrefix):]))
}
return proto.String("." + string(d.FullName()))
}

View file

@ -4,6 +4,10 @@
package protoreflect
import (
"strconv"
)
// SourceLocations is a list of source locations.
type SourceLocations interface {
// Len reports the number of source locations in the proto file.
@ -11,9 +15,20 @@ type SourceLocations interface {
// Get returns the ith SourceLocation. It panics if out of bounds.
Get(int) SourceLocation
doNotImplement
// ByPath returns the SourceLocation for the given path,
// returning the first location if multiple exist for the same path.
// If multiple locations exist for the same path,
// then SourceLocation.Next index can be used to identify the
// index of the next SourceLocation.
// If no location exists for this path, it returns the zero value.
ByPath(path SourcePath) SourceLocation
// TODO: Add ByPath and ByDescriptor helper methods.
// ByDescriptor returns the SourceLocation for the given descriptor,
// returning the first location if multiple exist for the same path.
// If no location exists for this descriptor, it returns the zero value.
ByDescriptor(desc Descriptor) SourceLocation
doNotImplement
}
// SourceLocation describes a source location and
@ -39,6 +54,10 @@ type SourceLocation struct {
LeadingComments string
// TrailingComments is the trailing attached comment for the declaration.
TrailingComments string
// Next is an index into SourceLocations for the next source location that
// has the same Path. It is zero if there is no next location.
Next int
}
// SourcePath identifies part of a file descriptor for a source location.
@ -48,5 +67,62 @@ type SourceLocation struct {
// See google.protobuf.SourceCodeInfo.Location.path.
type SourcePath []int32
// TODO: Add SourcePath.String method to pretty-print the path. For example:
// ".message_type[6].nested_type[15].field[3]"
// Equal reports whether p1 equals p2.
func (p1 SourcePath) Equal(p2 SourcePath) bool {
if len(p1) != len(p2) {
return false
}
for i := range p1 {
if p1[i] != p2[i] {
return false
}
}
return true
}
// String formats the path in a humanly readable manner.
// The output is guaranteed to be deterministic,
// making it suitable for use as a key into a Go map.
// It is not guaranteed to be stable as the exact output could change
// in a future version of this module.
//
// Example output:
// .message_type[6].nested_type[15].field[3]
func (p SourcePath) String() string {
b := p.appendFileDescriptorProto(nil)
for _, i := range p {
b = append(b, '.')
b = strconv.AppendInt(b, int64(i), 10)
}
return string(b)
}
type appendFunc func(*SourcePath, []byte) []byte
func (p *SourcePath) appendSingularField(b []byte, name string, f appendFunc) []byte {
if len(*p) == 0 {
return b
}
b = append(b, '.')
b = append(b, name...)
*p = (*p)[1:]
if f != nil {
b = f(p, b)
}
return b
}
func (p *SourcePath) appendRepeatedField(b []byte, name string, f appendFunc) []byte {
b = p.appendSingularField(b, name, nil)
if len(*p) == 0 || (*p)[0] < 0 {
return b
}
b = append(b, '[')
b = strconv.AppendUint(b, uint64((*p)[0]), 10)
b = append(b, ']')
*p = (*p)[1:]
if f != nil {
b = f(p, b)
}
return b
}

View file

@ -0,0 +1,461 @@
// 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.
// Code generated by generate-protos. DO NOT EDIT.
package protoreflect
func (p *SourcePath) appendFileDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendSingularField(b, "package", nil)
case 3:
b = p.appendRepeatedField(b, "dependency", nil)
case 10:
b = p.appendRepeatedField(b, "public_dependency", nil)
case 11:
b = p.appendRepeatedField(b, "weak_dependency", nil)
case 4:
b = p.appendRepeatedField(b, "message_type", (*SourcePath).appendDescriptorProto)
case 5:
b = p.appendRepeatedField(b, "enum_type", (*SourcePath).appendEnumDescriptorProto)
case 6:
b = p.appendRepeatedField(b, "service", (*SourcePath).appendServiceDescriptorProto)
case 7:
b = p.appendRepeatedField(b, "extension", (*SourcePath).appendFieldDescriptorProto)
case 8:
b = p.appendSingularField(b, "options", (*SourcePath).appendFileOptions)
case 9:
b = p.appendSingularField(b, "source_code_info", (*SourcePath).appendSourceCodeInfo)
case 12:
b = p.appendSingularField(b, "syntax", nil)
}
return b
}
func (p *SourcePath) appendDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendRepeatedField(b, "field", (*SourcePath).appendFieldDescriptorProto)
case 6:
b = p.appendRepeatedField(b, "extension", (*SourcePath).appendFieldDescriptorProto)
case 3:
b = p.appendRepeatedField(b, "nested_type", (*SourcePath).appendDescriptorProto)
case 4:
b = p.appendRepeatedField(b, "enum_type", (*SourcePath).appendEnumDescriptorProto)
case 5:
b = p.appendRepeatedField(b, "extension_range", (*SourcePath).appendDescriptorProto_ExtensionRange)
case 8:
b = p.appendRepeatedField(b, "oneof_decl", (*SourcePath).appendOneofDescriptorProto)
case 7:
b = p.appendSingularField(b, "options", (*SourcePath).appendMessageOptions)
case 9:
b = p.appendRepeatedField(b, "reserved_range", (*SourcePath).appendDescriptorProto_ReservedRange)
case 10:
b = p.appendRepeatedField(b, "reserved_name", nil)
}
return b
}
func (p *SourcePath) appendEnumDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendRepeatedField(b, "value", (*SourcePath).appendEnumValueDescriptorProto)
case 3:
b = p.appendSingularField(b, "options", (*SourcePath).appendEnumOptions)
case 4:
b = p.appendRepeatedField(b, "reserved_range", (*SourcePath).appendEnumDescriptorProto_EnumReservedRange)
case 5:
b = p.appendRepeatedField(b, "reserved_name", nil)
}
return b
}
func (p *SourcePath) appendServiceDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendRepeatedField(b, "method", (*SourcePath).appendMethodDescriptorProto)
case 3:
b = p.appendSingularField(b, "options", (*SourcePath).appendServiceOptions)
}
return b
}
func (p *SourcePath) appendFieldDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 3:
b = p.appendSingularField(b, "number", nil)
case 4:
b = p.appendSingularField(b, "label", nil)
case 5:
b = p.appendSingularField(b, "type", nil)
case 6:
b = p.appendSingularField(b, "type_name", nil)
case 2:
b = p.appendSingularField(b, "extendee", nil)
case 7:
b = p.appendSingularField(b, "default_value", nil)
case 9:
b = p.appendSingularField(b, "oneof_index", nil)
case 10:
b = p.appendSingularField(b, "json_name", nil)
case 8:
b = p.appendSingularField(b, "options", (*SourcePath).appendFieldOptions)
case 17:
b = p.appendSingularField(b, "proto3_optional", nil)
}
return b
}
func (p *SourcePath) appendFileOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "java_package", nil)
case 8:
b = p.appendSingularField(b, "java_outer_classname", nil)
case 10:
b = p.appendSingularField(b, "java_multiple_files", nil)
case 20:
b = p.appendSingularField(b, "java_generate_equals_and_hash", nil)
case 27:
b = p.appendSingularField(b, "java_string_check_utf8", nil)
case 9:
b = p.appendSingularField(b, "optimize_for", nil)
case 11:
b = p.appendSingularField(b, "go_package", nil)
case 16:
b = p.appendSingularField(b, "cc_generic_services", nil)
case 17:
b = p.appendSingularField(b, "java_generic_services", nil)
case 18:
b = p.appendSingularField(b, "py_generic_services", nil)
case 42:
b = p.appendSingularField(b, "php_generic_services", nil)
case 23:
b = p.appendSingularField(b, "deprecated", nil)
case 31:
b = p.appendSingularField(b, "cc_enable_arenas", nil)
case 36:
b = p.appendSingularField(b, "objc_class_prefix", nil)
case 37:
b = p.appendSingularField(b, "csharp_namespace", nil)
case 39:
b = p.appendSingularField(b, "swift_prefix", nil)
case 40:
b = p.appendSingularField(b, "php_class_prefix", nil)
case 41:
b = p.appendSingularField(b, "php_namespace", nil)
case 44:
b = p.appendSingularField(b, "php_metadata_namespace", nil)
case 45:
b = p.appendSingularField(b, "ruby_package", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendSourceCodeInfo(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendRepeatedField(b, "location", (*SourcePath).appendSourceCodeInfo_Location)
}
return b
}
func (p *SourcePath) appendDescriptorProto_ExtensionRange(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "start", nil)
case 2:
b = p.appendSingularField(b, "end", nil)
case 3:
b = p.appendSingularField(b, "options", (*SourcePath).appendExtensionRangeOptions)
}
return b
}
func (p *SourcePath) appendOneofDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendSingularField(b, "options", (*SourcePath).appendOneofOptions)
}
return b
}
func (p *SourcePath) appendMessageOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "message_set_wire_format", nil)
case 2:
b = p.appendSingularField(b, "no_standard_descriptor_accessor", nil)
case 3:
b = p.appendSingularField(b, "deprecated", nil)
case 7:
b = p.appendSingularField(b, "map_entry", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendDescriptorProto_ReservedRange(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "start", nil)
case 2:
b = p.appendSingularField(b, "end", nil)
}
return b
}
func (p *SourcePath) appendEnumValueDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendSingularField(b, "number", nil)
case 3:
b = p.appendSingularField(b, "options", (*SourcePath).appendEnumValueOptions)
}
return b
}
func (p *SourcePath) appendEnumOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 2:
b = p.appendSingularField(b, "allow_alias", nil)
case 3:
b = p.appendSingularField(b, "deprecated", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendEnumDescriptorProto_EnumReservedRange(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "start", nil)
case 2:
b = p.appendSingularField(b, "end", nil)
}
return b
}
func (p *SourcePath) appendMethodDescriptorProto(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name", nil)
case 2:
b = p.appendSingularField(b, "input_type", nil)
case 3:
b = p.appendSingularField(b, "output_type", nil)
case 4:
b = p.appendSingularField(b, "options", (*SourcePath).appendMethodOptions)
case 5:
b = p.appendSingularField(b, "client_streaming", nil)
case 6:
b = p.appendSingularField(b, "server_streaming", nil)
}
return b
}
func (p *SourcePath) appendServiceOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 33:
b = p.appendSingularField(b, "deprecated", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendFieldOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "ctype", nil)
case 2:
b = p.appendSingularField(b, "packed", nil)
case 6:
b = p.appendSingularField(b, "jstype", nil)
case 5:
b = p.appendSingularField(b, "lazy", nil)
case 3:
b = p.appendSingularField(b, "deprecated", nil)
case 10:
b = p.appendSingularField(b, "weak", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendUninterpretedOption(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 2:
b = p.appendRepeatedField(b, "name", (*SourcePath).appendUninterpretedOption_NamePart)
case 3:
b = p.appendSingularField(b, "identifier_value", nil)
case 4:
b = p.appendSingularField(b, "positive_int_value", nil)
case 5:
b = p.appendSingularField(b, "negative_int_value", nil)
case 6:
b = p.appendSingularField(b, "double_value", nil)
case 7:
b = p.appendSingularField(b, "string_value", nil)
case 8:
b = p.appendSingularField(b, "aggregate_value", nil)
}
return b
}
func (p *SourcePath) appendSourceCodeInfo_Location(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendRepeatedField(b, "path", nil)
case 2:
b = p.appendRepeatedField(b, "span", nil)
case 3:
b = p.appendSingularField(b, "leading_comments", nil)
case 4:
b = p.appendSingularField(b, "trailing_comments", nil)
case 6:
b = p.appendRepeatedField(b, "leading_detached_comments", nil)
}
return b
}
func (p *SourcePath) appendExtensionRangeOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendOneofOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendEnumValueOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "deprecated", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendMethodOptions(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 33:
b = p.appendSingularField(b, "deprecated", nil)
case 34:
b = p.appendSingularField(b, "idempotency_level", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
return b
}
func (p *SourcePath) appendUninterpretedOption_NamePart(b []byte) []byte {
if len(*p) == 0 {
return b
}
switch (*p)[0] {
case 1:
b = p.appendSingularField(b, "name_part", nil)
case 2:
b = p.appendSingularField(b, "is_extension", nil)
}
return b
}

View file

@ -232,11 +232,15 @@ type MessageDescriptor interface {
type isMessageDescriptor interface{ ProtoType(MessageDescriptor) }
// MessageType encapsulates a MessageDescriptor with a concrete Go implementation.
// It is recommended that implementations of this interface also implement the
// MessageFieldTypes interface.
type MessageType interface {
// New returns a newly allocated empty message.
// It may return nil for synthetic messages representing a map entry.
New() Message
// Zero returns an empty, read-only message.
// It may return nil for synthetic messages representing a map entry.
Zero() Message
// Descriptor returns the message descriptor.
@ -245,6 +249,26 @@ type MessageType interface {
Descriptor() MessageDescriptor
}
// MessageFieldTypes extends a MessageType by providing type information
// regarding enums and messages referenced by the message fields.
type MessageFieldTypes interface {
MessageType
// Enum returns the EnumType for the ith field in Descriptor.Fields.
// It returns nil if the ith field is not an enum kind.
// It panics if out of bounds.
//
// Invariant: mt.Enum(i).Descriptor() == mt.Descriptor().Fields(i).Enum()
Enum(i int) EnumType
// Message returns the MessageType for the ith field in Descriptor.Fields.
// It returns nil if the ith field is not a message or group kind.
// It panics if out of bounds.
//
// Invariant: mt.Message(i).Descriptor() == mt.Descriptor().Fields(i).Message()
Message(i int) MessageType
}
// MessageDescriptors is a list of message declarations.
type MessageDescriptors interface {
// Len reports the number of messages.
@ -279,8 +303,15 @@ type FieldDescriptor interface {
// JSONName reports the name used for JSON serialization.
// It is usually the camel-cased form of the field name.
// Extension fields are represented by the full name surrounded by brackets.
JSONName() string
// TextName reports the name used for text serialization.
// It is usually the name of the field, except that groups use the name
// of the inlined message, and extension fields are represented by the
// full name surrounded by brackets.
TextName() string
// HasPresence reports whether the field distinguishes between unpopulated
// and default values.
HasPresence() bool
@ -371,6 +402,9 @@ type FieldDescriptors interface {
// ByJSONName returns the FieldDescriptor for a field with s as the JSON name.
// It returns nil if not found.
ByJSONName(s string) FieldDescriptor
// ByTextName returns the FieldDescriptor for a field with s as the text name.
// It returns nil if not found.
ByTextName(s string) FieldDescriptor
// ByNumber returns the FieldDescriptor for a field numbered n.
// It returns nil if not found.
ByNumber(n FieldNumber) FieldDescriptor

View file

@ -17,24 +17,49 @@ package protoregistry
import (
"fmt"
"log"
"os"
"strings"
"sync"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/reflect/protoreflect"
)
// conflictPolicy configures the policy for handling registration conflicts.
//
// It can be over-written at compile time with a linker-initialized variable:
// go build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn"
//
// It can be over-written at program execution with an environment variable:
// GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn ./main
//
// Neither of the above are covered by the compatibility promise and
// may be removed in a future release of this module.
var conflictPolicy = "panic" // "panic" | "warn" | "ignore"
// ignoreConflict reports whether to ignore a registration conflict
// given the descriptor being registered and the error.
// It is a variable so that the behavior is easily overridden in another file.
var ignoreConflict = func(d protoreflect.Descriptor, err error) bool {
log.Printf(""+
"WARNING: %v\n"+
"A future release will panic on registration conflicts. See:\n"+
"https://developers.google.com/protocol-buffers/docs/reference/go/faq#namespace-conflict\n"+
"\n", err)
return true
const env = "GOLANG_PROTOBUF_REGISTRATION_CONFLICT"
const faq = "https://developers.google.com/protocol-buffers/docs/reference/go/faq#namespace-conflict"
policy := conflictPolicy
if v := os.Getenv(env); v != "" {
policy = v
}
switch policy {
case "panic":
panic(fmt.Sprintf("%v\nSee %v\n", err, faq))
case "warn":
fmt.Fprintf(os.Stderr, "WARNING: %v\nSee %v\n\n", err, faq)
return true
case "ignore":
return true
default:
panic("invalid " + env + " value: " + os.Getenv(env))
}
}
var globalMutex sync.RWMutex
@ -69,7 +94,8 @@ type Files struct {
// Note that enum values are in the top-level since that are in the same
// scope as the parent enum.
descsByName map[protoreflect.FullName]interface{}
filesByPath map[string]protoreflect.FileDescriptor
filesByPath map[string][]protoreflect.FileDescriptor
numFiles int
}
type packageDescriptor struct {
@ -92,48 +118,16 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
r.descsByName = map[protoreflect.FullName]interface{}{
"": &packageDescriptor{},
}
r.filesByPath = make(map[string]protoreflect.FileDescriptor)
r.filesByPath = make(map[string][]protoreflect.FileDescriptor)
}
path := file.Path()
if prev := r.filesByPath[path]; prev != nil {
// TODO: Remove this after some soak-in period after moving these types.
var prevPath string
const prevModule = "google.golang.org/genproto"
const prevVersion = "cb27e3aa (May 26th, 2020)"
switch path {
case "google/protobuf/field_mask.proto":
prevPath = prevModule + "/protobuf/field_mask"
case "google/protobuf/api.proto":
prevPath = prevModule + "/protobuf/api"
case "google/protobuf/type.proto":
prevPath = prevModule + "/protobuf/ptype"
case "google/protobuf/source_context.proto":
prevPath = prevModule + "/protobuf/source_context"
}
if r == GlobalFiles && prevPath != "" {
pkgName := strings.TrimSuffix(strings.TrimPrefix(path, "google/protobuf/"), ".proto")
pkgName = strings.Replace(pkgName, "_", "", -1) + "pb"
currPath := "google.golang.org/protobuf/types/known/" + pkgName
panic(fmt.Sprintf(""+
"duplicate registration of %q\n"+
"\n"+
"The generated definition for this file has moved:\n"+
"\tfrom: %q\n"+
"\tto: %q\n"+
"A dependency on the %q module must\n"+
"be at version %v or higher.\n"+
"\n"+
"Upgrade the dependency by running:\n"+
"\tgo get -u %v\n",
path, prevPath, currPath, prevModule, prevVersion, prevPath))
}
if prev := r.filesByPath[path]; len(prev) > 0 {
r.checkGenProtoConflict(path)
err := errors.New("file %q is already registered", file.Path())
err = amendErrorWithCaller(err, prev, file)
if r == GlobalFiles && ignoreConflict(file, err) {
err = nil
err = amendErrorWithCaller(err, prev[0], file)
if !(r == GlobalFiles && ignoreConflict(file, err)) {
return err
}
return err
}
for name := file.Package(); name != ""; name = name.Parent() {
@ -174,10 +168,52 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) {
r.descsByName[d.FullName()] = d
})
r.filesByPath[path] = file
r.filesByPath[path] = append(r.filesByPath[path], file)
r.numFiles++
return nil
}
// Several well-known types were hosted in the google.golang.org/genproto module
// but were later moved to this module. To avoid a weak dependency on the
// genproto module (and its relatively large set of transitive dependencies),
// we rely on a registration conflict to determine whether the genproto version
// is too old (i.e., does not contain aliases to the new type declarations).
func (r *Files) checkGenProtoConflict(path string) {
if r != GlobalFiles {
return
}
var prevPath string
const prevModule = "google.golang.org/genproto"
const prevVersion = "cb27e3aa (May 26th, 2020)"
switch path {
case "google/protobuf/field_mask.proto":
prevPath = prevModule + "/protobuf/field_mask"
case "google/protobuf/api.proto":
prevPath = prevModule + "/protobuf/api"
case "google/protobuf/type.proto":
prevPath = prevModule + "/protobuf/ptype"
case "google/protobuf/source_context.proto":
prevPath = prevModule + "/protobuf/source_context"
default:
return
}
pkgName := strings.TrimSuffix(strings.TrimPrefix(path, "google/protobuf/"), ".proto")
pkgName = strings.Replace(pkgName, "_", "", -1) + "pb" // e.g., "field_mask" => "fieldmaskpb"
currPath := "google.golang.org/protobuf/types/known/" + pkgName
panic(fmt.Sprintf(""+
"duplicate registration of %q\n"+
"\n"+
"The generated definition for this file has moved:\n"+
"\tfrom: %q\n"+
"\tto: %q\n"+
"A dependency on the %q module must\n"+
"be at version %v or higher.\n"+
"\n"+
"Upgrade the dependency by running:\n"+
"\tgo get -u %v\n",
path, prevPath, currPath, prevModule, prevVersion, prevPath))
}
// FindDescriptorByName looks up a descriptor by the full name.
//
// This returns (nil, NotFound) if not found.
@ -273,6 +309,7 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) {
// FindFileByPath looks up a file by the path.
//
// This returns (nil, NotFound) if not found.
// This returns an error if multiple files have the same path.
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
if r == nil {
return nil, NotFound
@ -281,13 +318,19 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
globalMutex.RLock()
defer globalMutex.RUnlock()
}
if fd, ok := r.filesByPath[path]; ok {
return fd, nil
fds := r.filesByPath[path]
switch len(fds) {
case 0:
return nil, NotFound
case 1:
return fds[0], nil
default:
return nil, errors.New("multiple files named %q", path)
}
return nil, NotFound
}
// NumFiles reports the number of registered files.
// NumFiles reports the number of registered files,
// including duplicate files with the same name.
func (r *Files) NumFiles() int {
if r == nil {
return 0
@ -296,10 +339,11 @@ func (r *Files) NumFiles() int {
globalMutex.RLock()
defer globalMutex.RUnlock()
}
return len(r.filesByPath)
return r.numFiles
}
// RangeFiles iterates over all registered files while f returns true.
// If multiple files have the same name, RangeFiles iterates over all of them.
// The iteration order is undefined.
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
if r == nil {
@ -309,9 +353,11 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
globalMutex.RLock()
defer globalMutex.RUnlock()
}
for _, file := range r.filesByPath {
if !f(file) {
return
for _, files := range r.filesByPath {
for _, file := range files {
if !f(file) {
return
}
}
}
}
@ -560,13 +606,25 @@ func (r *Types) FindEnumByName(enum protoreflect.FullName) (protoreflect.EnumTyp
return nil, NotFound
}
// FindMessageByName looks up a message by its full name.
// E.g., "google.protobuf.Any"
// FindMessageByName looks up a message by its full name,
// e.g. "google.protobuf.Any".
//
// This return (nil, NotFound) if not found.
// This returns (nil, NotFound) if not found.
func (r *Types) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
// The full name by itself is a valid URL.
return r.FindMessageByURL(string(message))
if r == nil {
return nil, NotFound
}
if r == GlobalTypes {
globalMutex.RLock()
defer globalMutex.RUnlock()
}
if v := r.typesByName[message]; v != nil {
if mt, _ := v.(protoreflect.MessageType); mt != nil {
return mt, nil
}
return nil, errors.New("found wrong type: got %v, want message", typeName(v))
}
return nil, NotFound
}
// FindMessageByURL looks up a message by a URL identifier.
@ -574,6 +632,8 @@ func (r *Types) FindMessageByName(message protoreflect.FullName) (protoreflect.M
//
// This returns (nil, NotFound) if not found.
func (r *Types) FindMessageByURL(url string) (protoreflect.MessageType, error) {
// This function is similar to FindMessageByName but
// truncates anything before and including '/' in the URL.
if r == nil {
return nil, NotFound
}
@ -613,6 +673,26 @@ func (r *Types) FindExtensionByName(field protoreflect.FullName) (protoreflect.E
if xt, _ := v.(protoreflect.ExtensionType); xt != nil {
return xt, nil
}
// MessageSet extensions are special in that the name of the extension
// is the name of the message type used to extend the MessageSet.
// This naming scheme is used by text and JSON serialization.
//
// This feature is protected by the ProtoLegacy flag since MessageSets
// are a proto1 feature that is long deprecated.
if flags.ProtoLegacy {
if _, ok := v.(protoreflect.MessageType); ok {
field := field.Append(messageset.ExtensionName)
if v := r.typesByName[field]; v != nil {
if xt, _ := v.(protoreflect.ExtensionType); xt != nil {
if messageset.IsMessageSetExtension(xt.TypeDescriptor()) {
return xt, nil
}
}
}
}
}
return nil, errors.New("found wrong type: got %v, want extension", typeName(v))
}
return nil, NotFound

File diff suppressed because it is too large Load diff

View file

@ -166,10 +166,13 @@ import (
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// any, err := anypb.New(foo)
// if err != nil {
// ...
// }
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// if err := any.UnmarshalTo(foo); err != nil {
// ...
// }
//
@ -420,14 +423,15 @@ var file_google_protobuf_any_proto_rawDesc = []byte{
0x41, 0x6e, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x42, 0x6f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x61, 0x6c, 0x75, 0x65, 0x42, 0x76, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x08, 0x41, 0x6e, 0x79,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0xa2, 0x02,
0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e,
0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f,
0x61, 0x6e, 0x79, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65,
0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (

View file

@ -303,16 +303,16 @@ var file_google_protobuf_duration_proto_rawDesc = []byte{
0x66, 0x22, 0x3a, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x7c, 0x0a,
0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x42, 0x0d, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c,
0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x83, 0x01,
0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0d, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67,
0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x64,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47,
0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79,
0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View file

@ -134,7 +134,16 @@ import (
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
//
// Example 5: Compute Timestamp from current time in Python.
// Example 5: Compute Timestamp from Java `Instant.now()`.
//
// Instant now = Instant.now();
//
// Timestamp timestamp =
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
// .setNanos(now.getNano()).build();
//
//
// Example 6: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
@ -306,15 +315,15 @@ var file_google_protobuf_timestamp_proto_rawDesc = []byte{
0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6e,
0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42,
0x7e, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02,
0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x85, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77,
0x6e, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x70, 0x62, 0xf8, 0x01, 0x01,
0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f,
0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (