ci: add retest github action

added source code of github retest
action.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna
2021-11-15 12:19:04 +05:30
committed by mergify[bot]
parent f7e7172c7b
commit 5a53f53166
287 changed files with 74334 additions and 0 deletions

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,678 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
logpb "google.golang.org/appengine/internal/log"
remotepb "google.golang.org/appengine/internal/remote_api"
)
const (
apiPath = "/rpc_http"
defaultTicketSuffix = "/default.20150612t184001.0"
)
var (
// Incoming headers.
ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context")
curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
devRequestIdHeader = http.CanonicalHeaderKey("X-Appengine-Dev-Request-Id")
// Outgoing headers.
apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint")
apiEndpointHeaderValue = []string{"app-engine-apis"}
apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method")
apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"}
apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline")
apiContentType = http.CanonicalHeaderKey("Content-Type")
apiContentTypeValue = []string{"application/octet-stream"}
logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count")
apiHTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: limitDial,
MaxIdleConns: 1000,
MaxIdleConnsPerHost: 10000,
IdleConnTimeout: 90 * time.Second,
},
}
defaultTicketOnce sync.Once
defaultTicket string
backgroundContextOnce sync.Once
backgroundContext netcontext.Context
)
func apiURL() *url.URL {
host, port := "appengine.googleapis.internal", "10001"
if h := os.Getenv("API_HOST"); h != "" {
host = h
}
if p := os.Getenv("API_PORT"); p != "" {
port = p
}
return &url.URL{
Scheme: "http",
Host: host + ":" + port,
Path: apiPath,
}
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
c := &context{
req: r,
outHeader: w.Header(),
apiURL: apiURL(),
}
r = r.WithContext(withContext(r.Context(), c))
c.req = r
stopFlushing := make(chan int)
// Patch up RemoteAddr so it looks reasonable.
if addr := r.Header.Get(userIPHeader); addr != "" {
r.RemoteAddr = addr
} else if addr = r.Header.Get(remoteAddrHeader); addr != "" {
r.RemoteAddr = addr
} else {
// Should not normally reach here, but pick a sensible default anyway.
r.RemoteAddr = "127.0.0.1"
}
// The address in the headers will most likely be of these forms:
// 123.123.123.123
// 2001:db8::1
// net/http.Request.RemoteAddr is specified to be in "IP:port" form.
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
// Assume the remote address is only a host; add a default port.
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
}
// Start goroutine responsible for flushing app logs.
// This is done after adding c to ctx.m (and stopped before removing it)
// because flushing logs requires making an API call.
go c.logFlusher(stopFlushing)
executeRequestSafely(c, r)
c.outHeader = nil // make sure header changes aren't respected any more
stopFlushing <- 1 // any logging beyond this point will be dropped
// Flush any pending logs asynchronously.
c.pendingLogs.Lock()
flushes := c.pendingLogs.flushes
if len(c.pendingLogs.lines) > 0 {
flushes++
}
c.pendingLogs.Unlock()
flushed := make(chan struct{})
go func() {
defer close(flushed)
// Force a log flush, because with very short requests we
// may not ever flush logs.
c.flushLog(true)
}()
w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
// Avoid nil Write call if c.Write is never called.
if c.outCode != 0 {
w.WriteHeader(c.outCode)
}
if c.outBody != nil {
w.Write(c.outBody)
}
// Wait for the last flush to complete before returning,
// otherwise the security ticket will not be valid.
<-flushed
}
func executeRequestSafely(c *context, r *http.Request) {
defer func() {
if x := recover(); x != nil {
logf(c, 4, "%s", renderPanic(x)) // 4 == critical
c.outCode = 500
}
}()
http.DefaultServeMux.ServeHTTP(c, r)
}
func renderPanic(x interface{}) string {
buf := make([]byte, 16<<10) // 16 KB should be plenty
buf = buf[:runtime.Stack(buf, false)]
// Remove the first few stack frames:
// this func
// the recover closure in the caller
// That will root the stack trace at the site of the panic.
const (
skipStart = "internal.renderPanic"
skipFrames = 2
)
start := bytes.Index(buf, []byte(skipStart))
p := start
for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ {
p = bytes.IndexByte(buf[p+1:], '\n') + p + 1
if p < 0 {
break
}
}
if p >= 0 {
// buf[start:p+1] is the block to remove.
// Copy buf[p+1:] over buf[start:] and shrink buf.
copy(buf[start:], buf[p+1:])
buf = buf[:len(buf)-(p+1-start)]
}
// Add panic heading.
head := fmt.Sprintf("panic: %v\n\n", x)
if len(head) > len(buf) {
// Extremely unlikely to happen.
return head
}
copy(buf[len(head):], buf)
copy(buf, head)
return string(buf)
}
// context represents the context of an in-flight HTTP request.
// It implements the appengine.Context and http.ResponseWriter interfaces.
type context struct {
req *http.Request
outCode int
outHeader http.Header
outBody []byte
pendingLogs struct {
sync.Mutex
lines []*logpb.UserAppLogLine
flushes int
}
apiURL *url.URL
}
var contextKey = "holds a *context"
// jointContext joins two contexts in a superficial way.
// It takes values and timeouts from a base context, and only values from another context.
type jointContext struct {
base netcontext.Context
valuesOnly netcontext.Context
}
func (c jointContext) Deadline() (time.Time, bool) {
return c.base.Deadline()
}
func (c jointContext) Done() <-chan struct{} {
return c.base.Done()
}
func (c jointContext) Err() error {
return c.base.Err()
}
func (c jointContext) Value(key interface{}) interface{} {
if val := c.base.Value(key); val != nil {
return val
}
return c.valuesOnly.Value(key)
}
// fromContext returns the App Engine context or nil if ctx is not
// derived from an App Engine context.
func fromContext(ctx netcontext.Context) *context {
c, _ := ctx.Value(&contextKey).(*context)
return c
}
func withContext(parent netcontext.Context, c *context) netcontext.Context {
ctx := netcontext.WithValue(parent, &contextKey, c)
if ns := c.req.Header.Get(curNamespaceHeader); ns != "" {
ctx = withNamespace(ctx, ns)
}
return ctx
}
func toContext(c *context) netcontext.Context {
return withContext(netcontext.Background(), c)
}
func IncomingHeaders(ctx netcontext.Context) http.Header {
if c := fromContext(ctx); c != nil {
return c.req.Header
}
return nil
}
func ReqContext(req *http.Request) netcontext.Context {
return req.Context()
}
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
return jointContext{
base: parent,
valuesOnly: req.Context(),
}
}
// DefaultTicket returns a ticket used for background context or dev_appserver.
func DefaultTicket() string {
defaultTicketOnce.Do(func() {
if IsDevAppServer() {
defaultTicket = "testapp" + defaultTicketSuffix
return
}
appID := partitionlessAppID()
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
majVersion := VersionID(nil)
if i := strings.Index(majVersion, "."); i > 0 {
majVersion = majVersion[:i]
}
defaultTicket = fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID())
})
return defaultTicket
}
func BackgroundContext() netcontext.Context {
backgroundContextOnce.Do(func() {
// Compute background security ticket.
ticket := DefaultTicket()
c := &context{
req: &http.Request{
Header: http.Header{
ticketHeader: []string{ticket},
},
},
apiURL: apiURL(),
}
backgroundContext = toContext(c)
// TODO(dsymonds): Wire up the shutdown handler to do a final flush.
go c.logFlusher(make(chan int))
})
return backgroundContext
}
// RegisterTestRequest registers the HTTP request req for testing, such that
// any API calls are sent to the provided URL. It returns a closure to delete
// the registration.
// It should only be used by aetest package.
func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) (*http.Request, func()) {
c := &context{
req: req,
apiURL: apiURL,
}
ctx := withContext(decorate(req.Context()), c)
req = req.WithContext(ctx)
c.req = req
return req, func() {}
}
var errTimeout = &CallError{
Detail: "Deadline exceeded",
Code: int32(remotepb.RpcError_CANCELLED),
Timeout: true,
}
func (c *context) Header() http.Header { return c.outHeader }
// Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status
// codes do not permit a response body (nor response entity headers such as
// Content-Length, Content-Type, etc).
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
return false
case status == 204:
return false
case status == 304:
return false
}
return true
}
func (c *context) Write(b []byte) (int, error) {
if c.outCode == 0 {
c.WriteHeader(http.StatusOK)
}
if len(b) > 0 && !bodyAllowedForStatus(c.outCode) {
return 0, http.ErrBodyNotAllowed
}
c.outBody = append(c.outBody, b...)
return len(b), nil
}
func (c *context) WriteHeader(code int) {
if c.outCode != 0 {
logf(c, 3, "WriteHeader called multiple times on request.") // error level
return
}
c.outCode = code
}
func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
hreq := &http.Request{
Method: "POST",
URL: c.apiURL,
Header: http.Header{
apiEndpointHeader: apiEndpointHeaderValue,
apiMethodHeader: apiMethodHeaderValue,
apiContentType: apiContentTypeValue,
apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)},
},
Body: ioutil.NopCloser(bytes.NewReader(body)),
ContentLength: int64(len(body)),
Host: c.apiURL.Host,
}
if info := c.req.Header.Get(dapperHeader); info != "" {
hreq.Header.Set(dapperHeader, info)
}
if info := c.req.Header.Get(traceHeader); info != "" {
hreq.Header.Set(traceHeader, info)
}
tr := apiHTTPClient.Transport.(*http.Transport)
var timedOut int32 // atomic; set to 1 if timed out
t := time.AfterFunc(timeout, func() {
atomic.StoreInt32(&timedOut, 1)
tr.CancelRequest(hreq)
})
defer t.Stop()
defer func() {
// Check if timeout was exceeded.
if atomic.LoadInt32(&timedOut) != 0 {
err = errTimeout
}
}()
hresp, err := apiHTTPClient.Do(hreq)
if err != nil {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge HTTP failed: %v", err),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
defer hresp.Body.Close()
hrespBody, err := ioutil.ReadAll(hresp.Body)
if hresp.StatusCode != 200 {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
if err != nil {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge response bad: %v", err),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
return hrespBody, nil
}
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
if ns := NamespaceFromContext(ctx); ns != "" {
if fn, ok := NamespaceMods[service]; ok {
fn(in, ns)
}
}
if f, ctx, ok := callOverrideFromContext(ctx); ok {
return f(ctx, service, method, in, out)
}
// Handle already-done contexts quickly.
select {
case <-ctx.Done():
return ctx.Err()
default:
}
c := fromContext(ctx)
if c == nil {
// Give a good error message rather than a panic lower down.
return errNotAppEngineContext
}
// Apply transaction modifications if we're in a transaction.
if t := transactionFromContext(ctx); t != nil {
if t.finished {
return errors.New("transaction context has expired")
}
applyTransaction(in, &t.transaction)
}
// Default RPC timeout is 60s.
timeout := 60 * time.Second
if deadline, ok := ctx.Deadline(); ok {
timeout = deadline.Sub(time.Now())
}
data, err := proto.Marshal(in)
if err != nil {
return err
}
ticket := c.req.Header.Get(ticketHeader)
// Use a test ticket under test environment.
if ticket == "" {
if appid := ctx.Value(&appIDOverrideKey); appid != nil {
ticket = appid.(string) + defaultTicketSuffix
}
}
// Fall back to use background ticket when the request ticket is not available in Flex or dev_appserver.
if ticket == "" {
ticket = DefaultTicket()
}
if dri := c.req.Header.Get(devRequestIdHeader); IsDevAppServer() && dri != "" {
ticket = dri
}
req := &remotepb.Request{
ServiceName: &service,
Method: &method,
Request: data,
RequestId: &ticket,
}
hreqBody, err := proto.Marshal(req)
if err != nil {
return err
}
hrespBody, err := c.post(hreqBody, timeout)
if err != nil {
return err
}
res := &remotepb.Response{}
if err := proto.Unmarshal(hrespBody, res); err != nil {
return err
}
if res.RpcError != nil {
ce := &CallError{
Detail: res.RpcError.GetDetail(),
Code: *res.RpcError.Code,
}
switch remotepb.RpcError_ErrorCode(ce.Code) {
case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED:
ce.Timeout = true
}
return ce
}
if res.ApplicationError != nil {
return &APIError{
Service: *req.ServiceName,
Detail: res.ApplicationError.GetDetail(),
Code: *res.ApplicationError.Code,
}
}
if res.Exception != nil || res.JavaException != nil {
// This shouldn't happen, but let's be defensive.
return &CallError{
Detail: "service bridge returned exception",
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
return proto.Unmarshal(res.Response, out)
}
func (c *context) Request() *http.Request {
return c.req
}
func (c *context) addLogLine(ll *logpb.UserAppLogLine) {
// Truncate long log lines.
// TODO(dsymonds): Check if this is still necessary.
const lim = 8 << 10
if len(*ll.Message) > lim {
suffix := fmt.Sprintf("...(length %d)", len(*ll.Message))
ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix)
}
c.pendingLogs.Lock()
c.pendingLogs.lines = append(c.pendingLogs.lines, ll)
c.pendingLogs.Unlock()
}
var logLevelName = map[int64]string{
0: "DEBUG",
1: "INFO",
2: "WARNING",
3: "ERROR",
4: "CRITICAL",
}
func logf(c *context, level int64, format string, args ...interface{}) {
if c == nil {
panic("not an App Engine context")
}
s := fmt.Sprintf(format, args...)
s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
c.addLogLine(&logpb.UserAppLogLine{
TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3),
Level: &level,
Message: &s,
})
// Only duplicate log to stderr if not running on App Engine second generation
if !IsSecondGen() {
log.Print(logLevelName[level] + ": " + s)
}
}
// flushLog attempts to flush any pending logs to the appserver.
// It should not be called concurrently.
func (c *context) flushLog(force bool) (flushed bool) {
c.pendingLogs.Lock()
// Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious.
n, rem := 0, 30<<20
for ; n < len(c.pendingLogs.lines); n++ {
ll := c.pendingLogs.lines[n]
// Each log line will require about 3 bytes of overhead.
nb := proto.Size(ll) + 3
if nb > rem {
break
}
rem -= nb
}
lines := c.pendingLogs.lines[:n]
c.pendingLogs.lines = c.pendingLogs.lines[n:]
c.pendingLogs.Unlock()
if len(lines) == 0 && !force {
// Nothing to flush.
return false
}
rescueLogs := false
defer func() {
if rescueLogs {
c.pendingLogs.Lock()
c.pendingLogs.lines = append(lines, c.pendingLogs.lines...)
c.pendingLogs.Unlock()
}
}()
buf, err := proto.Marshal(&logpb.UserAppLogGroup{
LogLine: lines,
})
if err != nil {
log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err)
rescueLogs = true
return false
}
req := &logpb.FlushRequest{
Logs: buf,
}
res := &basepb.VoidProto{}
c.pendingLogs.Lock()
c.pendingLogs.flushes++
c.pendingLogs.Unlock()
if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil {
log.Printf("internal.flushLog: Flush RPC: %v", err)
rescueLogs = true
return false
}
return true
}
const (
// Log flushing parameters.
flushInterval = 1 * time.Second
forceFlushInterval = 60 * time.Second
)
func (c *context) logFlusher(stop <-chan int) {
lastFlush := time.Now()
tick := time.NewTicker(flushInterval)
for {
select {
case <-stop:
// Request finished.
tick.Stop()
return
case <-tick.C:
force := time.Now().Sub(lastFlush) > forceFlushInterval
if c.flushLog(force) {
lastFlush = time.Now()
}
}
}
}
func ContextForTesting(req *http.Request) netcontext.Context {
return toContext(&context{req: req})
}

View File

@ -0,0 +1,169 @@
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"errors"
"fmt"
"net/http"
"time"
"appengine"
"appengine_internal"
basepb "appengine_internal/base"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
)
var contextKey = "holds an appengine.Context"
// fromContext returns the App Engine context or nil if ctx is not
// derived from an App Engine context.
func fromContext(ctx netcontext.Context) appengine.Context {
c, _ := ctx.Value(&contextKey).(appengine.Context)
return c
}
// This is only for classic App Engine adapters.
func ClassicContextFromContext(ctx netcontext.Context) (appengine.Context, error) {
c := fromContext(ctx)
if c == nil {
return nil, errNotAppEngineContext
}
return c, nil
}
func withContext(parent netcontext.Context, c appengine.Context) netcontext.Context {
ctx := netcontext.WithValue(parent, &contextKey, c)
s := &basepb.StringProto{}
c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil)
if ns := s.GetValue(); ns != "" {
ctx = NamespacedContext(ctx, ns)
}
return ctx
}
func IncomingHeaders(ctx netcontext.Context) http.Header {
if c := fromContext(ctx); c != nil {
if req, ok := c.Request().(*http.Request); ok {
return req.Header
}
}
return nil
}
func ReqContext(req *http.Request) netcontext.Context {
return WithContext(netcontext.Background(), req)
}
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
c := appengine.NewContext(req)
return withContext(parent, c)
}
type testingContext struct {
appengine.Context
req *http.Request
}
func (t *testingContext) FullyQualifiedAppID() string { return "dev~testcontext" }
func (t *testingContext) Call(service, method string, _, _ appengine_internal.ProtoMessage, _ *appengine_internal.CallOptions) error {
if service == "__go__" && method == "GetNamespace" {
return nil
}
return fmt.Errorf("testingContext: unsupported Call")
}
func (t *testingContext) Request() interface{} { return t.req }
func ContextForTesting(req *http.Request) netcontext.Context {
return withContext(netcontext.Background(), &testingContext{req: req})
}
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
if ns := NamespaceFromContext(ctx); ns != "" {
if fn, ok := NamespaceMods[service]; ok {
fn(in, ns)
}
}
if f, ctx, ok := callOverrideFromContext(ctx); ok {
return f(ctx, service, method, in, out)
}
// Handle already-done contexts quickly.
select {
case <-ctx.Done():
return ctx.Err()
default:
}
c := fromContext(ctx)
if c == nil {
// Give a good error message rather than a panic lower down.
return errNotAppEngineContext
}
// Apply transaction modifications if we're in a transaction.
if t := transactionFromContext(ctx); t != nil {
if t.finished {
return errors.New("transaction context has expired")
}
applyTransaction(in, &t.transaction)
}
var opts *appengine_internal.CallOptions
if d, ok := ctx.Deadline(); ok {
opts = &appengine_internal.CallOptions{
Timeout: d.Sub(time.Now()),
}
}
err := c.Call(service, method, in, out, opts)
switch v := err.(type) {
case *appengine_internal.APIError:
return &APIError{
Service: v.Service,
Detail: v.Detail,
Code: v.Code,
}
case *appengine_internal.CallError:
return &CallError{
Detail: v.Detail,
Code: v.Code,
Timeout: v.Timeout,
}
}
return err
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
panic("handleHTTP called; this should be impossible")
}
func logf(c appengine.Context, level int64, format string, args ...interface{}) {
var fn func(format string, args ...interface{})
switch level {
case 0:
fn = c.Debugf
case 1:
fn = c.Infof
case 2:
fn = c.Warningf
case 3:
fn = c.Errorf
case 4:
fn = c.Criticalf
default:
// This shouldn't happen.
fn = c.Criticalf
}
fn(format, args...)
}

View File

@ -0,0 +1,123 @@
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"errors"
"os"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
)
var errNotAppEngineContext = errors.New("not an App Engine context")
type CallOverrideFunc func(ctx netcontext.Context, service, method string, in, out proto.Message) error
var callOverrideKey = "holds []CallOverrideFunc"
func WithCallOverride(ctx netcontext.Context, f CallOverrideFunc) netcontext.Context {
// We avoid appending to any existing call override
// so we don't risk overwriting a popped stack below.
var cofs []CallOverrideFunc
if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok {
cofs = append(cofs, uf...)
}
cofs = append(cofs, f)
return netcontext.WithValue(ctx, &callOverrideKey, cofs)
}
func callOverrideFromContext(ctx netcontext.Context) (CallOverrideFunc, netcontext.Context, bool) {
cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc)
if len(cofs) == 0 {
return nil, nil, false
}
// We found a list of overrides; grab the last, and reconstitute a
// context that will hide it.
f := cofs[len(cofs)-1]
ctx = netcontext.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1])
return f, ctx, true
}
type logOverrideFunc func(level int64, format string, args ...interface{})
var logOverrideKey = "holds a logOverrideFunc"
func WithLogOverride(ctx netcontext.Context, f logOverrideFunc) netcontext.Context {
return netcontext.WithValue(ctx, &logOverrideKey, f)
}
var appIDOverrideKey = "holds a string, being the full app ID"
func WithAppIDOverride(ctx netcontext.Context, appID string) netcontext.Context {
return netcontext.WithValue(ctx, &appIDOverrideKey, appID)
}
var namespaceKey = "holds the namespace string"
func withNamespace(ctx netcontext.Context, ns string) netcontext.Context {
return netcontext.WithValue(ctx, &namespaceKey, ns)
}
func NamespaceFromContext(ctx netcontext.Context) string {
// If there's no namespace, return the empty string.
ns, _ := ctx.Value(&namespaceKey).(string)
return ns
}
// FullyQualifiedAppID returns the fully-qualified application ID.
// This may contain a partition prefix (e.g. "s~" for High Replication apps),
// or a domain prefix (e.g. "example.com:").
func FullyQualifiedAppID(ctx netcontext.Context) string {
if id, ok := ctx.Value(&appIDOverrideKey).(string); ok {
return id
}
return fullyQualifiedAppID(ctx)
}
func Logf(ctx netcontext.Context, level int64, format string, args ...interface{}) {
if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok {
f(level, format, args...)
return
}
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
logf(c, level, format, args...)
}
// NamespacedContext wraps a Context to support namespaces.
func NamespacedContext(ctx netcontext.Context, namespace string) netcontext.Context {
return withNamespace(ctx, namespace)
}
// SetTestEnv sets the env variables for testing background ticket in Flex.
func SetTestEnv() func() {
var environ = []struct {
key, value string
}{
{"GAE_LONG_APP_ID", "my-app-id"},
{"GAE_MINOR_VERSION", "067924799508853122"},
{"GAE_MODULE_INSTANCE", "0"},
{"GAE_MODULE_NAME", "default"},
{"GAE_MODULE_VERSION", "20150612t184001"},
}
for _, v := range environ {
old := os.Getenv(v.key)
os.Setenv(v.key, v.value)
v.value = old
}
return func() { // Restore old environment after the test completes.
for _, v := range environ {
if v.value == "" {
os.Unsetenv(v.key)
continue
}
os.Setenv(v.key, v.value)
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"strings"
)
func parseFullAppID(appid string) (partition, domain, displayID string) {
if i := strings.Index(appid, "~"); i != -1 {
partition, appid = appid[:i], appid[i+1:]
}
if i := strings.Index(appid, ":"); i != -1 {
domain, appid = appid[:i], appid[i+1:]
}
return partition, domain, appid
}
// appID returns "appid" or "domain.com:appid".
func appID(fullAppID string) string {
_, dom, dis := parseFullAppID(fullAppID)
if dom != "" {
return dom + ":" + dis
}
return dis
}

View File

@ -0,0 +1,308 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google.golang.org/appengine/internal/base/api_base.proto
package base
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type StringProto struct {
Value *string `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StringProto) Reset() { *m = StringProto{} }
func (m *StringProto) String() string { return proto.CompactTextString(m) }
func (*StringProto) ProtoMessage() {}
func (*StringProto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{0}
}
func (m *StringProto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StringProto.Unmarshal(m, b)
}
func (m *StringProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StringProto.Marshal(b, m, deterministic)
}
func (dst *StringProto) XXX_Merge(src proto.Message) {
xxx_messageInfo_StringProto.Merge(dst, src)
}
func (m *StringProto) XXX_Size() int {
return xxx_messageInfo_StringProto.Size(m)
}
func (m *StringProto) XXX_DiscardUnknown() {
xxx_messageInfo_StringProto.DiscardUnknown(m)
}
var xxx_messageInfo_StringProto proto.InternalMessageInfo
func (m *StringProto) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
type Integer32Proto struct {
Value *int32 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Integer32Proto) Reset() { *m = Integer32Proto{} }
func (m *Integer32Proto) String() string { return proto.CompactTextString(m) }
func (*Integer32Proto) ProtoMessage() {}
func (*Integer32Proto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{1}
}
func (m *Integer32Proto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Integer32Proto.Unmarshal(m, b)
}
func (m *Integer32Proto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Integer32Proto.Marshal(b, m, deterministic)
}
func (dst *Integer32Proto) XXX_Merge(src proto.Message) {
xxx_messageInfo_Integer32Proto.Merge(dst, src)
}
func (m *Integer32Proto) XXX_Size() int {
return xxx_messageInfo_Integer32Proto.Size(m)
}
func (m *Integer32Proto) XXX_DiscardUnknown() {
xxx_messageInfo_Integer32Proto.DiscardUnknown(m)
}
var xxx_messageInfo_Integer32Proto proto.InternalMessageInfo
func (m *Integer32Proto) GetValue() int32 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type Integer64Proto struct {
Value *int64 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Integer64Proto) Reset() { *m = Integer64Proto{} }
func (m *Integer64Proto) String() string { return proto.CompactTextString(m) }
func (*Integer64Proto) ProtoMessage() {}
func (*Integer64Proto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{2}
}
func (m *Integer64Proto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Integer64Proto.Unmarshal(m, b)
}
func (m *Integer64Proto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Integer64Proto.Marshal(b, m, deterministic)
}
func (dst *Integer64Proto) XXX_Merge(src proto.Message) {
xxx_messageInfo_Integer64Proto.Merge(dst, src)
}
func (m *Integer64Proto) XXX_Size() int {
return xxx_messageInfo_Integer64Proto.Size(m)
}
func (m *Integer64Proto) XXX_DiscardUnknown() {
xxx_messageInfo_Integer64Proto.DiscardUnknown(m)
}
var xxx_messageInfo_Integer64Proto proto.InternalMessageInfo
func (m *Integer64Proto) GetValue() int64 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type BoolProto struct {
Value *bool `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BoolProto) Reset() { *m = BoolProto{} }
func (m *BoolProto) String() string { return proto.CompactTextString(m) }
func (*BoolProto) ProtoMessage() {}
func (*BoolProto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{3}
}
func (m *BoolProto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BoolProto.Unmarshal(m, b)
}
func (m *BoolProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BoolProto.Marshal(b, m, deterministic)
}
func (dst *BoolProto) XXX_Merge(src proto.Message) {
xxx_messageInfo_BoolProto.Merge(dst, src)
}
func (m *BoolProto) XXX_Size() int {
return xxx_messageInfo_BoolProto.Size(m)
}
func (m *BoolProto) XXX_DiscardUnknown() {
xxx_messageInfo_BoolProto.DiscardUnknown(m)
}
var xxx_messageInfo_BoolProto proto.InternalMessageInfo
func (m *BoolProto) GetValue() bool {
if m != nil && m.Value != nil {
return *m.Value
}
return false
}
type DoubleProto struct {
Value *float64 `protobuf:"fixed64,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DoubleProto) Reset() { *m = DoubleProto{} }
func (m *DoubleProto) String() string { return proto.CompactTextString(m) }
func (*DoubleProto) ProtoMessage() {}
func (*DoubleProto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{4}
}
func (m *DoubleProto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DoubleProto.Unmarshal(m, b)
}
func (m *DoubleProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DoubleProto.Marshal(b, m, deterministic)
}
func (dst *DoubleProto) XXX_Merge(src proto.Message) {
xxx_messageInfo_DoubleProto.Merge(dst, src)
}
func (m *DoubleProto) XXX_Size() int {
return xxx_messageInfo_DoubleProto.Size(m)
}
func (m *DoubleProto) XXX_DiscardUnknown() {
xxx_messageInfo_DoubleProto.DiscardUnknown(m)
}
var xxx_messageInfo_DoubleProto proto.InternalMessageInfo
func (m *DoubleProto) GetValue() float64 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type BytesProto struct {
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BytesProto) Reset() { *m = BytesProto{} }
func (m *BytesProto) String() string { return proto.CompactTextString(m) }
func (*BytesProto) ProtoMessage() {}
func (*BytesProto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{5}
}
func (m *BytesProto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BytesProto.Unmarshal(m, b)
}
func (m *BytesProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BytesProto.Marshal(b, m, deterministic)
}
func (dst *BytesProto) XXX_Merge(src proto.Message) {
xxx_messageInfo_BytesProto.Merge(dst, src)
}
func (m *BytesProto) XXX_Size() int {
return xxx_messageInfo_BytesProto.Size(m)
}
func (m *BytesProto) XXX_DiscardUnknown() {
xxx_messageInfo_BytesProto.DiscardUnknown(m)
}
var xxx_messageInfo_BytesProto proto.InternalMessageInfo
func (m *BytesProto) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
type VoidProto struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *VoidProto) Reset() { *m = VoidProto{} }
func (m *VoidProto) String() string { return proto.CompactTextString(m) }
func (*VoidProto) ProtoMessage() {}
func (*VoidProto) Descriptor() ([]byte, []int) {
return fileDescriptor_api_base_9d49f8792e0c1140, []int{6}
}
func (m *VoidProto) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VoidProto.Unmarshal(m, b)
}
func (m *VoidProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VoidProto.Marshal(b, m, deterministic)
}
func (dst *VoidProto) XXX_Merge(src proto.Message) {
xxx_messageInfo_VoidProto.Merge(dst, src)
}
func (m *VoidProto) XXX_Size() int {
return xxx_messageInfo_VoidProto.Size(m)
}
func (m *VoidProto) XXX_DiscardUnknown() {
xxx_messageInfo_VoidProto.DiscardUnknown(m)
}
var xxx_messageInfo_VoidProto proto.InternalMessageInfo
func init() {
proto.RegisterType((*StringProto)(nil), "appengine.base.StringProto")
proto.RegisterType((*Integer32Proto)(nil), "appengine.base.Integer32Proto")
proto.RegisterType((*Integer64Proto)(nil), "appengine.base.Integer64Proto")
proto.RegisterType((*BoolProto)(nil), "appengine.base.BoolProto")
proto.RegisterType((*DoubleProto)(nil), "appengine.base.DoubleProto")
proto.RegisterType((*BytesProto)(nil), "appengine.base.BytesProto")
proto.RegisterType((*VoidProto)(nil), "appengine.base.VoidProto")
}
func init() {
proto.RegisterFile("google.golang.org/appengine/internal/base/api_base.proto", fileDescriptor_api_base_9d49f8792e0c1140)
}
var fileDescriptor_api_base_9d49f8792e0c1140 = []byte{
// 199 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0xcf, 0x3f, 0x4b, 0xc6, 0x30,
0x10, 0x06, 0x70, 0x5a, 0xad, 0xb4, 0x57, 0xe9, 0x20, 0x0e, 0x1d, 0xb5, 0x05, 0x71, 0x4a, 0x40,
0x45, 0x9c, 0x83, 0x8b, 0x9b, 0x28, 0x38, 0xb8, 0x48, 0x8a, 0xc7, 0x11, 0x08, 0xb9, 0x90, 0xa6,
0x82, 0xdf, 0x5e, 0xda, 0xd2, 0xfa, 0xc2, 0x9b, 0xed, 0xfe, 0xfc, 0xe0, 0xe1, 0x81, 0x27, 0x62,
0x26, 0x8b, 0x82, 0xd8, 0x6a, 0x47, 0x82, 0x03, 0x49, 0xed, 0x3d, 0x3a, 0x32, 0x0e, 0xa5, 0x71,
0x11, 0x83, 0xd3, 0x56, 0x0e, 0x7a, 0x44, 0xa9, 0xbd, 0xf9, 0x9a, 0x07, 0xe1, 0x03, 0x47, 0xbe,
0x68, 0x76, 0x27, 0xe6, 0x6b, 0xd7, 0x43, 0xfd, 0x1e, 0x83, 0x71, 0xf4, 0xba, 0xbc, 0x2f, 0xa1,
0xf8, 0xd1, 0x76, 0xc2, 0x36, 0xbb, 0xca, 0x6f, 0xab, 0xb7, 0x75, 0xe9, 0x6e, 0xa0, 0x79, 0x71,
0x11, 0x09, 0xc3, 0xfd, 0x5d, 0xc2, 0x15, 0xc7, 0xee, 0xf1, 0x21, 0xe1, 0x4e, 0x36, 0x77, 0x0d,
0x95, 0x62, 0xb6, 0x09, 0x52, 0x6e, 0xa4, 0x87, 0xfa, 0x99, 0xa7, 0xc1, 0x62, 0x02, 0x65, 0xff,
0x79, 0xa0, 0x7e, 0x23, 0x8e, 0xab, 0x69, 0x0f, 0xcd, 0xb9, 0xca, 0xcb, 0xdd, 0xd5, 0x50, 0x7d,
0xb0, 0xf9, 0x5e, 0x98, 0x3a, 0xfb, 0x3c, 0x9d, 0x9b, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xba,
0x37, 0x25, 0xea, 0x44, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,33 @@
// Built-in base types for API calls. Primarily useful as return types.
syntax = "proto2";
option go_package = "base";
package appengine.base;
message StringProto {
required string value = 1;
}
message Integer32Proto {
required int32 value = 1;
}
message Integer64Proto {
required int64 value = 1;
}
message BoolProto {
required bool value = 1;
}
message DoubleProto {
required double value = 1;
}
message BytesProto {
required bytes value = 1 [ctype=CORD];
}
message VoidProto {
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,551 @@
syntax = "proto2";
option go_package = "datastore";
package appengine;
message Action{}
message PropertyValue {
optional int64 int64Value = 1;
optional bool booleanValue = 2;
optional string stringValue = 3;
optional double doubleValue = 4;
optional group PointValue = 5 {
required double x = 6;
required double y = 7;
}
optional group UserValue = 8 {
required string email = 9;
required string auth_domain = 10;
optional string nickname = 11;
optional string federated_identity = 21;
optional string federated_provider = 22;
}
optional group ReferenceValue = 12 {
required string app = 13;
optional string name_space = 20;
repeated group PathElement = 14 {
required string type = 15;
optional int64 id = 16;
optional string name = 17;
}
}
}
message Property {
enum Meaning {
NO_MEANING = 0;
BLOB = 14;
TEXT = 15;
BYTESTRING = 16;
ATOM_CATEGORY = 1;
ATOM_LINK = 2;
ATOM_TITLE = 3;
ATOM_CONTENT = 4;
ATOM_SUMMARY = 5;
ATOM_AUTHOR = 6;
GD_WHEN = 7;
GD_EMAIL = 8;
GEORSS_POINT = 9;
GD_IM = 10;
GD_PHONENUMBER = 11;
GD_POSTALADDRESS = 12;
GD_RATING = 13;
BLOBKEY = 17;
ENTITY_PROTO = 19;
INDEX_VALUE = 18;
};
optional Meaning meaning = 1 [default = NO_MEANING];
optional string meaning_uri = 2;
required string name = 3;
required PropertyValue value = 5;
required bool multiple = 4;
optional bool searchable = 6 [default=false];
enum FtsTokenizationOption {
HTML = 1;
ATOM = 2;
}
optional FtsTokenizationOption fts_tokenization_option = 8;
optional string locale = 9 [default = "en"];
}
message Path {
repeated group Element = 1 {
required string type = 2;
optional int64 id = 3;
optional string name = 4;
}
}
message Reference {
required string app = 13;
optional string name_space = 20;
required Path path = 14;
}
message User {
required string email = 1;
required string auth_domain = 2;
optional string nickname = 3;
optional string federated_identity = 6;
optional string federated_provider = 7;
}
message EntityProto {
required Reference key = 13;
required Path entity_group = 16;
optional User owner = 17;
enum Kind {
GD_CONTACT = 1;
GD_EVENT = 2;
GD_MESSAGE = 3;
}
optional Kind kind = 4;
optional string kind_uri = 5;
repeated Property property = 14;
repeated Property raw_property = 15;
optional int32 rank = 18;
}
message CompositeProperty {
required int64 index_id = 1;
repeated string value = 2;
}
message Index {
required string entity_type = 1;
required bool ancestor = 5;
repeated group Property = 2 {
required string name = 3;
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
optional Direction direction = 4 [default = ASCENDING];
}
}
message CompositeIndex {
required string app_id = 1;
required int64 id = 2;
required Index definition = 3;
enum State {
WRITE_ONLY = 1;
READ_WRITE = 2;
DELETED = 3;
ERROR = 4;
}
required State state = 4;
optional bool only_use_if_required = 6 [default = false];
}
message IndexPostfix {
message IndexValue {
required string property_name = 1;
required PropertyValue value = 2;
}
repeated IndexValue index_value = 1;
optional Reference key = 2;
optional bool before = 3 [default=true];
}
message IndexPosition {
optional string key = 1;
optional bool before = 2 [default=true];
}
message Snapshot {
enum Status {
INACTIVE = 0;
ACTIVE = 1;
}
required int64 ts = 1;
}
message InternalHeader {
optional string qos = 1;
}
message Transaction {
optional InternalHeader header = 4;
required fixed64 handle = 1;
required string app = 2;
optional bool mark_changes = 3 [default = false];
}
message Query {
optional InternalHeader header = 39;
required string app = 1;
optional string name_space = 29;
optional string kind = 3;
optional Reference ancestor = 17;
repeated group Filter = 4 {
enum Operator {
LESS_THAN = 1;
LESS_THAN_OR_EQUAL = 2;
GREATER_THAN = 3;
GREATER_THAN_OR_EQUAL = 4;
EQUAL = 5;
IN = 6;
EXISTS = 7;
}
required Operator op = 6;
repeated Property property = 14;
}
optional string search_query = 8;
repeated group Order = 9 {
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
required string property = 10;
optional Direction direction = 11 [default = ASCENDING];
}
enum Hint {
ORDER_FIRST = 1;
ANCESTOR_FIRST = 2;
FILTER_FIRST = 3;
}
optional Hint hint = 18;
optional int32 count = 23;
optional int32 offset = 12 [default = 0];
optional int32 limit = 16;
optional CompiledCursor compiled_cursor = 30;
optional CompiledCursor end_compiled_cursor = 31;
repeated CompositeIndex composite_index = 19;
optional bool require_perfect_plan = 20 [default = false];
optional bool keys_only = 21 [default = false];
optional Transaction transaction = 22;
optional bool compile = 25 [default = false];
optional int64 failover_ms = 26;
optional bool strong = 32;
repeated string property_name = 33;
repeated string group_by_property_name = 34;
optional bool distinct = 24;
optional int64 min_safe_time_seconds = 35;
repeated string safe_replica_name = 36;
optional bool persist_offset = 37 [default=false];
}
message CompiledQuery {
required group PrimaryScan = 1 {
optional string index_name = 2;
optional string start_key = 3;
optional bool start_inclusive = 4;
optional string end_key = 5;
optional bool end_inclusive = 6;
repeated string start_postfix_value = 22;
repeated string end_postfix_value = 23;
optional int64 end_unapplied_log_timestamp_us = 19;
}
repeated group MergeJoinScan = 7 {
required string index_name = 8;
repeated string prefix_value = 9;
optional bool value_prefix = 20 [default=false];
}
optional Index index_def = 21;
optional int32 offset = 10 [default = 0];
optional int32 limit = 11;
required bool keys_only = 12;
repeated string property_name = 24;
optional int32 distinct_infix_size = 25;
optional group EntityFilter = 13 {
optional bool distinct = 14 [default=false];
optional string kind = 17;
optional Reference ancestor = 18;
}
}
message CompiledCursor {
optional group Position = 2 {
optional string start_key = 27;
repeated group IndexValue = 29 {
optional string property = 30;
required PropertyValue value = 31;
}
optional Reference key = 32;
optional bool start_inclusive = 28 [default=true];
}
}
message Cursor {
required fixed64 cursor = 1;
optional string app = 2;
}
message Error {
enum ErrorCode {
BAD_REQUEST = 1;
CONCURRENT_TRANSACTION = 2;
INTERNAL_ERROR = 3;
NEED_INDEX = 4;
TIMEOUT = 5;
PERMISSION_DENIED = 6;
BIGTABLE_ERROR = 7;
COMMITTED_BUT_STILL_APPLYING = 8;
CAPABILITY_DISABLED = 9;
TRY_ALTERNATE_BACKEND = 10;
SAFE_TIME_TOO_OLD = 11;
}
}
message Cost {
optional int32 index_writes = 1;
optional int32 index_write_bytes = 2;
optional int32 entity_writes = 3;
optional int32 entity_write_bytes = 4;
optional group CommitCost = 5 {
optional int32 requested_entity_puts = 6;
optional int32 requested_entity_deletes = 7;
};
optional int32 approximate_storage_delta = 8;
optional int32 id_sequence_updates = 9;
}
message GetRequest {
optional InternalHeader header = 6;
repeated Reference key = 1;
optional Transaction transaction = 2;
optional int64 failover_ms = 3;
optional bool strong = 4;
optional bool allow_deferred = 5 [default=false];
}
message GetResponse {
repeated group Entity = 1 {
optional EntityProto entity = 2;
optional Reference key = 4;
optional int64 version = 3;
}
repeated Reference deferred = 5;
optional bool in_order = 6 [default=true];
}
message PutRequest {
optional InternalHeader header = 11;
repeated EntityProto entity = 1;
optional Transaction transaction = 2;
repeated CompositeIndex composite_index = 3;
optional bool trusted = 4 [default = false];
optional bool force = 7 [default = false];
optional bool mark_changes = 8 [default = false];
repeated Snapshot snapshot = 9;
enum AutoIdPolicy {
CURRENT = 0;
SEQUENTIAL = 1;
}
optional AutoIdPolicy auto_id_policy = 10 [default = CURRENT];
}
message PutResponse {
repeated Reference key = 1;
optional Cost cost = 2;
repeated int64 version = 3;
}
message TouchRequest {
optional InternalHeader header = 10;
repeated Reference key = 1;
repeated CompositeIndex composite_index = 2;
optional bool force = 3 [default = false];
repeated Snapshot snapshot = 9;
}
message TouchResponse {
optional Cost cost = 1;
}
message DeleteRequest {
optional InternalHeader header = 10;
repeated Reference key = 6;
optional Transaction transaction = 5;
optional bool trusted = 4 [default = false];
optional bool force = 7 [default = false];
optional bool mark_changes = 8 [default = false];
repeated Snapshot snapshot = 9;
}
message DeleteResponse {
optional Cost cost = 1;
repeated int64 version = 3;
}
message NextRequest {
optional InternalHeader header = 5;
required Cursor cursor = 1;
optional int32 count = 2;
optional int32 offset = 4 [default = 0];
optional bool compile = 3 [default = false];
}
message QueryResult {
optional Cursor cursor = 1;
repeated EntityProto result = 2;
optional int32 skipped_results = 7;
required bool more_results = 3;
optional bool keys_only = 4;
optional bool index_only = 9;
optional bool small_ops = 10;
optional CompiledQuery compiled_query = 5;
optional CompiledCursor compiled_cursor = 6;
repeated CompositeIndex index = 8;
repeated int64 version = 11;
}
message AllocateIdsRequest {
optional InternalHeader header = 4;
optional Reference model_key = 1;
optional int64 size = 2;
optional int64 max = 3;
repeated Reference reserve = 5;
}
message AllocateIdsResponse {
required int64 start = 1;
required int64 end = 2;
optional Cost cost = 3;
}
message CompositeIndices {
repeated CompositeIndex index = 1;
}
message AddActionsRequest {
optional InternalHeader header = 3;
required Transaction transaction = 1;
repeated Action action = 2;
}
message AddActionsResponse {
}
message BeginTransactionRequest {
optional InternalHeader header = 3;
required string app = 1;
optional bool allow_multiple_eg = 2 [default = false];
optional string database_id = 4;
enum TransactionMode {
UNKNOWN = 0;
READ_ONLY = 1;
READ_WRITE = 2;
}
optional TransactionMode mode = 5 [default = UNKNOWN];
optional Transaction previous_transaction = 7;
}
message CommitResponse {
optional Cost cost = 1;
repeated group Version = 3 {
required Reference root_entity_key = 4;
required int64 version = 5;
}
}

View File

@ -0,0 +1,55 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"os"
netcontext "golang.org/x/net/context"
)
var (
// This is set to true in identity_classic.go, which is behind the appengine build tag.
// The appengine build tag is set for the first generation runtimes (<= Go 1.9) but not
// the second generation runtimes (>= Go 1.11), so this indicates whether we're on a
// first-gen runtime. See IsStandard below for the second-gen check.
appengineStandard bool
// This is set to true in identity_flex.go, which is behind the appenginevm build tag.
appengineFlex bool
)
// AppID is the implementation of the wrapper function of the same name in
// ../identity.go. See that file for commentary.
func AppID(c netcontext.Context) string {
return appID(FullyQualifiedAppID(c))
}
// IsStandard is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsStandard() bool {
// appengineStandard will be true for first-gen runtimes (<= Go 1.9) but not
// second-gen (>= Go 1.11).
return appengineStandard || IsSecondGen()
}
// IsStandard is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsSecondGen() bool {
// Second-gen runtimes set $GAE_ENV so we use that to check if we're on a second-gen runtime.
return os.Getenv("GAE_ENV") == "standard"
}
// IsFlex is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsFlex() bool {
return appengineFlex
}
// IsAppEngine is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsAppEngine() bool {
return IsStandard() || IsFlex()
}

View File

@ -0,0 +1,61 @@
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"appengine"
netcontext "golang.org/x/net/context"
)
func init() {
appengineStandard = true
}
func DefaultVersionHostname(ctx netcontext.Context) string {
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
return appengine.DefaultVersionHostname(c)
}
func Datacenter(_ netcontext.Context) string { return appengine.Datacenter() }
func ServerSoftware() string { return appengine.ServerSoftware() }
func InstanceID() string { return appengine.InstanceID() }
func IsDevAppServer() bool { return appengine.IsDevAppServer() }
func RequestID(ctx netcontext.Context) string {
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
return appengine.RequestID(c)
}
func ModuleName(ctx netcontext.Context) string {
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
return appengine.ModuleName(c)
}
func VersionID(ctx netcontext.Context) string {
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
return appengine.VersionID(c)
}
func fullyQualifiedAppID(ctx netcontext.Context) string {
c := fromContext(ctx)
if c == nil {
panic(errNotAppEngineContext)
}
return c.FullyQualifiedAppID()
}

View File

@ -0,0 +1,11 @@
// Copyright 2018 Google LLC. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appenginevm
package internal
func init() {
appengineFlex = true
}

View File

@ -0,0 +1,134 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"log"
"net/http"
"os"
"strings"
netcontext "golang.org/x/net/context"
)
// These functions are implementations of the wrapper functions
// in ../appengine/identity.go. See that file for commentary.
const (
hDefaultVersionHostname = "X-AppEngine-Default-Version-Hostname"
hRequestLogId = "X-AppEngine-Request-Log-Id"
hDatacenter = "X-AppEngine-Datacenter"
)
func ctxHeaders(ctx netcontext.Context) http.Header {
c := fromContext(ctx)
if c == nil {
return nil
}
return c.Request().Header
}
func DefaultVersionHostname(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hDefaultVersionHostname)
}
func RequestID(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hRequestLogId)
}
func Datacenter(ctx netcontext.Context) string {
if dc := ctxHeaders(ctx).Get(hDatacenter); dc != "" {
return dc
}
// If the header isn't set, read zone from the metadata service.
// It has the format projects/[NUMERIC_PROJECT_ID]/zones/[ZONE]
zone, err := getMetadata("instance/zone")
if err != nil {
log.Printf("Datacenter: %v", err)
return ""
}
parts := strings.Split(string(zone), "/")
if len(parts) == 0 {
return ""
}
return parts[len(parts)-1]
}
func ServerSoftware() string {
// TODO(dsymonds): Remove fallback when we've verified this.
if s := os.Getenv("SERVER_SOFTWARE"); s != "" {
return s
}
if s := os.Getenv("GAE_ENV"); s != "" {
return s
}
return "Google App Engine/1.x.x"
}
// TODO(dsymonds): Remove the metadata fetches.
func ModuleName(_ netcontext.Context) string {
if s := os.Getenv("GAE_MODULE_NAME"); s != "" {
return s
}
if s := os.Getenv("GAE_SERVICE"); s != "" {
return s
}
return string(mustGetMetadata("instance/attributes/gae_backend_name"))
}
func VersionID(_ netcontext.Context) string {
if s1, s2 := os.Getenv("GAE_MODULE_VERSION"), os.Getenv("GAE_MINOR_VERSION"); s1 != "" && s2 != "" {
return s1 + "." + s2
}
if s1, s2 := os.Getenv("GAE_VERSION"), os.Getenv("GAE_DEPLOYMENT_ID"); s1 != "" && s2 != "" {
return s1 + "." + s2
}
return string(mustGetMetadata("instance/attributes/gae_backend_version")) + "." + string(mustGetMetadata("instance/attributes/gae_backend_minor_version"))
}
func InstanceID() string {
if s := os.Getenv("GAE_MODULE_INSTANCE"); s != "" {
return s
}
if s := os.Getenv("GAE_INSTANCE"); s != "" {
return s
}
return string(mustGetMetadata("instance/attributes/gae_backend_instance"))
}
func partitionlessAppID() string {
// gae_project has everything except the partition prefix.
if appID := os.Getenv("GAE_LONG_APP_ID"); appID != "" {
return appID
}
if project := os.Getenv("GOOGLE_CLOUD_PROJECT"); project != "" {
return project
}
return string(mustGetMetadata("instance/attributes/gae_project"))
}
func fullyQualifiedAppID(_ netcontext.Context) string {
if s := os.Getenv("GAE_APPLICATION"); s != "" {
return s
}
appID := partitionlessAppID()
part := os.Getenv("GAE_PARTITION")
if part == "" {
part = string(mustGetMetadata("instance/attributes/gae_partition"))
}
if part != "" {
appID = part + "~" + appID
}
return appID
}
func IsDevAppServer() bool {
return os.Getenv("RUN_WITH_DEVAPPSERVER") != ""
}

View File

@ -0,0 +1,110 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// Package internal provides support for package appengine.
//
// Programs should not use this package directly. Its API is not stable.
// Use packages appengine and appengine/* instead.
package internal
import (
"fmt"
"github.com/golang/protobuf/proto"
remotepb "google.golang.org/appengine/internal/remote_api"
)
// errorCodeMaps is a map of service name to the error code map for the service.
var errorCodeMaps = make(map[string]map[int32]string)
// RegisterErrorCodeMap is called from API implementations to register their
// error code map. This should only be called from init functions.
func RegisterErrorCodeMap(service string, m map[int32]string) {
errorCodeMaps[service] = m
}
type timeoutCodeKey struct {
service string
code int32
}
// timeoutCodes is the set of service+code pairs that represent timeouts.
var timeoutCodes = make(map[timeoutCodeKey]bool)
func RegisterTimeoutErrorCode(service string, code int32) {
timeoutCodes[timeoutCodeKey{service, code}] = true
}
// APIError is the type returned by appengine.Context's Call method
// when an API call fails in an API-specific way. This may be, for instance,
// a taskqueue API call failing with TaskQueueServiceError::UNKNOWN_QUEUE.
type APIError struct {
Service string
Detail string
Code int32 // API-specific error code
}
func (e *APIError) Error() string {
if e.Code == 0 {
if e.Detail == "" {
return "APIError <empty>"
}
return e.Detail
}
s := fmt.Sprintf("API error %d", e.Code)
if m, ok := errorCodeMaps[e.Service]; ok {
s += " (" + e.Service + ": " + m[e.Code] + ")"
} else {
// Shouldn't happen, but provide a bit more detail if it does.
s = e.Service + " " + s
}
if e.Detail != "" {
s += ": " + e.Detail
}
return s
}
func (e *APIError) IsTimeout() bool {
return timeoutCodes[timeoutCodeKey{e.Service, e.Code}]
}
// CallError is the type returned by appengine.Context's Call method when an
// API call fails in a generic way, such as RpcError::CAPABILITY_DISABLED.
type CallError struct {
Detail string
Code int32
// TODO: Remove this if we get a distinguishable error code.
Timeout bool
}
func (e *CallError) Error() string {
var msg string
switch remotepb.RpcError_ErrorCode(e.Code) {
case remotepb.RpcError_UNKNOWN:
return e.Detail
case remotepb.RpcError_OVER_QUOTA:
msg = "Over quota"
case remotepb.RpcError_CAPABILITY_DISABLED:
msg = "Capability disabled"
case remotepb.RpcError_CANCELLED:
msg = "Canceled"
default:
msg = fmt.Sprintf("Call error %d", e.Code)
}
s := msg + ": " + e.Detail
if e.Timeout {
s += " (timeout)"
}
return s
}
func (e *CallError) IsTimeout() bool {
return e.Timeout
}
// NamespaceMods is a map from API service to a function that will mutate an RPC request to attach a namespace.
// The function should be prepared to be called on the same message more than once; it should only modify the
// RPC request the first time.
var NamespaceMods = make(map[string]func(m proto.Message, namespace string))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,150 @@
syntax = "proto2";
option go_package = "log";
package appengine;
message LogServiceError {
enum ErrorCode {
OK = 0;
INVALID_REQUEST = 1;
STORAGE_ERROR = 2;
}
}
message UserAppLogLine {
required int64 timestamp_usec = 1;
required int64 level = 2;
required string message = 3;
}
message UserAppLogGroup {
repeated UserAppLogLine log_line = 2;
}
message FlushRequest {
optional bytes logs = 1;
}
message SetStatusRequest {
required string status = 1;
}
message LogOffset {
optional bytes request_id = 1;
}
message LogLine {
required int64 time = 1;
required int32 level = 2;
required string log_message = 3;
}
message RequestLog {
required string app_id = 1;
optional string module_id = 37 [default="default"];
required string version_id = 2;
required bytes request_id = 3;
optional LogOffset offset = 35;
required string ip = 4;
optional string nickname = 5;
required int64 start_time = 6;
required int64 end_time = 7;
required int64 latency = 8;
required int64 mcycles = 9;
required string method = 10;
required string resource = 11;
required string http_version = 12;
required int32 status = 13;
required int64 response_size = 14;
optional string referrer = 15;
optional string user_agent = 16;
required string url_map_entry = 17;
required string combined = 18;
optional int64 api_mcycles = 19;
optional string host = 20;
optional double cost = 21;
optional string task_queue_name = 22;
optional string task_name = 23;
optional bool was_loading_request = 24;
optional int64 pending_time = 25;
optional int32 replica_index = 26 [default = -1];
optional bool finished = 27 [default = true];
optional bytes clone_key = 28;
repeated LogLine line = 29;
optional bool lines_incomplete = 36;
optional bytes app_engine_release = 38;
optional int32 exit_reason = 30;
optional bool was_throttled_for_time = 31;
optional bool was_throttled_for_requests = 32;
optional int64 throttled_time = 33;
optional bytes server_name = 34;
}
message LogModuleVersion {
optional string module_id = 1 [default="default"];
optional string version_id = 2;
}
message LogReadRequest {
required string app_id = 1;
repeated string version_id = 2;
repeated LogModuleVersion module_version = 19;
optional int64 start_time = 3;
optional int64 end_time = 4;
optional LogOffset offset = 5;
repeated bytes request_id = 6;
optional int32 minimum_log_level = 7;
optional bool include_incomplete = 8;
optional int64 count = 9;
optional string combined_log_regex = 14;
optional string host_regex = 15;
optional int32 replica_index = 16;
optional bool include_app_logs = 10;
optional int32 app_logs_per_request = 17;
optional bool include_host = 11;
optional bool include_all = 12;
optional bool cache_iterator = 13;
optional int32 num_shards = 18;
}
message LogReadResponse {
repeated RequestLog log = 1;
optional LogOffset offset = 2;
optional int64 last_end_time = 3;
}
message LogUsageRecord {
optional string version_id = 1;
optional int32 start_time = 2;
optional int32 end_time = 3;
optional int64 count = 4;
optional int64 total_size = 5;
optional int32 records = 6;
}
message LogUsageRequest {
required string app_id = 1;
repeated string version_id = 2;
optional int32 start_time = 3;
optional int32 end_time = 4;
optional uint32 resolution_hours = 5 [default = 1];
optional bool combine_versions = 6;
optional int32 usage_version = 7;
optional bool versions_only = 8;
}
message LogUsageResponse {
repeated LogUsageRecord usage = 1;
optional LogUsageRecord summary = 2;
}

View File

@ -0,0 +1,16 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"appengine_internal"
)
func Main() {
MainPath = ""
appengine_internal.Main()
}

View File

@ -0,0 +1,7 @@
package internal
// MainPath stores the file path of the main package. On App Engine Standard
// using Go version 1.9 and below, this will be unset. On App Engine Flex and
// App Engine Standard second-gen (Go 1.11 and above), this will be the
// filepath to package main.
var MainPath string

View File

@ -0,0 +1,69 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
)
func Main() {
MainPath = filepath.Dir(findMainPath())
installHealthChecker(http.DefaultServeMux)
port := "8080"
if s := os.Getenv("PORT"); s != "" {
port = s
}
host := ""
if IsDevAppServer() {
host = "127.0.0.1"
}
if err := http.ListenAndServe(host+":"+port, http.HandlerFunc(handleHTTP)); err != nil {
log.Fatalf("http.ListenAndServe: %v", err)
}
}
// Find the path to package main by looking at the root Caller.
func findMainPath() string {
pc := make([]uintptr, 100)
n := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:n])
for {
frame, more := frames.Next()
// Tests won't have package main, instead they have testing.tRunner
if frame.Function == "main.main" || frame.Function == "testing.tRunner" {
return frame.File
}
if !more {
break
}
}
return ""
}
func installHealthChecker(mux *http.ServeMux) {
// If no health check handler has been installed by this point, add a trivial one.
const healthPath = "/_ah/health"
hreq := &http.Request{
Method: "GET",
URL: &url.URL{
Path: healthPath,
},
}
if _, pat := mux.Handler(hreq); pat != healthPath {
mux.HandleFunc(healthPath, func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "ok")
})
}
}

View File

@ -0,0 +1,60 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file has code for accessing metadata.
//
// References:
// https://cloud.google.com/compute/docs/metadata
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
const (
metadataHost = "metadata"
metadataPath = "/computeMetadata/v1/"
)
var (
metadataRequestHeaders = http.Header{
"Metadata-Flavor": []string{"Google"},
}
)
// TODO(dsymonds): Do we need to support default values, like Python?
func mustGetMetadata(key string) []byte {
b, err := getMetadata(key)
if err != nil {
panic(fmt.Sprintf("Metadata fetch failed for '%s': %v", key, err))
}
return b
}
func getMetadata(key string) ([]byte, error) {
// TODO(dsymonds): May need to use url.Parse to support keys with query args.
req := &http.Request{
Method: "GET",
URL: &url.URL{
Scheme: "http",
Host: metadataHost,
Path: metadataPath + key,
},
Header: metadataRequestHeaders,
Host: metadataHost,
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("metadata server returned HTTP %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}

View File

@ -0,0 +1,56 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file implements a network dialer that limits the number of concurrent connections.
// It is only used for API calls.
import (
"log"
"net"
"runtime"
"sync"
"time"
)
var limitSem = make(chan int, 100) // TODO(dsymonds): Use environment variable.
func limitRelease() {
// non-blocking
select {
case <-limitSem:
default:
// This should not normally happen.
log.Print("appengine: unbalanced limitSem release!")
}
}
func limitDial(network, addr string) (net.Conn, error) {
limitSem <- 1
// Dial with a timeout in case the API host is MIA.
// The connection should normally be very fast.
conn, err := net.DialTimeout(network, addr, 10*time.Second)
if err != nil {
limitRelease()
return nil, err
}
lc := &limitConn{Conn: conn}
runtime.SetFinalizer(lc, (*limitConn).Close) // shouldn't usually be required
return lc, nil
}
type limitConn struct {
close sync.Once
net.Conn
}
func (lc *limitConn) Close() error {
defer lc.close.Do(func() {
limitRelease()
runtime.SetFinalizer(lc, nil)
})
return lc.Conn.Close()
}

View File

@ -0,0 +1,40 @@
#!/bin/bash -e
#
# This script rebuilds the generated code for the protocol buffers.
# To run this you will need protoc and goprotobuf installed;
# see https://github.com/golang/protobuf for instructions.
PKG=google.golang.org/appengine
function die() {
echo 1>&2 $*
exit 1
}
# Sanity check that the right tools are accessible.
for tool in go protoc protoc-gen-go; do
q=$(which $tool) || die "didn't find $tool"
echo 1>&2 "$tool: $q"
done
echo -n 1>&2 "finding package dir... "
pkgdir=$(go list -f '{{.Dir}}' $PKG)
echo 1>&2 $pkgdir
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
echo 1>&2 "base: $base"
cd $base
# Run protoc once per package.
for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do
echo 1>&2 "* $dir"
protoc --go_out=. $dir/*.proto
done
for f in $(find $PKG/internal -name '*.pb.go'); do
# Remove proto.RegisterEnum calls.
# These cause duplicate registration panics when these packages
# are used on classic App Engine. proto.RegisterEnum only affects
# parsing the text format; we don't care about that.
# https://code.google.com/p/googleappengine/issues/detail?id=11670#c17
sed -i '/proto.RegisterEnum/d' $f
done

View File

@ -0,0 +1,361 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google.golang.org/appengine/internal/remote_api/remote_api.proto
package remote_api
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type RpcError_ErrorCode int32
const (
RpcError_UNKNOWN RpcError_ErrorCode = 0
RpcError_CALL_NOT_FOUND RpcError_ErrorCode = 1
RpcError_PARSE_ERROR RpcError_ErrorCode = 2
RpcError_SECURITY_VIOLATION RpcError_ErrorCode = 3
RpcError_OVER_QUOTA RpcError_ErrorCode = 4
RpcError_REQUEST_TOO_LARGE RpcError_ErrorCode = 5
RpcError_CAPABILITY_DISABLED RpcError_ErrorCode = 6
RpcError_FEATURE_DISABLED RpcError_ErrorCode = 7
RpcError_BAD_REQUEST RpcError_ErrorCode = 8
RpcError_RESPONSE_TOO_LARGE RpcError_ErrorCode = 9
RpcError_CANCELLED RpcError_ErrorCode = 10
RpcError_REPLAY_ERROR RpcError_ErrorCode = 11
RpcError_DEADLINE_EXCEEDED RpcError_ErrorCode = 12
)
var RpcError_ErrorCode_name = map[int32]string{
0: "UNKNOWN",
1: "CALL_NOT_FOUND",
2: "PARSE_ERROR",
3: "SECURITY_VIOLATION",
4: "OVER_QUOTA",
5: "REQUEST_TOO_LARGE",
6: "CAPABILITY_DISABLED",
7: "FEATURE_DISABLED",
8: "BAD_REQUEST",
9: "RESPONSE_TOO_LARGE",
10: "CANCELLED",
11: "REPLAY_ERROR",
12: "DEADLINE_EXCEEDED",
}
var RpcError_ErrorCode_value = map[string]int32{
"UNKNOWN": 0,
"CALL_NOT_FOUND": 1,
"PARSE_ERROR": 2,
"SECURITY_VIOLATION": 3,
"OVER_QUOTA": 4,
"REQUEST_TOO_LARGE": 5,
"CAPABILITY_DISABLED": 6,
"FEATURE_DISABLED": 7,
"BAD_REQUEST": 8,
"RESPONSE_TOO_LARGE": 9,
"CANCELLED": 10,
"REPLAY_ERROR": 11,
"DEADLINE_EXCEEDED": 12,
}
func (x RpcError_ErrorCode) Enum() *RpcError_ErrorCode {
p := new(RpcError_ErrorCode)
*p = x
return p
}
func (x RpcError_ErrorCode) String() string {
return proto.EnumName(RpcError_ErrorCode_name, int32(x))
}
func (x *RpcError_ErrorCode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(RpcError_ErrorCode_value, data, "RpcError_ErrorCode")
if err != nil {
return err
}
*x = RpcError_ErrorCode(value)
return nil
}
func (RpcError_ErrorCode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_remote_api_1978114ec33a273d, []int{2, 0}
}
type Request struct {
ServiceName *string `protobuf:"bytes,2,req,name=service_name,json=serviceName" json:"service_name,omitempty"`
Method *string `protobuf:"bytes,3,req,name=method" json:"method,omitempty"`
Request []byte `protobuf:"bytes,4,req,name=request" json:"request,omitempty"`
RequestId *string `protobuf:"bytes,5,opt,name=request_id,json=requestId" json:"request_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Request) Reset() { *m = Request{} }
func (m *Request) String() string { return proto.CompactTextString(m) }
func (*Request) ProtoMessage() {}
func (*Request) Descriptor() ([]byte, []int) {
return fileDescriptor_remote_api_1978114ec33a273d, []int{0}
}
func (m *Request) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Request.Unmarshal(m, b)
}
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
}
func (dst *Request) XXX_Merge(src proto.Message) {
xxx_messageInfo_Request.Merge(dst, src)
}
func (m *Request) XXX_Size() int {
return xxx_messageInfo_Request.Size(m)
}
func (m *Request) XXX_DiscardUnknown() {
xxx_messageInfo_Request.DiscardUnknown(m)
}
var xxx_messageInfo_Request proto.InternalMessageInfo
func (m *Request) GetServiceName() string {
if m != nil && m.ServiceName != nil {
return *m.ServiceName
}
return ""
}
func (m *Request) GetMethod() string {
if m != nil && m.Method != nil {
return *m.Method
}
return ""
}
func (m *Request) GetRequest() []byte {
if m != nil {
return m.Request
}
return nil
}
func (m *Request) GetRequestId() string {
if m != nil && m.RequestId != nil {
return *m.RequestId
}
return ""
}
type ApplicationError struct {
Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"`
Detail *string `protobuf:"bytes,2,req,name=detail" json:"detail,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplicationError) Reset() { *m = ApplicationError{} }
func (m *ApplicationError) String() string { return proto.CompactTextString(m) }
func (*ApplicationError) ProtoMessage() {}
func (*ApplicationError) Descriptor() ([]byte, []int) {
return fileDescriptor_remote_api_1978114ec33a273d, []int{1}
}
func (m *ApplicationError) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationError.Unmarshal(m, b)
}
func (m *ApplicationError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationError.Marshal(b, m, deterministic)
}
func (dst *ApplicationError) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationError.Merge(dst, src)
}
func (m *ApplicationError) XXX_Size() int {
return xxx_messageInfo_ApplicationError.Size(m)
}
func (m *ApplicationError) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationError.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationError proto.InternalMessageInfo
func (m *ApplicationError) GetCode() int32 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *ApplicationError) GetDetail() string {
if m != nil && m.Detail != nil {
return *m.Detail
}
return ""
}
type RpcError struct {
Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"`
Detail *string `protobuf:"bytes,2,opt,name=detail" json:"detail,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RpcError) Reset() { *m = RpcError{} }
func (m *RpcError) String() string { return proto.CompactTextString(m) }
func (*RpcError) ProtoMessage() {}
func (*RpcError) Descriptor() ([]byte, []int) {
return fileDescriptor_remote_api_1978114ec33a273d, []int{2}
}
func (m *RpcError) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RpcError.Unmarshal(m, b)
}
func (m *RpcError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RpcError.Marshal(b, m, deterministic)
}
func (dst *RpcError) XXX_Merge(src proto.Message) {
xxx_messageInfo_RpcError.Merge(dst, src)
}
func (m *RpcError) XXX_Size() int {
return xxx_messageInfo_RpcError.Size(m)
}
func (m *RpcError) XXX_DiscardUnknown() {
xxx_messageInfo_RpcError.DiscardUnknown(m)
}
var xxx_messageInfo_RpcError proto.InternalMessageInfo
func (m *RpcError) GetCode() int32 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *RpcError) GetDetail() string {
if m != nil && m.Detail != nil {
return *m.Detail
}
return ""
}
type Response struct {
Response []byte `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"`
Exception []byte `protobuf:"bytes,2,opt,name=exception" json:"exception,omitempty"`
ApplicationError *ApplicationError `protobuf:"bytes,3,opt,name=application_error,json=applicationError" json:"application_error,omitempty"`
JavaException []byte `protobuf:"bytes,4,opt,name=java_exception,json=javaException" json:"java_exception,omitempty"`
RpcError *RpcError `protobuf:"bytes,5,opt,name=rpc_error,json=rpcError" json:"rpc_error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Response) Reset() { *m = Response{} }
func (m *Response) String() string { return proto.CompactTextString(m) }
func (*Response) ProtoMessage() {}
func (*Response) Descriptor() ([]byte, []int) {
return fileDescriptor_remote_api_1978114ec33a273d, []int{3}
}
func (m *Response) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Response.Unmarshal(m, b)
}
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
}
func (dst *Response) XXX_Merge(src proto.Message) {
xxx_messageInfo_Response.Merge(dst, src)
}
func (m *Response) XXX_Size() int {
return xxx_messageInfo_Response.Size(m)
}
func (m *Response) XXX_DiscardUnknown() {
xxx_messageInfo_Response.DiscardUnknown(m)
}
var xxx_messageInfo_Response proto.InternalMessageInfo
func (m *Response) GetResponse() []byte {
if m != nil {
return m.Response
}
return nil
}
func (m *Response) GetException() []byte {
if m != nil {
return m.Exception
}
return nil
}
func (m *Response) GetApplicationError() *ApplicationError {
if m != nil {
return m.ApplicationError
}
return nil
}
func (m *Response) GetJavaException() []byte {
if m != nil {
return m.JavaException
}
return nil
}
func (m *Response) GetRpcError() *RpcError {
if m != nil {
return m.RpcError
}
return nil
}
func init() {
proto.RegisterType((*Request)(nil), "remote_api.Request")
proto.RegisterType((*ApplicationError)(nil), "remote_api.ApplicationError")
proto.RegisterType((*RpcError)(nil), "remote_api.RpcError")
proto.RegisterType((*Response)(nil), "remote_api.Response")
}
func init() {
proto.RegisterFile("google.golang.org/appengine/internal/remote_api/remote_api.proto", fileDescriptor_remote_api_1978114ec33a273d)
}
var fileDescriptor_remote_api_1978114ec33a273d = []byte{
// 531 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x51, 0x6e, 0xd3, 0x40,
0x10, 0x86, 0xb1, 0x9b, 0x34, 0xf1, 0xc4, 0x2d, 0xdb, 0xa5, 0x14, 0x0b, 0x15, 0x29, 0x44, 0x42,
0xca, 0x53, 0x2a, 0x38, 0x00, 0x62, 0x63, 0x6f, 0x91, 0x85, 0x65, 0xa7, 0x6b, 0xbb, 0x50, 0x5e,
0x56, 0x2b, 0x67, 0x65, 0x8c, 0x12, 0xaf, 0xd9, 0x98, 0x8a, 0x17, 0x6e, 0xc0, 0xb5, 0x38, 0x0c,
0xb7, 0x40, 0x36, 0x6e, 0x63, 0xf5, 0x89, 0xb7, 0x7f, 0x7e, 0x7b, 0xe6, 0x1b, 0xcd, 0xcc, 0xc2,
0xbb, 0x5c, 0xa9, 0x7c, 0x23, 0x17, 0xb9, 0xda, 0x88, 0x32, 0x5f, 0x28, 0x9d, 0x5f, 0x88, 0xaa,
0x92, 0x65, 0x5e, 0x94, 0xf2, 0xa2, 0x28, 0x6b, 0xa9, 0x4b, 0xb1, 0xb9, 0xd0, 0x72, 0xab, 0x6a,
0xc9, 0x45, 0x55, 0xf4, 0xe4, 0xa2, 0xd2, 0xaa, 0x56, 0x18, 0xf6, 0xce, 0xec, 0x27, 0x8c, 0x98,
0xfc, 0xf6, 0x5d, 0xee, 0x6a, 0xfc, 0x12, 0xec, 0x9d, 0xd4, 0xb7, 0x45, 0x26, 0x79, 0x29, 0xb6,
0xd2, 0x31, 0xa7, 0xe6, 0xdc, 0x62, 0x93, 0xce, 0x0b, 0xc5, 0x56, 0xe2, 0x33, 0x38, 0xdc, 0xca,
0xfa, 0x8b, 0x5a, 0x3b, 0x07, 0xed, 0xc7, 0x2e, 0xc2, 0x0e, 0x8c, 0xf4, 0xbf, 0x2a, 0xce, 0x60,
0x6a, 0xce, 0x6d, 0x76, 0x17, 0xe2, 0x17, 0x00, 0x9d, 0xe4, 0xc5, 0xda, 0x19, 0x4e, 0x8d, 0xb9,
0xc5, 0xac, 0xce, 0xf1, 0xd7, 0xb3, 0xb7, 0x80, 0x48, 0x55, 0x6d, 0x8a, 0x4c, 0xd4, 0x85, 0x2a,
0xa9, 0xd6, 0x4a, 0x63, 0x0c, 0x83, 0x4c, 0xad, 0xa5, 0x63, 0x4c, 0xcd, 0xf9, 0x90, 0xb5, 0xba,
0x01, 0xaf, 0x65, 0x2d, 0x8a, 0x4d, 0xd7, 0x55, 0x17, 0xcd, 0x7e, 0x9b, 0x30, 0x66, 0x55, 0xf6,
0x7f, 0x89, 0x46, 0x2f, 0xf1, 0x97, 0x09, 0x56, 0x9b, 0xe5, 0x36, 0x7f, 0x4d, 0x60, 0x94, 0x86,
0x1f, 0xc2, 0xe8, 0x63, 0x88, 0x1e, 0x61, 0x0c, 0xc7, 0x2e, 0x09, 0x02, 0x1e, 0x46, 0x09, 0xbf,
0x8c, 0xd2, 0xd0, 0x43, 0x06, 0x7e, 0x0c, 0x93, 0x15, 0x61, 0x31, 0xe5, 0x94, 0xb1, 0x88, 0x21,
0x13, 0x9f, 0x01, 0x8e, 0xa9, 0x9b, 0x32, 0x3f, 0xb9, 0xe1, 0xd7, 0x7e, 0x14, 0x90, 0xc4, 0x8f,
0x42, 0x74, 0x80, 0x8f, 0x01, 0xa2, 0x6b, 0xca, 0xf8, 0x55, 0x1a, 0x25, 0x04, 0x0d, 0xf0, 0x53,
0x38, 0x61, 0xf4, 0x2a, 0xa5, 0x71, 0xc2, 0x93, 0x28, 0xe2, 0x01, 0x61, 0xef, 0x29, 0x1a, 0xe2,
0x67, 0xf0, 0xc4, 0x25, 0x2b, 0xb2, 0xf4, 0x83, 0xa6, 0x80, 0xe7, 0xc7, 0x64, 0x19, 0x50, 0x0f,
0x1d, 0xe2, 0x53, 0x40, 0x97, 0x94, 0x24, 0x29, 0xa3, 0x7b, 0x77, 0xd4, 0xe0, 0x97, 0xc4, 0xe3,
0x5d, 0x25, 0x34, 0x6e, 0xf0, 0x8c, 0xc6, 0xab, 0x28, 0x8c, 0x69, 0xaf, 0xae, 0x85, 0x8f, 0xc0,
0x72, 0x49, 0xe8, 0xd2, 0xa0, 0xc9, 0x03, 0x8c, 0xc0, 0x66, 0x74, 0x15, 0x90, 0x9b, 0xae, 0xef,
0x49, 0xd3, 0x8f, 0x47, 0x89, 0x17, 0xf8, 0x21, 0xe5, 0xf4, 0x93, 0x4b, 0xa9, 0x47, 0x3d, 0x64,
0xcf, 0xfe, 0x18, 0x30, 0x66, 0x72, 0x57, 0xa9, 0x72, 0x27, 0xf1, 0x73, 0x18, 0xeb, 0x4e, 0x3b,
0xc6, 0xd4, 0x98, 0xdb, 0xec, 0x3e, 0xc6, 0xe7, 0x60, 0xc9, 0x1f, 0x99, 0xac, 0x9a, 0x75, 0xb5,
0x23, 0xb5, 0xd9, 0xde, 0xc0, 0x3e, 0x9c, 0x88, 0xfd, 0x3a, 0xb9, 0x6c, 0x06, 0xec, 0x1c, 0x4c,
0x8d, 0xf9, 0xe4, 0xcd, 0xf9, 0xa2, 0x77, 0x87, 0x0f, 0x77, 0xce, 0x90, 0x78, 0x78, 0x05, 0xaf,
0xe0, 0xf8, 0xab, 0xb8, 0x15, 0x7c, 0x4f, 0x1b, 0xb4, 0xb4, 0xa3, 0xc6, 0xa5, 0xf7, 0xc4, 0xd7,
0x60, 0xe9, 0x2a, 0xeb, 0x48, 0xc3, 0x96, 0x74, 0xda, 0x27, 0xdd, 0x1d, 0x07, 0x1b, 0xeb, 0x4e,
0x2d, 0xed, 0xcf, 0xbd, 0x07, 0xf0, 0x37, 0x00, 0x00, 0xff, 0xff, 0x38, 0xd1, 0x0f, 0x22, 0x4f,
0x03, 0x00, 0x00,
}

View File

@ -0,0 +1,44 @@
syntax = "proto2";
option go_package = "remote_api";
package remote_api;
message Request {
required string service_name = 2;
required string method = 3;
required bytes request = 4;
optional string request_id = 5;
}
message ApplicationError {
required int32 code = 1;
required string detail = 2;
}
message RpcError {
enum ErrorCode {
UNKNOWN = 0;
CALL_NOT_FOUND = 1;
PARSE_ERROR = 2;
SECURITY_VIOLATION = 3;
OVER_QUOTA = 4;
REQUEST_TOO_LARGE = 5;
CAPABILITY_DISABLED = 6;
FEATURE_DISABLED = 7;
BAD_REQUEST = 8;
RESPONSE_TOO_LARGE = 9;
CANCELLED = 10;
REPLAY_ERROR = 11;
DEADLINE_EXCEEDED = 12;
}
required int32 code = 1;
optional string detail = 2;
}
message Response {
optional bytes response = 1;
optional bytes exception = 2;
optional ApplicationError application_error = 3;
optional bytes java_exception = 4;
optional RpcError rpc_error = 5;
}

View File

@ -0,0 +1,115 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file implements hooks for applying datastore transactions.
import (
"errors"
"reflect"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
pb "google.golang.org/appengine/internal/datastore"
)
var transactionSetters = make(map[reflect.Type]reflect.Value)
// RegisterTransactionSetter registers a function that sets transaction information
// in a protocol buffer message. f should be a function with two arguments,
// the first being a protocol buffer type, and the second being *datastore.Transaction.
func RegisterTransactionSetter(f interface{}) {
v := reflect.ValueOf(f)
transactionSetters[v.Type().In(0)] = v
}
// applyTransaction applies the transaction t to message pb
// by using the relevant setter passed to RegisterTransactionSetter.
func applyTransaction(pb proto.Message, t *pb.Transaction) {
v := reflect.ValueOf(pb)
if f, ok := transactionSetters[v.Type()]; ok {
f.Call([]reflect.Value{v, reflect.ValueOf(t)})
}
}
var transactionKey = "used for *Transaction"
func transactionFromContext(ctx netcontext.Context) *transaction {
t, _ := ctx.Value(&transactionKey).(*transaction)
return t
}
func withTransaction(ctx netcontext.Context, t *transaction) netcontext.Context {
return netcontext.WithValue(ctx, &transactionKey, t)
}
type transaction struct {
transaction pb.Transaction
finished bool
}
var ErrConcurrentTransaction = errors.New("internal: concurrent transaction")
func RunTransactionOnce(c netcontext.Context, f func(netcontext.Context) error, xg bool, readOnly bool, previousTransaction *pb.Transaction) (*pb.Transaction, error) {
if transactionFromContext(c) != nil {
return nil, errors.New("nested transactions are not supported")
}
// Begin the transaction.
t := &transaction{}
req := &pb.BeginTransactionRequest{
App: proto.String(FullyQualifiedAppID(c)),
}
if xg {
req.AllowMultipleEg = proto.Bool(true)
}
if previousTransaction != nil {
req.PreviousTransaction = previousTransaction
}
if readOnly {
req.Mode = pb.BeginTransactionRequest_READ_ONLY.Enum()
} else {
req.Mode = pb.BeginTransactionRequest_READ_WRITE.Enum()
}
if err := Call(c, "datastore_v3", "BeginTransaction", req, &t.transaction); err != nil {
return nil, err
}
// Call f, rolling back the transaction if f returns a non-nil error, or panics.
// The panic is not recovered.
defer func() {
if t.finished {
return
}
t.finished = true
// Ignore the error return value, since we are already returning a non-nil
// error (or we're panicking).
Call(c, "datastore_v3", "Rollback", &t.transaction, &basepb.VoidProto{})
}()
if err := f(withTransaction(c, t)); err != nil {
return &t.transaction, err
}
t.finished = true
// Commit the transaction.
res := &pb.CommitResponse{}
err := Call(c, "datastore_v3", "Commit", &t.transaction, res)
if ae, ok := err.(*APIError); ok {
/* TODO: restore this conditional
if appengine.IsDevAppServer() {
*/
// The Python Dev AppServer raises an ApplicationError with error code 2 (which is
// Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.".
if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." {
return &t.transaction, ErrConcurrentTransaction
}
if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) {
return &t.transaction, ErrConcurrentTransaction
}
}
return &t.transaction, err
}

View File

@ -0,0 +1,527 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto
package urlfetch
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type URLFetchServiceError_ErrorCode int32
const (
URLFetchServiceError_OK URLFetchServiceError_ErrorCode = 0
URLFetchServiceError_INVALID_URL URLFetchServiceError_ErrorCode = 1
URLFetchServiceError_FETCH_ERROR URLFetchServiceError_ErrorCode = 2
URLFetchServiceError_UNSPECIFIED_ERROR URLFetchServiceError_ErrorCode = 3
URLFetchServiceError_RESPONSE_TOO_LARGE URLFetchServiceError_ErrorCode = 4
URLFetchServiceError_DEADLINE_EXCEEDED URLFetchServiceError_ErrorCode = 5
URLFetchServiceError_SSL_CERTIFICATE_ERROR URLFetchServiceError_ErrorCode = 6
URLFetchServiceError_DNS_ERROR URLFetchServiceError_ErrorCode = 7
URLFetchServiceError_CLOSED URLFetchServiceError_ErrorCode = 8
URLFetchServiceError_INTERNAL_TRANSIENT_ERROR URLFetchServiceError_ErrorCode = 9
URLFetchServiceError_TOO_MANY_REDIRECTS URLFetchServiceError_ErrorCode = 10
URLFetchServiceError_MALFORMED_REPLY URLFetchServiceError_ErrorCode = 11
URLFetchServiceError_CONNECTION_ERROR URLFetchServiceError_ErrorCode = 12
)
var URLFetchServiceError_ErrorCode_name = map[int32]string{
0: "OK",
1: "INVALID_URL",
2: "FETCH_ERROR",
3: "UNSPECIFIED_ERROR",
4: "RESPONSE_TOO_LARGE",
5: "DEADLINE_EXCEEDED",
6: "SSL_CERTIFICATE_ERROR",
7: "DNS_ERROR",
8: "CLOSED",
9: "INTERNAL_TRANSIENT_ERROR",
10: "TOO_MANY_REDIRECTS",
11: "MALFORMED_REPLY",
12: "CONNECTION_ERROR",
}
var URLFetchServiceError_ErrorCode_value = map[string]int32{
"OK": 0,
"INVALID_URL": 1,
"FETCH_ERROR": 2,
"UNSPECIFIED_ERROR": 3,
"RESPONSE_TOO_LARGE": 4,
"DEADLINE_EXCEEDED": 5,
"SSL_CERTIFICATE_ERROR": 6,
"DNS_ERROR": 7,
"CLOSED": 8,
"INTERNAL_TRANSIENT_ERROR": 9,
"TOO_MANY_REDIRECTS": 10,
"MALFORMED_REPLY": 11,
"CONNECTION_ERROR": 12,
}
func (x URLFetchServiceError_ErrorCode) Enum() *URLFetchServiceError_ErrorCode {
p := new(URLFetchServiceError_ErrorCode)
*p = x
return p
}
func (x URLFetchServiceError_ErrorCode) String() string {
return proto.EnumName(URLFetchServiceError_ErrorCode_name, int32(x))
}
func (x *URLFetchServiceError_ErrorCode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(URLFetchServiceError_ErrorCode_value, data, "URLFetchServiceError_ErrorCode")
if err != nil {
return err
}
*x = URLFetchServiceError_ErrorCode(value)
return nil
}
func (URLFetchServiceError_ErrorCode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{0, 0}
}
type URLFetchRequest_RequestMethod int32
const (
URLFetchRequest_GET URLFetchRequest_RequestMethod = 1
URLFetchRequest_POST URLFetchRequest_RequestMethod = 2
URLFetchRequest_HEAD URLFetchRequest_RequestMethod = 3
URLFetchRequest_PUT URLFetchRequest_RequestMethod = 4
URLFetchRequest_DELETE URLFetchRequest_RequestMethod = 5
URLFetchRequest_PATCH URLFetchRequest_RequestMethod = 6
)
var URLFetchRequest_RequestMethod_name = map[int32]string{
1: "GET",
2: "POST",
3: "HEAD",
4: "PUT",
5: "DELETE",
6: "PATCH",
}
var URLFetchRequest_RequestMethod_value = map[string]int32{
"GET": 1,
"POST": 2,
"HEAD": 3,
"PUT": 4,
"DELETE": 5,
"PATCH": 6,
}
func (x URLFetchRequest_RequestMethod) Enum() *URLFetchRequest_RequestMethod {
p := new(URLFetchRequest_RequestMethod)
*p = x
return p
}
func (x URLFetchRequest_RequestMethod) String() string {
return proto.EnumName(URLFetchRequest_RequestMethod_name, int32(x))
}
func (x *URLFetchRequest_RequestMethod) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(URLFetchRequest_RequestMethod_value, data, "URLFetchRequest_RequestMethod")
if err != nil {
return err
}
*x = URLFetchRequest_RequestMethod(value)
return nil
}
func (URLFetchRequest_RequestMethod) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{1, 0}
}
type URLFetchServiceError struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *URLFetchServiceError) Reset() { *m = URLFetchServiceError{} }
func (m *URLFetchServiceError) String() string { return proto.CompactTextString(m) }
func (*URLFetchServiceError) ProtoMessage() {}
func (*URLFetchServiceError) Descriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{0}
}
func (m *URLFetchServiceError) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_URLFetchServiceError.Unmarshal(m, b)
}
func (m *URLFetchServiceError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_URLFetchServiceError.Marshal(b, m, deterministic)
}
func (dst *URLFetchServiceError) XXX_Merge(src proto.Message) {
xxx_messageInfo_URLFetchServiceError.Merge(dst, src)
}
func (m *URLFetchServiceError) XXX_Size() int {
return xxx_messageInfo_URLFetchServiceError.Size(m)
}
func (m *URLFetchServiceError) XXX_DiscardUnknown() {
xxx_messageInfo_URLFetchServiceError.DiscardUnknown(m)
}
var xxx_messageInfo_URLFetchServiceError proto.InternalMessageInfo
type URLFetchRequest struct {
Method *URLFetchRequest_RequestMethod `protobuf:"varint,1,req,name=Method,enum=appengine.URLFetchRequest_RequestMethod" json:"Method,omitempty"`
Url *string `protobuf:"bytes,2,req,name=Url" json:"Url,omitempty"`
Header []*URLFetchRequest_Header `protobuf:"group,3,rep,name=Header,json=header" json:"header,omitempty"`
Payload []byte `protobuf:"bytes,6,opt,name=Payload" json:"Payload,omitempty"`
FollowRedirects *bool `protobuf:"varint,7,opt,name=FollowRedirects,def=1" json:"FollowRedirects,omitempty"`
Deadline *float64 `protobuf:"fixed64,8,opt,name=Deadline" json:"Deadline,omitempty"`
MustValidateServerCertificate *bool `protobuf:"varint,9,opt,name=MustValidateServerCertificate,def=1" json:"MustValidateServerCertificate,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *URLFetchRequest) Reset() { *m = URLFetchRequest{} }
func (m *URLFetchRequest) String() string { return proto.CompactTextString(m) }
func (*URLFetchRequest) ProtoMessage() {}
func (*URLFetchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{1}
}
func (m *URLFetchRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_URLFetchRequest.Unmarshal(m, b)
}
func (m *URLFetchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_URLFetchRequest.Marshal(b, m, deterministic)
}
func (dst *URLFetchRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_URLFetchRequest.Merge(dst, src)
}
func (m *URLFetchRequest) XXX_Size() int {
return xxx_messageInfo_URLFetchRequest.Size(m)
}
func (m *URLFetchRequest) XXX_DiscardUnknown() {
xxx_messageInfo_URLFetchRequest.DiscardUnknown(m)
}
var xxx_messageInfo_URLFetchRequest proto.InternalMessageInfo
const Default_URLFetchRequest_FollowRedirects bool = true
const Default_URLFetchRequest_MustValidateServerCertificate bool = true
func (m *URLFetchRequest) GetMethod() URLFetchRequest_RequestMethod {
if m != nil && m.Method != nil {
return *m.Method
}
return URLFetchRequest_GET
}
func (m *URLFetchRequest) GetUrl() string {
if m != nil && m.Url != nil {
return *m.Url
}
return ""
}
func (m *URLFetchRequest) GetHeader() []*URLFetchRequest_Header {
if m != nil {
return m.Header
}
return nil
}
func (m *URLFetchRequest) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *URLFetchRequest) GetFollowRedirects() bool {
if m != nil && m.FollowRedirects != nil {
return *m.FollowRedirects
}
return Default_URLFetchRequest_FollowRedirects
}
func (m *URLFetchRequest) GetDeadline() float64 {
if m != nil && m.Deadline != nil {
return *m.Deadline
}
return 0
}
func (m *URLFetchRequest) GetMustValidateServerCertificate() bool {
if m != nil && m.MustValidateServerCertificate != nil {
return *m.MustValidateServerCertificate
}
return Default_URLFetchRequest_MustValidateServerCertificate
}
type URLFetchRequest_Header struct {
Key *string `protobuf:"bytes,4,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,5,req,name=Value" json:"Value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *URLFetchRequest_Header) Reset() { *m = URLFetchRequest_Header{} }
func (m *URLFetchRequest_Header) String() string { return proto.CompactTextString(m) }
func (*URLFetchRequest_Header) ProtoMessage() {}
func (*URLFetchRequest_Header) Descriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{1, 0}
}
func (m *URLFetchRequest_Header) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_URLFetchRequest_Header.Unmarshal(m, b)
}
func (m *URLFetchRequest_Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_URLFetchRequest_Header.Marshal(b, m, deterministic)
}
func (dst *URLFetchRequest_Header) XXX_Merge(src proto.Message) {
xxx_messageInfo_URLFetchRequest_Header.Merge(dst, src)
}
func (m *URLFetchRequest_Header) XXX_Size() int {
return xxx_messageInfo_URLFetchRequest_Header.Size(m)
}
func (m *URLFetchRequest_Header) XXX_DiscardUnknown() {
xxx_messageInfo_URLFetchRequest_Header.DiscardUnknown(m)
}
var xxx_messageInfo_URLFetchRequest_Header proto.InternalMessageInfo
func (m *URLFetchRequest_Header) GetKey() string {
if m != nil && m.Key != nil {
return *m.Key
}
return ""
}
func (m *URLFetchRequest_Header) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
type URLFetchResponse struct {
Content []byte `protobuf:"bytes,1,opt,name=Content" json:"Content,omitempty"`
StatusCode *int32 `protobuf:"varint,2,req,name=StatusCode" json:"StatusCode,omitempty"`
Header []*URLFetchResponse_Header `protobuf:"group,3,rep,name=Header,json=header" json:"header,omitempty"`
ContentWasTruncated *bool `protobuf:"varint,6,opt,name=ContentWasTruncated,def=0" json:"ContentWasTruncated,omitempty"`
ExternalBytesSent *int64 `protobuf:"varint,7,opt,name=ExternalBytesSent" json:"ExternalBytesSent,omitempty"`
ExternalBytesReceived *int64 `protobuf:"varint,8,opt,name=ExternalBytesReceived" json:"ExternalBytesReceived,omitempty"`
FinalUrl *string `protobuf:"bytes,9,opt,name=FinalUrl" json:"FinalUrl,omitempty"`
ApiCpuMilliseconds *int64 `protobuf:"varint,10,opt,name=ApiCpuMilliseconds,def=0" json:"ApiCpuMilliseconds,omitempty"`
ApiBytesSent *int64 `protobuf:"varint,11,opt,name=ApiBytesSent,def=0" json:"ApiBytesSent,omitempty"`
ApiBytesReceived *int64 `protobuf:"varint,12,opt,name=ApiBytesReceived,def=0" json:"ApiBytesReceived,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *URLFetchResponse) Reset() { *m = URLFetchResponse{} }
func (m *URLFetchResponse) String() string { return proto.CompactTextString(m) }
func (*URLFetchResponse) ProtoMessage() {}
func (*URLFetchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{2}
}
func (m *URLFetchResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_URLFetchResponse.Unmarshal(m, b)
}
func (m *URLFetchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_URLFetchResponse.Marshal(b, m, deterministic)
}
func (dst *URLFetchResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_URLFetchResponse.Merge(dst, src)
}
func (m *URLFetchResponse) XXX_Size() int {
return xxx_messageInfo_URLFetchResponse.Size(m)
}
func (m *URLFetchResponse) XXX_DiscardUnknown() {
xxx_messageInfo_URLFetchResponse.DiscardUnknown(m)
}
var xxx_messageInfo_URLFetchResponse proto.InternalMessageInfo
const Default_URLFetchResponse_ContentWasTruncated bool = false
const Default_URLFetchResponse_ApiCpuMilliseconds int64 = 0
const Default_URLFetchResponse_ApiBytesSent int64 = 0
const Default_URLFetchResponse_ApiBytesReceived int64 = 0
func (m *URLFetchResponse) GetContent() []byte {
if m != nil {
return m.Content
}
return nil
}
func (m *URLFetchResponse) GetStatusCode() int32 {
if m != nil && m.StatusCode != nil {
return *m.StatusCode
}
return 0
}
func (m *URLFetchResponse) GetHeader() []*URLFetchResponse_Header {
if m != nil {
return m.Header
}
return nil
}
func (m *URLFetchResponse) GetContentWasTruncated() bool {
if m != nil && m.ContentWasTruncated != nil {
return *m.ContentWasTruncated
}
return Default_URLFetchResponse_ContentWasTruncated
}
func (m *URLFetchResponse) GetExternalBytesSent() int64 {
if m != nil && m.ExternalBytesSent != nil {
return *m.ExternalBytesSent
}
return 0
}
func (m *URLFetchResponse) GetExternalBytesReceived() int64 {
if m != nil && m.ExternalBytesReceived != nil {
return *m.ExternalBytesReceived
}
return 0
}
func (m *URLFetchResponse) GetFinalUrl() string {
if m != nil && m.FinalUrl != nil {
return *m.FinalUrl
}
return ""
}
func (m *URLFetchResponse) GetApiCpuMilliseconds() int64 {
if m != nil && m.ApiCpuMilliseconds != nil {
return *m.ApiCpuMilliseconds
}
return Default_URLFetchResponse_ApiCpuMilliseconds
}
func (m *URLFetchResponse) GetApiBytesSent() int64 {
if m != nil && m.ApiBytesSent != nil {
return *m.ApiBytesSent
}
return Default_URLFetchResponse_ApiBytesSent
}
func (m *URLFetchResponse) GetApiBytesReceived() int64 {
if m != nil && m.ApiBytesReceived != nil {
return *m.ApiBytesReceived
}
return Default_URLFetchResponse_ApiBytesReceived
}
type URLFetchResponse_Header struct {
Key *string `protobuf:"bytes,4,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,5,req,name=Value" json:"Value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *URLFetchResponse_Header) Reset() { *m = URLFetchResponse_Header{} }
func (m *URLFetchResponse_Header) String() string { return proto.CompactTextString(m) }
func (*URLFetchResponse_Header) ProtoMessage() {}
func (*URLFetchResponse_Header) Descriptor() ([]byte, []int) {
return fileDescriptor_urlfetch_service_b245a7065f33bced, []int{2, 0}
}
func (m *URLFetchResponse_Header) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_URLFetchResponse_Header.Unmarshal(m, b)
}
func (m *URLFetchResponse_Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_URLFetchResponse_Header.Marshal(b, m, deterministic)
}
func (dst *URLFetchResponse_Header) XXX_Merge(src proto.Message) {
xxx_messageInfo_URLFetchResponse_Header.Merge(dst, src)
}
func (m *URLFetchResponse_Header) XXX_Size() int {
return xxx_messageInfo_URLFetchResponse_Header.Size(m)
}
func (m *URLFetchResponse_Header) XXX_DiscardUnknown() {
xxx_messageInfo_URLFetchResponse_Header.DiscardUnknown(m)
}
var xxx_messageInfo_URLFetchResponse_Header proto.InternalMessageInfo
func (m *URLFetchResponse_Header) GetKey() string {
if m != nil && m.Key != nil {
return *m.Key
}
return ""
}
func (m *URLFetchResponse_Header) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
func init() {
proto.RegisterType((*URLFetchServiceError)(nil), "appengine.URLFetchServiceError")
proto.RegisterType((*URLFetchRequest)(nil), "appengine.URLFetchRequest")
proto.RegisterType((*URLFetchRequest_Header)(nil), "appengine.URLFetchRequest.Header")
proto.RegisterType((*URLFetchResponse)(nil), "appengine.URLFetchResponse")
proto.RegisterType((*URLFetchResponse_Header)(nil), "appengine.URLFetchResponse.Header")
}
func init() {
proto.RegisterFile("google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto", fileDescriptor_urlfetch_service_b245a7065f33bced)
}
var fileDescriptor_urlfetch_service_b245a7065f33bced = []byte{
// 770 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0xe3, 0x54,
0x10, 0xc6, 0x76, 0x7e, 0xa7, 0x5d, 0x7a, 0x76, 0xb6, 0x45, 0x66, 0xb5, 0xa0, 0x10, 0x09, 0x29,
0x17, 0x90, 0x2e, 0x2b, 0x24, 0x44, 0xaf, 0x70, 0xed, 0x93, 0xad, 0xa9, 0x63, 0x47, 0xc7, 0x4e,
0x61, 0xb9, 0xb1, 0xac, 0x78, 0x9a, 0x5a, 0xb2, 0xec, 0x60, 0x9f, 0x2c, 0xf4, 0x35, 0x78, 0x0d,
0xde, 0x87, 0xa7, 0xe1, 0x02, 0x9d, 0xc4, 0xc9, 0x6e, 0xbb, 0xd1, 0x4a, 0x5c, 0x65, 0xe6, 0x9b,
0xef, 0xcc, 0x99, 0x7c, 0xdf, 0xf8, 0x80, 0xb3, 0x2c, 0xcb, 0x65, 0x4e, 0xe3, 0x65, 0x99, 0x27,
0xc5, 0x72, 0x5c, 0x56, 0xcb, 0xf3, 0x64, 0xb5, 0xa2, 0x62, 0x99, 0x15, 0x74, 0x9e, 0x15, 0x92,
0xaa, 0x22, 0xc9, 0xcf, 0xd7, 0x55, 0x7e, 0x4b, 0x72, 0x71, 0xb7, 0x0f, 0xe2, 0x9a, 0xaa, 0xb7,
0xd9, 0x82, 0xc6, 0xab, 0xaa, 0x94, 0x25, 0xf6, 0xf7, 0x67, 0x86, 0x7f, 0xeb, 0x70, 0x3a, 0x17,
0xde, 0x44, 0xb1, 0xc2, 0x2d, 0x89, 0x57, 0x55, 0x59, 0x0d, 0xff, 0xd2, 0xa1, 0xbf, 0x89, 0xec,
0x32, 0x25, 0xec, 0x80, 0x1e, 0x5c, 0xb3, 0x4f, 0xf0, 0x04, 0x8e, 0x5c, 0xff, 0xc6, 0xf2, 0x5c,
0x27, 0x9e, 0x0b, 0x8f, 0x69, 0x0a, 0x98, 0xf0, 0xc8, 0xbe, 0x8a, 0xb9, 0x10, 0x81, 0x60, 0x3a,
0x9e, 0xc1, 0xd3, 0xb9, 0x1f, 0xce, 0xb8, 0xed, 0x4e, 0x5c, 0xee, 0x34, 0xb0, 0x81, 0x9f, 0x01,
0x0a, 0x1e, 0xce, 0x02, 0x3f, 0xe4, 0x71, 0x14, 0x04, 0xb1, 0x67, 0x89, 0xd7, 0x9c, 0xb5, 0x14,
0xdd, 0xe1, 0x96, 0xe3, 0xb9, 0x3e, 0x8f, 0xf9, 0xaf, 0x36, 0xe7, 0x0e, 0x77, 0x58, 0x1b, 0x3f,
0x87, 0xb3, 0x30, 0xf4, 0x62, 0x9b, 0x8b, 0xc8, 0x9d, 0xb8, 0xb6, 0x15, 0xf1, 0xa6, 0x53, 0x07,
0x9f, 0x40, 0xdf, 0xf1, 0xc3, 0x26, 0xed, 0x22, 0x40, 0xc7, 0xf6, 0x82, 0x90, 0x3b, 0xac, 0x87,
0x2f, 0xc0, 0x74, 0xfd, 0x88, 0x0b, 0xdf, 0xf2, 0xe2, 0x48, 0x58, 0x7e, 0xe8, 0x72, 0x3f, 0x6a,
0x98, 0x7d, 0x35, 0x82, 0xba, 0x79, 0x6a, 0xf9, 0x6f, 0x62, 0xc1, 0x1d, 0x57, 0x70, 0x3b, 0x0a,
0x19, 0xe0, 0x33, 0x38, 0x99, 0x5a, 0xde, 0x24, 0x10, 0x53, 0xee, 0xc4, 0x82, 0xcf, 0xbc, 0x37,
0xec, 0x08, 0x4f, 0x81, 0xd9, 0x81, 0xef, 0x73, 0x3b, 0x72, 0x03, 0xbf, 0x69, 0x71, 0x3c, 0xfc,
0xc7, 0x80, 0x93, 0x9d, 0x5a, 0x82, 0x7e, 0x5f, 0x53, 0x2d, 0xf1, 0x27, 0xe8, 0x4c, 0x49, 0xde,
0x95, 0xa9, 0xa9, 0x0d, 0xf4, 0xd1, 0xa7, 0xaf, 0x46, 0xe3, 0xbd, 0xba, 0xe3, 0x47, 0xdc, 0x71,
0xf3, 0xbb, 0xe5, 0x8b, 0xe6, 0x1c, 0x32, 0x30, 0xe6, 0x55, 0x6e, 0xea, 0x03, 0x7d, 0xd4, 0x17,
0x2a, 0xc4, 0x1f, 0xa1, 0x73, 0x47, 0x49, 0x4a, 0x95, 0x69, 0x0c, 0x8c, 0x11, 0xbc, 0xfa, 0xea,
0x23, 0x3d, 0xaf, 0x36, 0x44, 0xd1, 0x1c, 0xc0, 0x17, 0xd0, 0x9d, 0x25, 0xf7, 0x79, 0x99, 0xa4,
0x66, 0x67, 0xa0, 0x8d, 0x8e, 0x2f, 0xf5, 0x9e, 0x26, 0x76, 0x10, 0x8e, 0xe1, 0x64, 0x52, 0xe6,
0x79, 0xf9, 0x87, 0xa0, 0x34, 0xab, 0x68, 0x21, 0x6b, 0xb3, 0x3b, 0xd0, 0x46, 0xbd, 0x8b, 0x96,
0xac, 0xd6, 0x24, 0x1e, 0x17, 0xf1, 0x39, 0xf4, 0x1c, 0x4a, 0xd2, 0x3c, 0x2b, 0xc8, 0xec, 0x0d,
0xb4, 0x91, 0x26, 0xf6, 0x39, 0xfe, 0x0c, 0x5f, 0x4c, 0xd7, 0xb5, 0xbc, 0x49, 0xf2, 0x2c, 0x4d,
0x24, 0xa9, 0xed, 0xa1, 0xca, 0xa6, 0x4a, 0x66, 0xb7, 0xd9, 0x22, 0x91, 0x64, 0xf6, 0xdf, 0xeb,
0xfc, 0x71, 0xea, 0xf3, 0x97, 0xd0, 0xd9, 0xfe, 0x0f, 0x25, 0xc6, 0x35, 0xdd, 0x9b, 0xad, 0xad,
0x18, 0xd7, 0x74, 0x8f, 0xa7, 0xd0, 0xbe, 0x49, 0xf2, 0x35, 0x99, 0xed, 0x0d, 0xb6, 0x4d, 0x86,
0x1e, 0x3c, 0x79, 0xa0, 0x26, 0x76, 0xc1, 0x78, 0xcd, 0x23, 0xa6, 0x61, 0x0f, 0x5a, 0xb3, 0x20,
0x8c, 0x98, 0xae, 0xa2, 0x2b, 0x6e, 0x39, 0xcc, 0x50, 0xc5, 0xd9, 0x3c, 0x62, 0x2d, 0xb5, 0x2e,
0x0e, 0xf7, 0x78, 0xc4, 0x59, 0x1b, 0xfb, 0xd0, 0x9e, 0x59, 0x91, 0x7d, 0xc5, 0x3a, 0xc3, 0x7f,
0x0d, 0x60, 0xef, 0x84, 0xad, 0x57, 0x65, 0x51, 0x13, 0x9a, 0xd0, 0xb5, 0xcb, 0x42, 0x52, 0x21,
0x4d, 0x4d, 0x49, 0x29, 0x76, 0x29, 0x7e, 0x09, 0x10, 0xca, 0x44, 0xae, 0x6b, 0xf5, 0x71, 0x6c,
0x8c, 0x6b, 0x8b, 0xf7, 0x10, 0xbc, 0x78, 0xe4, 0xdf, 0xf0, 0xa0, 0x7f, 0xdb, 0x6b, 0x1e, 0x1b,
0xf8, 0x03, 0x3c, 0x6b, 0xae, 0xf9, 0x25, 0xa9, 0xa3, 0x6a, 0x5d, 0x28, 0x81, 0xb6, 0x66, 0xf6,
0x2e, 0xda, 0xb7, 0x49, 0x5e, 0x93, 0x38, 0xc4, 0xc0, 0x6f, 0xe0, 0x29, 0xff, 0x73, 0xfb, 0x02,
0x5c, 0xde, 0x4b, 0xaa, 0x43, 0x35, 0xb8, 0x72, 0xd7, 0x10, 0x1f, 0x16, 0xf0, 0x7b, 0x38, 0x7b,
0x00, 0x0a, 0x5a, 0x50, 0xf6, 0x96, 0xd2, 0x8d, 0xcd, 0x86, 0x38, 0x5c, 0x54, 0xfb, 0x30, 0xc9,
0x8a, 0x24, 0x57, 0xfb, 0xaa, 0xec, 0xed, 0x8b, 0x7d, 0x8e, 0xdf, 0x01, 0x5a, 0xab, 0xcc, 0x5e,
0xad, 0xa7, 0x59, 0x9e, 0x67, 0x35, 0x2d, 0xca, 0x22, 0xad, 0x4d, 0x50, 0xed, 0x2e, 0xb4, 0x97,
0xe2, 0x40, 0x11, 0xbf, 0x86, 0x63, 0x6b, 0x95, 0xbd, 0x9b, 0xf6, 0x68, 0x47, 0x7e, 0x00, 0xe3,
0xb7, 0xc0, 0x76, 0xf9, 0x7e, 0xcc, 0xe3, 0x1d, 0xf5, 0x83, 0xd2, 0xff, 0x5f, 0xa6, 0x4b, 0xf8,
0xad, 0xb7, 0x7b, 0x2a, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x9f, 0x6d, 0x24, 0x63, 0x05,
0x00, 0x00,
}

View File

@ -0,0 +1,64 @@
syntax = "proto2";
option go_package = "urlfetch";
package appengine;
message URLFetchServiceError {
enum ErrorCode {
OK = 0;
INVALID_URL = 1;
FETCH_ERROR = 2;
UNSPECIFIED_ERROR = 3;
RESPONSE_TOO_LARGE = 4;
DEADLINE_EXCEEDED = 5;
SSL_CERTIFICATE_ERROR = 6;
DNS_ERROR = 7;
CLOSED = 8;
INTERNAL_TRANSIENT_ERROR = 9;
TOO_MANY_REDIRECTS = 10;
MALFORMED_REPLY = 11;
CONNECTION_ERROR = 12;
}
}
message URLFetchRequest {
enum RequestMethod {
GET = 1;
POST = 2;
HEAD = 3;
PUT = 4;
DELETE = 5;
PATCH = 6;
}
required RequestMethod Method = 1;
required string Url = 2;
repeated group Header = 3 {
required string Key = 4;
required string Value = 5;
}
optional bytes Payload = 6 [ctype=CORD];
optional bool FollowRedirects = 7 [default=true];
optional double Deadline = 8;
optional bool MustValidateServerCertificate = 9 [default=true];
}
message URLFetchResponse {
optional bytes Content = 1;
required int32 StatusCode = 2;
repeated group Header = 3 {
required string Key = 4;
required string Value = 5;
}
optional bool ContentWasTruncated = 6 [default=false];
optional int64 ExternalBytesSent = 7;
optional int64 ExternalBytesReceived = 8;
optional string FinalUrl = 9;
optional int64 ApiCpuMilliseconds = 10 [default=0];
optional int64 ApiBytesSent = 11 [default=0];
optional int64 ApiBytesReceived = 12 [default=0];
}

View File

@ -0,0 +1,210 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// Package urlfetch provides an http.RoundTripper implementation
// for fetching URLs via App Engine's urlfetch service.
package urlfetch // import "google.golang.org/appengine/urlfetch"
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
pb "google.golang.org/appengine/internal/urlfetch"
)
// Transport is an implementation of http.RoundTripper for
// App Engine. Users should generally create an http.Client using
// this transport and use the Client rather than using this transport
// directly.
type Transport struct {
Context context.Context
// Controls whether the application checks the validity of SSL certificates
// over HTTPS connections. A value of false (the default) instructs the
// application to send a request to the server only if the certificate is
// valid and signed by a trusted certificate authority (CA), and also
// includes a hostname that matches the certificate. A value of true
// instructs the application to perform no certificate validation.
AllowInvalidServerCertificate bool
}
// Verify statically that *Transport implements http.RoundTripper.
var _ http.RoundTripper = (*Transport)(nil)
// Client returns an *http.Client using a default urlfetch Transport. This
// client will have the default deadline of 5 seconds, and will check the
// validity of SSL certificates.
//
// Any deadline of the provided context will be used for requests through this client;
// if the client does not have a deadline then a 5 second default is used.
func Client(ctx context.Context) *http.Client {
return &http.Client{
Transport: &Transport{
Context: ctx,
},
}
}
type bodyReader struct {
content []byte
truncated bool
closed bool
}
// ErrTruncatedBody is the error returned after the final Read() from a
// response's Body if the body has been truncated by App Engine's proxy.
var ErrTruncatedBody = errors.New("urlfetch: truncated body")
func statusCodeToText(code int) string {
if t := http.StatusText(code); t != "" {
return t
}
return strconv.Itoa(code)
}
func (br *bodyReader) Read(p []byte) (n int, err error) {
if br.closed {
if br.truncated {
return 0, ErrTruncatedBody
}
return 0, io.EOF
}
n = copy(p, br.content)
if n > 0 {
br.content = br.content[n:]
return
}
if br.truncated {
br.closed = true
return 0, ErrTruncatedBody
}
return 0, io.EOF
}
func (br *bodyReader) Close() error {
br.closed = true
br.content = nil
return nil
}
// A map of the URL Fetch-accepted methods that take a request body.
var methodAcceptsRequestBody = map[string]bool{
"POST": true,
"PUT": true,
"PATCH": true,
}
// urlString returns a valid string given a URL. This function is necessary because
// the String method of URL doesn't correctly handle URLs with non-empty Opaque values.
// See http://code.google.com/p/go/issues/detail?id=4860.
func urlString(u *url.URL) string {
if u.Opaque == "" || strings.HasPrefix(u.Opaque, "//") {
return u.String()
}
aux := *u
aux.Opaque = "//" + aux.Host + aux.Opaque
return aux.String()
}
// RoundTrip issues a single HTTP request and returns its response. Per the
// http.RoundTripper interface, RoundTrip only returns an error if there
// was an unsupported request or the URL Fetch proxy fails.
// Note that HTTP response codes such as 5xx, 403, 404, etc are not
// errors as far as the transport is concerned and will be returned
// with err set to nil.
func (t *Transport) RoundTrip(req *http.Request) (res *http.Response, err error) {
methNum, ok := pb.URLFetchRequest_RequestMethod_value[req.Method]
if !ok {
return nil, fmt.Errorf("urlfetch: unsupported HTTP method %q", req.Method)
}
method := pb.URLFetchRequest_RequestMethod(methNum)
freq := &pb.URLFetchRequest{
Method: &method,
Url: proto.String(urlString(req.URL)),
FollowRedirects: proto.Bool(false), // http.Client's responsibility
MustValidateServerCertificate: proto.Bool(!t.AllowInvalidServerCertificate),
}
if deadline, ok := t.Context.Deadline(); ok {
freq.Deadline = proto.Float64(deadline.Sub(time.Now()).Seconds())
}
for k, vals := range req.Header {
for _, val := range vals {
freq.Header = append(freq.Header, &pb.URLFetchRequest_Header{
Key: proto.String(k),
Value: proto.String(val),
})
}
}
if methodAcceptsRequestBody[req.Method] && req.Body != nil {
// Avoid a []byte copy if req.Body has a Bytes method.
switch b := req.Body.(type) {
case interface {
Bytes() []byte
}:
freq.Payload = b.Bytes()
default:
freq.Payload, err = ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
}
}
fres := &pb.URLFetchResponse{}
if err := internal.Call(t.Context, "urlfetch", "Fetch", freq, fres); err != nil {
return nil, err
}
res = &http.Response{}
res.StatusCode = int(*fres.StatusCode)
res.Status = fmt.Sprintf("%d %s", res.StatusCode, statusCodeToText(res.StatusCode))
res.Header = make(http.Header)
res.Request = req
// Faked:
res.ProtoMajor = 1
res.ProtoMinor = 1
res.Proto = "HTTP/1.1"
res.Close = true
for _, h := range fres.Header {
hkey := http.CanonicalHeaderKey(*h.Key)
hval := *h.Value
if hkey == "Content-Length" {
// Will get filled in below for all but HEAD requests.
if req.Method == "HEAD" {
res.ContentLength, _ = strconv.ParseInt(hval, 10, 64)
}
continue
}
res.Header.Add(hkey, hval)
}
if req.Method != "HEAD" {
res.ContentLength = int64(len(fres.Content))
}
truncated := fres.GetContentWasTruncated()
res.Body = &bodyReader{content: fres.Content, truncated: truncated}
return
}
func init() {
internal.RegisterErrorCodeMap("urlfetch", pb.URLFetchServiceError_ErrorCode_name)
internal.RegisterTimeoutErrorCode("urlfetch", int32(pb.URLFetchServiceError_DEADLINE_EXCEEDED))
}

View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at https://tip.golang.org/AUTHORS.

View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at https://tip.golang.org/CONTRIBUTORS.

View File

@ -0,0 +1,27 @@
Copyright (c) 2018 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

View File

@ -0,0 +1,791 @@
// 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 prototext
import (
"fmt"
"strings"
"unicode/utf8"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/encoding/text"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/set"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// Unmarshal reads the given []byte into the given proto.Message.
func Unmarshal(b []byte, m proto.Message) error {
return UnmarshalOptions{}.Unmarshal(b, m)
}
// UnmarshalOptions is a configurable textproto format unmarshaler.
type UnmarshalOptions struct {
pragma.NoUnkeyedLiterals
// AllowPartial accepts input for messages that will result in missing
// required fields. If AllowPartial is false (the default), Unmarshal will
// return error if there are any missing required fields.
AllowPartial bool
// DiscardUnknown specifies whether to ignore unknown fields when parsing.
// An unknown field is any field whose field name or field number does not
// resolve to any known or extension field in the message.
// By default, unmarshal rejects unknown fields as an error.
DiscardUnknown bool
// Resolver is used for looking up types when unmarshaling
// google.protobuf.Any messages or extension fields.
// If nil, this defaults to using protoregistry.GlobalTypes.
Resolver interface {
protoregistry.MessageTypeResolver
protoregistry.ExtensionTypeResolver
}
}
// Unmarshal reads the given []byte and populates the given proto.Message using options in
// UnmarshalOptions object.
func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
return o.unmarshal(b, m)
}
// unmarshal is a centralized function that all unmarshal operations go through.
// For profiling purposes, avoid changing the name of this function or
// introducing other code paths for unmarshal that do not go through this.
func (o UnmarshalOptions) unmarshal(b []byte, m proto.Message) error {
proto.Reset(m)
if o.Resolver == nil {
o.Resolver = protoregistry.GlobalTypes
}
dec := decoder{text.NewDecoder(b), o}
if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil {
return err
}
if o.AllowPartial {
return nil
}
return proto.CheckInitialized(m)
}
type decoder struct {
*text.Decoder
opts UnmarshalOptions
}
// newError returns an error object with position info.
func (d decoder) newError(pos int, f string, x ...interface{}) error {
line, column := d.Position(pos)
head := fmt.Sprintf("(line %d:%d): ", line, column)
return errors.New(head+f, x...)
}
// unexpectedTokenError returns a syntax error for the given unexpected token.
func (d decoder) unexpectedTokenError(tok text.Token) error {
return d.syntaxError(tok.Pos(), "unexpected token: %s", tok.RawString())
}
// syntaxError returns a syntax error for given position.
func (d decoder) syntaxError(pos int, f string, x ...interface{}) error {
line, column := d.Position(pos)
head := fmt.Sprintf("syntax error (line %d:%d): ", line, column)
return errors.New(head+f, x...)
}
// unmarshalMessage unmarshals into the given protoreflect.Message.
func (d decoder) unmarshalMessage(m pref.Message, checkDelims bool) error {
messageDesc := m.Descriptor()
if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
return errors.New("no support for proto1 MessageSets")
}
if messageDesc.FullName() == genid.Any_message_fullname {
return d.unmarshalAny(m, checkDelims)
}
if checkDelims {
tok, err := d.Read()
if err != nil {
return err
}
if tok.Kind() != text.MessageOpen {
return d.unexpectedTokenError(tok)
}
}
var seenNums set.Ints
var seenOneofs set.Ints
fieldDescs := messageDesc.Fields()
for {
// Read field name.
tok, err := d.Read()
if err != nil {
return err
}
switch typ := tok.Kind(); typ {
case text.Name:
// Continue below.
case text.EOF:
if checkDelims {
return text.ErrUnexpectedEOF
}
return nil
default:
if checkDelims && typ == text.MessageClose {
return nil
}
return d.unexpectedTokenError(tok)
}
// Resolve the field descriptor.
var name pref.Name
var fd pref.FieldDescriptor
var xt pref.ExtensionType
var xtErr error
var isFieldNumberName bool
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
}
case text.TypeName:
// Handle extensions only. This code path is not for Any.
xt, xtErr = d.findExtension(pref.FullName(tok.TypeName()))
case text.FieldNumber:
isFieldNumberName = true
num := pref.FieldNumber(tok.FieldNumber())
if !num.IsValid() {
return d.newError(tok.Pos(), "invalid field number: %d", num)
}
fd = fieldDescs.ByNumber(num)
if fd == nil {
xt, xtErr = d.opts.Resolver.FindExtensionByNumber(messageDesc.FullName(), num)
}
}
if xt != nil {
fd = xt.TypeDescriptor()
if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() {
return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
}
} else if xtErr != nil && xtErr != protoregistry.NotFound {
return d.newError(tok.Pos(), "unable to resolve [%s]: %v", tok.RawString(), xtErr)
}
if flags.ProtoLegacy {
if fd != nil && fd.IsWeak() && fd.Message().IsPlaceholder() {
fd = nil // reset since the weak reference is not linked in
}
}
// Handle unknown fields.
if fd == nil {
if d.opts.DiscardUnknown || messageDesc.ReservedNames().Has(name) {
d.skipValue()
continue
}
return d.newError(tok.Pos(), "unknown field: %v", tok.RawString())
}
// Handle fields identified by field number.
if isFieldNumberName {
// TODO: Add an option to permit parsing field numbers.
//
// This requires careful thought as the MarshalOptions.EmitUnknown
// option allows formatting unknown fields as the field number and the
// best-effort textual representation of the field value. In that case,
// it may not be possible to unmarshal the value from a parser that does
// have information about the unknown field.
return d.newError(tok.Pos(), "cannot specify field by number: %v", tok.RawString())
}
switch {
case fd.IsList():
kind := fd.Kind()
if kind != pref.MessageKind && kind != pref.GroupKind && !tok.HasSeparator() {
return d.syntaxError(tok.Pos(), "missing field separator :")
}
list := m.Mutable(fd).List()
if err := d.unmarshalList(fd, list); err != nil {
return err
}
case fd.IsMap():
mmap := m.Mutable(fd).Map()
if err := d.unmarshalMap(fd, mmap); err != nil {
return err
}
default:
kind := fd.Kind()
if kind != pref.MessageKind && kind != pref.GroupKind && !tok.HasSeparator() {
return d.syntaxError(tok.Pos(), "missing field separator :")
}
// If field is a oneof, check if it has already been set.
if od := fd.ContainingOneof(); od != nil {
idx := uint64(od.Index())
if seenOneofs.Has(idx) {
return d.newError(tok.Pos(), "error parsing %q, oneof %v is already set", tok.RawString(), od.FullName())
}
seenOneofs.Set(idx)
}
num := uint64(fd.Number())
if seenNums.Has(num) {
return d.newError(tok.Pos(), "non-repeated field %q is repeated", tok.RawString())
}
if err := d.unmarshalSingular(fd, m); err != nil {
return err
}
seenNums.Set(num)
}
}
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 {
var val pref.Value
var err error
switch fd.Kind() {
case pref.MessageKind, pref.GroupKind:
val = m.NewField(fd)
err = d.unmarshalMessage(val.Message(), true)
default:
val, err = d.unmarshalScalar(fd)
}
if err == nil {
m.Set(fd, val)
}
return err
}
// unmarshalScalar unmarshals a scalar/enum protoreflect.Value specified by the
// given FieldDescriptor.
func (d decoder) unmarshalScalar(fd pref.FieldDescriptor) (pref.Value, error) {
tok, err := d.Read()
if err != nil {
return pref.Value{}, err
}
if tok.Kind() != text.Scalar {
return pref.Value{}, d.unexpectedTokenError(tok)
}
kind := fd.Kind()
switch kind {
case pref.BoolKind:
if b, ok := tok.Bool(); ok {
return pref.ValueOfBool(b), nil
}
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
if n, ok := tok.Int32(); ok {
return pref.ValueOfInt32(n), nil
}
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
if n, ok := tok.Int64(); ok {
return pref.ValueOfInt64(n), nil
}
case pref.Uint32Kind, pref.Fixed32Kind:
if n, ok := tok.Uint32(); ok {
return pref.ValueOfUint32(n), nil
}
case pref.Uint64Kind, pref.Fixed64Kind:
if n, ok := tok.Uint64(); ok {
return pref.ValueOfUint64(n), nil
}
case pref.FloatKind:
if n, ok := tok.Float32(); ok {
return pref.ValueOfFloat32(n), nil
}
case pref.DoubleKind:
if n, ok := tok.Float64(); ok {
return pref.ValueOfFloat64(n), nil
}
case pref.StringKind:
if s, ok := tok.String(); ok {
if strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
return pref.Value{}, d.newError(tok.Pos(), "contains invalid UTF-8")
}
return pref.ValueOfString(s), nil
}
case pref.BytesKind:
if b, ok := tok.String(); ok {
return pref.ValueOfBytes([]byte(b)), nil
}
case pref.EnumKind:
if lit, ok := tok.Enum(); ok {
// Lookup EnumNumber based on name.
if enumVal := fd.Enum().Values().ByName(pref.Name(lit)); enumVal != nil {
return pref.ValueOfEnum(enumVal.Number()), nil
}
}
if num, ok := tok.Int32(); ok {
return pref.ValueOfEnum(pref.EnumNumber(num)), nil
}
default:
panic(fmt.Sprintf("invalid scalar kind %v", kind))
}
return pref.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString())
}
// unmarshalList unmarshals into given protoreflect.List. A list value can
// either be in [] syntax or simply just a single scalar/message value.
func (d decoder) unmarshalList(fd pref.FieldDescriptor, list pref.List) error {
tok, err := d.Peek()
if err != nil {
return err
}
switch fd.Kind() {
case pref.MessageKind, pref.GroupKind:
switch tok.Kind() {
case text.ListOpen:
d.Read()
for {
tok, err := d.Peek()
if err != nil {
return err
}
switch tok.Kind() {
case text.ListClose:
d.Read()
return nil
case text.MessageOpen:
pval := list.NewElement()
if err := d.unmarshalMessage(pval.Message(), true); err != nil {
return err
}
list.Append(pval)
default:
return d.unexpectedTokenError(tok)
}
}
case text.MessageOpen:
pval := list.NewElement()
if err := d.unmarshalMessage(pval.Message(), true); err != nil {
return err
}
list.Append(pval)
return nil
}
default:
switch tok.Kind() {
case text.ListOpen:
d.Read()
for {
tok, err := d.Peek()
if err != nil {
return err
}
switch tok.Kind() {
case text.ListClose:
d.Read()
return nil
case text.Scalar:
pval, err := d.unmarshalScalar(fd)
if err != nil {
return err
}
list.Append(pval)
default:
return d.unexpectedTokenError(tok)
}
}
case text.Scalar:
pval, err := d.unmarshalScalar(fd)
if err != nil {
return err
}
list.Append(pval)
return nil
}
}
return d.unexpectedTokenError(tok)
}
// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
// textproto message containing {key: <kvalue>, value: <mvalue>}.
func (d decoder) unmarshalMap(fd pref.FieldDescriptor, mmap pref.Map) error {
// Determine ahead whether map entry is a scalar type or a message type in
// order to call the appropriate unmarshalMapValue func inside
// unmarshalMapEntry.
var unmarshalMapValue func() (pref.Value, error)
switch fd.MapValue().Kind() {
case pref.MessageKind, pref.GroupKind:
unmarshalMapValue = func() (pref.Value, error) {
pval := mmap.NewValue()
if err := d.unmarshalMessage(pval.Message(), true); err != nil {
return pref.Value{}, err
}
return pval, nil
}
default:
unmarshalMapValue = func() (pref.Value, error) {
return d.unmarshalScalar(fd.MapValue())
}
}
tok, err := d.Read()
if err != nil {
return err
}
switch tok.Kind() {
case text.MessageOpen:
return d.unmarshalMapEntry(fd, mmap, unmarshalMapValue)
case text.ListOpen:
for {
tok, err := d.Read()
if err != nil {
return err
}
switch tok.Kind() {
case text.ListClose:
return nil
case text.MessageOpen:
if err := d.unmarshalMapEntry(fd, mmap, unmarshalMapValue); err != nil {
return err
}
default:
return d.unexpectedTokenError(tok)
}
}
default:
return d.unexpectedTokenError(tok)
}
}
// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
// textproto message containing {key: <kvalue>, value: <mvalue>}.
func (d decoder) unmarshalMapEntry(fd pref.FieldDescriptor, mmap pref.Map, unmarshalMapValue func() (pref.Value, error)) error {
var key pref.MapKey
var pval pref.Value
Loop:
for {
// Read field name.
tok, err := d.Read()
if err != nil {
return err
}
switch tok.Kind() {
case text.Name:
if tok.NameKind() != text.IdentName {
if !d.opts.DiscardUnknown {
return d.newError(tok.Pos(), "unknown map entry field %q", tok.RawString())
}
d.skipValue()
continue Loop
}
// Continue below.
case text.MessageClose:
break Loop
default:
return d.unexpectedTokenError(tok)
}
switch name := pref.Name(tok.IdentName()); name {
case genid.MapEntry_Key_field_name:
if !tok.HasSeparator() {
return d.syntaxError(tok.Pos(), "missing field separator :")
}
if key.IsValid() {
return d.newError(tok.Pos(), "map entry %q cannot be repeated", name)
}
val, err := d.unmarshalScalar(fd.MapKey())
if err != nil {
return err
}
key = val.MapKey()
case genid.MapEntry_Value_field_name:
if kind := fd.MapValue().Kind(); (kind != pref.MessageKind) && (kind != pref.GroupKind) {
if !tok.HasSeparator() {
return d.syntaxError(tok.Pos(), "missing field separator :")
}
}
if pval.IsValid() {
return d.newError(tok.Pos(), "map entry %q cannot be repeated", name)
}
pval, err = unmarshalMapValue()
if err != nil {
return err
}
default:
if !d.opts.DiscardUnknown {
return d.newError(tok.Pos(), "unknown map entry field %q", name)
}
d.skipValue()
}
}
if !key.IsValid() {
key = fd.MapKey().Default().MapKey()
}
if !pval.IsValid() {
switch fd.MapValue().Kind() {
case pref.MessageKind, pref.GroupKind:
// If value field is not set for message/group types, construct an
// empty one as default.
pval = mmap.NewValue()
default:
pval = fd.MapValue().Default()
}
}
mmap.Set(key, pval)
return nil
}
// unmarshalAny unmarshals an Any textproto. It can either be in expanded form
// or non-expanded form.
func (d decoder) unmarshalAny(m pref.Message, checkDelims bool) error {
var typeURL string
var bValue []byte
var seenTypeUrl bool
var seenValue bool
var isExpanded bool
if checkDelims {
tok, err := d.Read()
if err != nil {
return err
}
if tok.Kind() != text.MessageOpen {
return d.unexpectedTokenError(tok)
}
}
Loop:
for {
// Read field name. Can only have 3 possible field names, i.e. type_url,
// value and type URL name inside [].
tok, err := d.Read()
if err != nil {
return err
}
if typ := tok.Kind(); typ != text.Name {
if checkDelims {
if typ == text.MessageClose {
break Loop
}
} else if typ == text.EOF {
break Loop
}
return d.unexpectedTokenError(tok)
}
switch tok.NameKind() {
case text.IdentName:
// Both type_url and value fields require field separator :.
if !tok.HasSeparator() {
return d.syntaxError(tok.Pos(), "missing field separator :")
}
switch name := pref.Name(tok.IdentName()); name {
case genid.Any_TypeUrl_field_name:
if seenTypeUrl {
return d.newError(tok.Pos(), "duplicate %v field", genid.Any_TypeUrl_field_fullname)
}
if isExpanded {
return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
}
tok, err := d.Read()
if err != nil {
return err
}
var ok bool
typeURL, ok = tok.String()
if !ok {
return d.newError(tok.Pos(), "invalid %v field value: %v", genid.Any_TypeUrl_field_fullname, tok.RawString())
}
seenTypeUrl = true
case genid.Any_Value_field_name:
if seenValue {
return d.newError(tok.Pos(), "duplicate %v field", genid.Any_Value_field_fullname)
}
if isExpanded {
return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
}
tok, err := d.Read()
if err != nil {
return err
}
s, ok := tok.String()
if !ok {
return d.newError(tok.Pos(), "invalid %v field value: %v", genid.Any_Value_field_fullname, tok.RawString())
}
bValue = []byte(s)
seenValue = true
default:
if !d.opts.DiscardUnknown {
return d.newError(tok.Pos(), "invalid field name %q in %v message", tok.RawString(), genid.Any_message_fullname)
}
}
case text.TypeName:
if isExpanded {
return d.newError(tok.Pos(), "cannot have more than one type")
}
if seenTypeUrl {
return d.newError(tok.Pos(), "conflict with type_url field")
}
typeURL = tok.TypeName()
var err error
bValue, err = d.unmarshalExpandedAny(typeURL, tok.Pos())
if err != nil {
return err
}
isExpanded = true
default:
if !d.opts.DiscardUnknown {
return d.newError(tok.Pos(), "invalid field name %q in %v message", tok.RawString(), genid.Any_message_fullname)
}
}
}
fds := m.Descriptor().Fields()
if len(typeURL) > 0 {
m.Set(fds.ByNumber(genid.Any_TypeUrl_field_number), pref.ValueOfString(typeURL))
}
if len(bValue) > 0 {
m.Set(fds.ByNumber(genid.Any_Value_field_number), pref.ValueOfBytes(bValue))
}
return nil
}
func (d decoder) unmarshalExpandedAny(typeURL string, pos int) ([]byte, error) {
mt, err := d.opts.Resolver.FindMessageByURL(typeURL)
if err != nil {
return nil, d.newError(pos, "unable to resolve message [%v]: %v", typeURL, err)
}
// Create new message for the embedded message type and unmarshal the value
// field into it.
m := mt.New()
if err := d.unmarshalMessage(m, true); err != nil {
return nil, err
}
// Serialize the embedded message and return the resulting bytes.
b, err := proto.MarshalOptions{
AllowPartial: true, // Never check required fields inside an Any.
Deterministic: true,
}.Marshal(m.Interface())
if err != nil {
return nil, d.newError(pos, "error in marshaling message into Any.value: %v", err)
}
return b, nil
}
// skipValue makes the decoder parse a field value in order to advance the read
// to the next field. It relies on Read returning an error if the types are not
// in valid sequence.
func (d decoder) skipValue() error {
tok, err := d.Read()
if err != nil {
return err
}
// Only need to continue reading for messages and lists.
switch tok.Kind() {
case text.MessageOpen:
return d.skipMessageValue()
case text.ListOpen:
for {
tok, err := d.Read()
if err != nil {
return err
}
switch tok.Kind() {
case text.ListClose:
return nil
case text.MessageOpen:
return d.skipMessageValue()
default:
// 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
}
}
}
}
return nil
}
// skipMessageValue makes the decoder parse and skip over all fields in a
// message. It assumes that the previous read type is MessageOpen.
func (d decoder) skipMessageValue() error {
for {
tok, err := d.Read()
if err != nil {
return err
}
switch tok.Kind() {
case text.MessageClose:
return nil
case text.Name:
if err := d.skipValue(); err != nil {
return err
}
}
}
}

View File

@ -0,0 +1,7 @@
// 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 prototext marshals and unmarshals protocol buffer messages as the
// textproto format.
package prototext

View File

@ -0,0 +1,433 @@
// 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 prototext
import (
"fmt"
"sort"
"strconv"
"unicode/utf8"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/encoding/text"
"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/pragma"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const defaultIndent = " "
// Format formats the message as a multiline string.
// This function is only intended for human consumption and ignores errors.
// Do not depend on the output being stable. It may change over time across
// different versions of the program.
func Format(m proto.Message) string {
return MarshalOptions{Multiline: true}.Format(m)
}
// Marshal writes the given proto.Message in textproto format using default
// options. Do not depend on the output being stable. It may change over time
// across different versions of the program.
func Marshal(m proto.Message) ([]byte, error) {
return MarshalOptions{}.Marshal(m)
}
// MarshalOptions is a configurable text format marshaler.
type MarshalOptions struct {
pragma.NoUnkeyedLiterals
// Multiline specifies whether the marshaler should format the output in
// indented-form with every textual element on a new line.
// If Indent is an empty string, then an arbitrary indent is chosen.
Multiline bool
// Indent specifies the set of indentation characters to use in a multiline
// formatted output such that every entry is preceded by Indent and
// terminated by a newline. If non-empty, then Multiline is treated as true.
// Indent can only be composed of space or tab characters.
Indent string
// EmitASCII specifies whether to format strings and bytes as ASCII only
// as opposed to using UTF-8 encoding when possible.
EmitASCII bool
// allowInvalidUTF8 specifies whether to permit the encoding of strings
// with invalid UTF-8. This is unexported as it is intended to only
// be specified by the Format method.
allowInvalidUTF8 bool
// AllowPartial allows messages that have missing required fields to marshal
// without returning an error. If AllowPartial is false (the default),
// Marshal will return error if there are any missing required fields.
AllowPartial bool
// EmitUnknown specifies whether to emit unknown fields in the output.
// If specified, the unmarshaler may be unable to parse the output.
// The default is to exclude unknown fields.
EmitUnknown bool
// Resolver is used for looking up types when expanding google.protobuf.Any
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
Resolver interface {
protoregistry.ExtensionTypeResolver
protoregistry.MessageTypeResolver
}
}
// Format formats the message as a string.
// This method is only intended for human consumption and ignores errors.
// Do not depend on the output being stable. It may change over time across
// different versions of the program.
func (o MarshalOptions) Format(m proto.Message) string {
if m == nil || !m.ProtoReflect().IsValid() {
return "<nil>" // invalid syntax, but okay since this is for debugging
}
o.allowInvalidUTF8 = true
o.AllowPartial = true
o.EmitUnknown = true
b, _ := o.Marshal(m)
return string(b)
}
// Marshal writes the given proto.Message in textproto format using options in
// MarshalOptions object. Do not depend on the output being stable. It may
// change over time across different versions of the program.
func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
return o.marshal(m)
}
// marshal is a centralized function that all marshal operations go through.
// For profiling purposes, avoid changing the name of this function or
// introducing other code paths for marshal that do not go through this.
func (o MarshalOptions) marshal(m proto.Message) ([]byte, error) {
var delims = [2]byte{'{', '}'}
if o.Multiline && o.Indent == "" {
o.Indent = defaultIndent
}
if o.Resolver == nil {
o.Resolver = protoregistry.GlobalTypes
}
internalEnc, err := text.NewEncoder(o.Indent, delims, o.EmitASCII)
if err != nil {
return nil, err
}
// Treat nil message interface as an empty message,
// in which case there is nothing to output.
if m == nil {
return []byte{}, nil
}
enc := encoder{internalEnc, o}
err = enc.marshalMessage(m.ProtoReflect(), false)
if err != nil {
return nil, err
}
out := enc.Bytes()
if len(o.Indent) > 0 && len(out) > 0 {
out = append(out, '\n')
}
if o.AllowPartial {
return out, nil
}
return out, proto.CheckInitialized(m)
}
type encoder struct {
*text.Encoder
opts MarshalOptions
}
// marshalMessage marshals the given protoreflect.Message.
func (e encoder) marshalMessage(m pref.Message, inclDelims bool) error {
messageDesc := m.Descriptor()
if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
return errors.New("no support for proto1 MessageSets")
}
if inclDelims {
e.StartMessage()
defer e.EndMessage()
}
// Handle Any expansion.
if messageDesc.FullName() == genid.Any_message_fullname {
if e.marshalAny(m) {
return nil
}
// 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++
}
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 err
}
// Marshal unknown fields.
if e.opts.EmitUnknown {
e.marshalUnknown(m.GetUnknown())
}
return nil
}
// marshalField marshals the given field with protoreflect.Value.
func (e encoder) marshalField(name string, val pref.Value, fd pref.FieldDescriptor) error {
switch {
case fd.IsList():
return e.marshalList(name, val.List(), fd)
case fd.IsMap():
return e.marshalMap(name, val.Map(), fd)
default:
e.WriteName(name)
return e.marshalSingular(val, fd)
}
}
// marshalSingular marshals the given non-repeated field value. This includes
// all scalar types, enums, messages, and groups.
func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
kind := fd.Kind()
switch kind {
case pref.BoolKind:
e.WriteBool(val.Bool())
case pref.StringKind:
s := val.String()
if !e.opts.allowInvalidUTF8 && strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
return errors.InvalidUTF8(string(fd.FullName()))
}
e.WriteString(s)
case pref.Int32Kind, pref.Int64Kind,
pref.Sint32Kind, pref.Sint64Kind,
pref.Sfixed32Kind, pref.Sfixed64Kind:
e.WriteInt(val.Int())
case pref.Uint32Kind, pref.Uint64Kind,
pref.Fixed32Kind, pref.Fixed64Kind:
e.WriteUint(val.Uint())
case pref.FloatKind:
// Encoder.WriteFloat handles the special numbers NaN and infinites.
e.WriteFloat(val.Float(), 32)
case pref.DoubleKind:
// Encoder.WriteFloat handles the special numbers NaN and infinites.
e.WriteFloat(val.Float(), 64)
case pref.BytesKind:
e.WriteString(string(val.Bytes()))
case pref.EnumKind:
num := val.Enum()
if desc := fd.Enum().Values().ByNumber(num); desc != nil {
e.WriteLiteral(string(desc.Name()))
} else {
// Use numeric value if there is no enum description.
e.WriteInt(int64(num))
}
case pref.MessageKind, pref.GroupKind:
return e.marshalMessage(val.Message(), true)
default:
panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
}
return nil
}
// marshalList marshals the given protoreflect.List as multiple name-value fields.
func (e encoder) marshalList(name string, list pref.List, fd pref.FieldDescriptor) error {
size := list.Len()
for i := 0; i < size; i++ {
e.WriteName(name)
if err := e.marshalSingular(list.Get(i), fd); err != nil {
return err
}
}
return nil
}
// 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 {
e.WriteName(name)
e.StartMessage()
defer e.EndMessage()
e.WriteName(string(genid.MapEntry_Key_field_name))
err = e.marshalSingular(key.Value(), fd.MapKey())
if err != nil {
return false
}
e.WriteName(string(genid.MapEntry_Value_field_name))
err = e.marshalSingular(val, fd.MapValue())
if err != nil {
return false
}
return true
})
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) {
const dec = 10
const hex = 16
for len(b) > 0 {
num, wtype, n := protowire.ConsumeTag(b)
b = b[n:]
e.WriteName(strconv.FormatInt(int64(num), dec))
switch wtype {
case protowire.VarintType:
var v uint64
v, n = protowire.ConsumeVarint(b)
e.WriteUint(v)
case protowire.Fixed32Type:
var v uint32
v, n = protowire.ConsumeFixed32(b)
e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
case protowire.Fixed64Type:
var v uint64
v, n = protowire.ConsumeFixed64(b)
e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
case protowire.BytesType:
var v []byte
v, n = protowire.ConsumeBytes(b)
e.WriteString(string(v))
case protowire.StartGroupType:
e.StartMessage()
var v []byte
v, n = protowire.ConsumeGroup(num, b)
e.marshalUnknown(v)
e.EndMessage()
default:
panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
}
b = b[n:]
}
}
// marshalAny marshals the given google.protobuf.Any message in expanded form.
// It returns true if it was able to marshal, else false.
func (e encoder) marshalAny(any pref.Message) bool {
// Construct the embedded message.
fds := any.Descriptor().Fields()
fdType := fds.ByNumber(genid.Any_TypeUrl_field_number)
typeURL := any.Get(fdType).String()
mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
if err != nil {
return false
}
m := mt.New().Interface()
// Unmarshal bytes into embedded message.
fdValue := fds.ByNumber(genid.Any_Value_field_number)
value := any.Get(fdValue)
err = proto.UnmarshalOptions{
AllowPartial: true,
Resolver: e.opts.Resolver,
}.Unmarshal(value.Bytes(), m)
if err != nil {
return false
}
// Get current encoder position. If marshaling fails, reset encoder output
// back to this position.
pos := e.Snapshot()
// Field name is the proto field name enclosed in [].
e.WriteName("[" + typeURL + "]")
err = e.marshalMessage(m.ProtoReflect(), true)
if err != nil {
e.Reset(pos)
return false
}
return true
}

View File

@ -0,0 +1,538 @@
// 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 protowire parses and formats the raw wire encoding.
// See https://developers.google.com/protocol-buffers/docs/encoding.
//
// For marshaling and unmarshaling entire protobuf messages,
// use the "google.golang.org/protobuf/proto" package instead.
package protowire
import (
"io"
"math"
"math/bits"
"google.golang.org/protobuf/internal/errors"
)
// Number represents the field number.
type Number int32
const (
MinValidNumber Number = 1
FirstReservedNumber Number = 19000
LastReservedNumber Number = 19999
MaxValidNumber Number = 1<<29 - 1
)
// IsValid reports whether the field number is semantically valid.
//
// Note that while numbers within the reserved range are semantically invalid,
// they are syntactically valid in the wire format.
// Implementations may treat records with reserved field numbers as unknown.
func (n Number) IsValid() bool {
return MinValidNumber <= n && n < FirstReservedNumber || LastReservedNumber < n && n <= MaxValidNumber
}
// Type represents the wire type.
type Type int8
const (
VarintType Type = 0
Fixed32Type Type = 5
Fixed64Type Type = 1
BytesType Type = 2
StartGroupType Type = 3
EndGroupType Type = 4
)
const (
_ = -iota
errCodeTruncated
errCodeFieldNumber
errCodeOverflow
errCodeReserved
errCodeEndGroup
)
var (
errFieldNumber = errors.New("invalid field number")
errOverflow = errors.New("variable length integer overflow")
errReserved = errors.New("cannot parse reserved wire type")
errEndGroup = errors.New("mismatching end group marker")
errParse = errors.New("parse error")
)
// ParseError converts an error code into an error value.
// This returns nil if n is a non-negative number.
func ParseError(n int) error {
if n >= 0 {
return nil
}
switch n {
case errCodeTruncated:
return io.ErrUnexpectedEOF
case errCodeFieldNumber:
return errFieldNumber
case errCodeOverflow:
return errOverflow
case errCodeReserved:
return errReserved
case errCodeEndGroup:
return errEndGroup
default:
return errParse
}
}
// ConsumeField parses an entire field record (both tag and value) and returns
// the field number, the wire type, and the total length.
// This returns a negative length upon an error (see ParseError).
//
// The total length includes the tag header and the end group marker (if the
// field is a group).
func ConsumeField(b []byte) (Number, Type, int) {
num, typ, n := ConsumeTag(b)
if n < 0 {
return 0, 0, n // forward error code
}
m := ConsumeFieldValue(num, typ, b[n:])
if m < 0 {
return 0, 0, m // forward error code
}
return num, typ, n + m
}
// ConsumeFieldValue parses a field value and returns its length.
// This assumes that the field Number and wire Type have already been parsed.
// This returns a negative length upon an error (see ParseError).
//
// When parsing a group, the length includes the end group marker and
// the end group is verified to match the starting field number.
func ConsumeFieldValue(num Number, typ Type, b []byte) (n int) {
switch typ {
case VarintType:
_, n = ConsumeVarint(b)
return n
case Fixed32Type:
_, n = ConsumeFixed32(b)
return n
case Fixed64Type:
_, n = ConsumeFixed64(b)
return n
case BytesType:
_, n = ConsumeBytes(b)
return n
case StartGroupType:
n0 := len(b)
for {
num2, typ2, n := ConsumeTag(b)
if n < 0 {
return n // forward error code
}
b = b[n:]
if typ2 == EndGroupType {
if num != num2 {
return errCodeEndGroup
}
return n0 - len(b)
}
n = ConsumeFieldValue(num2, typ2, b)
if n < 0 {
return n // forward error code
}
b = b[n:]
}
case EndGroupType:
return errCodeEndGroup
default:
return errCodeReserved
}
}
// AppendTag encodes num and typ as a varint-encoded tag and appends it to b.
func AppendTag(b []byte, num Number, typ Type) []byte {
return AppendVarint(b, EncodeTag(num, typ))
}
// ConsumeTag parses b as a varint-encoded tag, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeTag(b []byte) (Number, Type, int) {
v, n := ConsumeVarint(b)
if n < 0 {
return 0, 0, n // forward error code
}
num, typ := DecodeTag(v)
if num < MinValidNumber {
return 0, 0, errCodeFieldNumber
}
return num, typ, n
}
func SizeTag(num Number) int {
return SizeVarint(EncodeTag(num, 0)) // wire type has no effect on size
}
// AppendVarint appends v to b as a varint-encoded uint64.
func AppendVarint(b []byte, v uint64) []byte {
switch {
case v < 1<<7:
b = append(b, byte(v))
case v < 1<<14:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte(v>>7))
case v < 1<<21:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte(v>>14))
case v < 1<<28:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte(v>>21))
case v < 1<<35:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte(v>>28))
case v < 1<<42:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte((v>>28)&0x7f|0x80),
byte(v>>35))
case v < 1<<49:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte((v>>28)&0x7f|0x80),
byte((v>>35)&0x7f|0x80),
byte(v>>42))
case v < 1<<56:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte((v>>28)&0x7f|0x80),
byte((v>>35)&0x7f|0x80),
byte((v>>42)&0x7f|0x80),
byte(v>>49))
case v < 1<<63:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte((v>>28)&0x7f|0x80),
byte((v>>35)&0x7f|0x80),
byte((v>>42)&0x7f|0x80),
byte((v>>49)&0x7f|0x80),
byte(v>>56))
default:
b = append(b,
byte((v>>0)&0x7f|0x80),
byte((v>>7)&0x7f|0x80),
byte((v>>14)&0x7f|0x80),
byte((v>>21)&0x7f|0x80),
byte((v>>28)&0x7f|0x80),
byte((v>>35)&0x7f|0x80),
byte((v>>42)&0x7f|0x80),
byte((v>>49)&0x7f|0x80),
byte((v>>56)&0x7f|0x80),
1)
}
return b
}
// ConsumeVarint parses b as a varint-encoded uint64, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeVarint(b []byte) (v uint64, n int) {
var y uint64
if len(b) <= 0 {
return 0, errCodeTruncated
}
v = uint64(b[0])
if v < 0x80 {
return v, 1
}
v -= 0x80
if len(b) <= 1 {
return 0, errCodeTruncated
}
y = uint64(b[1])
v += y << 7
if y < 0x80 {
return v, 2
}
v -= 0x80 << 7
if len(b) <= 2 {
return 0, errCodeTruncated
}
y = uint64(b[2])
v += y << 14
if y < 0x80 {
return v, 3
}
v -= 0x80 << 14
if len(b) <= 3 {
return 0, errCodeTruncated
}
y = uint64(b[3])
v += y << 21
if y < 0x80 {
return v, 4
}
v -= 0x80 << 21
if len(b) <= 4 {
return 0, errCodeTruncated
}
y = uint64(b[4])
v += y << 28
if y < 0x80 {
return v, 5
}
v -= 0x80 << 28
if len(b) <= 5 {
return 0, errCodeTruncated
}
y = uint64(b[5])
v += y << 35
if y < 0x80 {
return v, 6
}
v -= 0x80 << 35
if len(b) <= 6 {
return 0, errCodeTruncated
}
y = uint64(b[6])
v += y << 42
if y < 0x80 {
return v, 7
}
v -= 0x80 << 42
if len(b) <= 7 {
return 0, errCodeTruncated
}
y = uint64(b[7])
v += y << 49
if y < 0x80 {
return v, 8
}
v -= 0x80 << 49
if len(b) <= 8 {
return 0, errCodeTruncated
}
y = uint64(b[8])
v += y << 56
if y < 0x80 {
return v, 9
}
v -= 0x80 << 56
if len(b) <= 9 {
return 0, errCodeTruncated
}
y = uint64(b[9])
v += y << 63
if y < 2 {
return v, 10
}
return 0, errCodeOverflow
}
// SizeVarint returns the encoded size of a varint.
// The size is guaranteed to be within 1 and 10, inclusive.
func SizeVarint(v uint64) int {
// This computes 1 + (bits.Len64(v)-1)/7.
// 9/64 is a good enough approximation of 1/7
return int(9*uint32(bits.Len64(v))+64) / 64
}
// AppendFixed32 appends v to b as a little-endian uint32.
func AppendFixed32(b []byte, v uint32) []byte {
return append(b,
byte(v>>0),
byte(v>>8),
byte(v>>16),
byte(v>>24))
}
// ConsumeFixed32 parses b as a little-endian uint32, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeFixed32(b []byte) (v uint32, n int) {
if len(b) < 4 {
return 0, errCodeTruncated
}
v = uint32(b[0])<<0 | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
return v, 4
}
// SizeFixed32 returns the encoded size of a fixed32; which is always 4.
func SizeFixed32() int {
return 4
}
// AppendFixed64 appends v to b as a little-endian uint64.
func AppendFixed64(b []byte, v uint64) []byte {
return append(b,
byte(v>>0),
byte(v>>8),
byte(v>>16),
byte(v>>24),
byte(v>>32),
byte(v>>40),
byte(v>>48),
byte(v>>56))
}
// ConsumeFixed64 parses b as a little-endian uint64, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeFixed64(b []byte) (v uint64, n int) {
if len(b) < 8 {
return 0, errCodeTruncated
}
v = uint64(b[0])<<0 | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
return v, 8
}
// SizeFixed64 returns the encoded size of a fixed64; which is always 8.
func SizeFixed64() int {
return 8
}
// AppendBytes appends v to b as a length-prefixed bytes value.
func AppendBytes(b []byte, v []byte) []byte {
return append(AppendVarint(b, uint64(len(v))), v...)
}
// ConsumeBytes parses b as a length-prefixed bytes value, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeBytes(b []byte) (v []byte, n int) {
m, n := ConsumeVarint(b)
if n < 0 {
return nil, n // forward error code
}
if m > uint64(len(b[n:])) {
return nil, errCodeTruncated
}
return b[n:][:m], n + int(m)
}
// SizeBytes returns the encoded size of a length-prefixed bytes value,
// given only the length.
func SizeBytes(n int) int {
return SizeVarint(uint64(n)) + n
}
// AppendString appends v to b as a length-prefixed bytes value.
func AppendString(b []byte, v string) []byte {
return append(AppendVarint(b, uint64(len(v))), v...)
}
// ConsumeString parses b as a length-prefixed bytes value, reporting its length.
// This returns a negative length upon an error (see ParseError).
func ConsumeString(b []byte) (v string, n int) {
bb, n := ConsumeBytes(b)
return string(bb), n
}
// AppendGroup appends v to b as group value, with a trailing end group marker.
// The value v must not contain the end marker.
func AppendGroup(b []byte, num Number, v []byte) []byte {
return AppendVarint(append(b, v...), EncodeTag(num, EndGroupType))
}
// ConsumeGroup parses b as a group value until the trailing end group marker,
// and verifies that the end marker matches the provided num. The value v
// does not contain the end marker, while the length does contain the end marker.
// This returns a negative length upon an error (see ParseError).
func ConsumeGroup(num Number, b []byte) (v []byte, n int) {
n = ConsumeFieldValue(num, StartGroupType, b)
if n < 0 {
return nil, n // forward error code
}
b = b[:n]
// Truncate off end group marker, but need to handle denormalized varints.
// Assuming end marker is never 0 (which is always the case since
// EndGroupType is non-zero), we can truncate all trailing bytes where the
// lower 7 bits are all zero (implying that the varint is denormalized).
for len(b) > 0 && b[len(b)-1]&0x7f == 0 {
b = b[:len(b)-1]
}
b = b[:len(b)-SizeTag(num)]
return b, n
}
// SizeGroup returns the encoded size of a group, given only the length.
func SizeGroup(num Number, n int) int {
return n + SizeTag(num)
}
// DecodeTag decodes the field Number and wire Type from its unified form.
// The Number is -1 if the decoded field number overflows int32.
// Other than overflow, this does not check for field number validity.
func DecodeTag(x uint64) (Number, Type) {
// NOTE: MessageSet allows for larger field numbers than normal.
if x>>3 > uint64(math.MaxInt32) {
return -1, 0
}
return Number(x >> 3), Type(x & 7)
}
// EncodeTag encodes the field Number and wire Type into its unified form.
func EncodeTag(num Number, typ Type) uint64 {
return uint64(num)<<3 | uint64(typ&7)
}
// DecodeZigZag decodes a zig-zag-encoded uint64 as an int64.
// Input: {…, 5, 3, 1, 0, 2, 4, 6, …}
// Output: {…, -3, -2, -1, 0, +1, +2, +3, …}
func DecodeZigZag(x uint64) int64 {
return int64(x>>1) ^ int64(x)<<63>>63
}
// EncodeZigZag encodes an int64 as a zig-zag-encoded uint64.
// Input: {…, -3, -2, -1, 0, +1, +2, +3, …}
// Output: {…, 5, 3, 1, 0, 2, 4, 6, …}
func EncodeZigZag(x int64) uint64 {
return uint64(x<<1) ^ uint64(x>>63)
}
// DecodeBool decodes a uint64 as a bool.
// Input: { 0, 1, 2, …}
// Output: {false, true, true, …}
func DecodeBool(x uint64) bool {
return x != 0
}
// EncodeBool encodes a bool as a uint64.
// Input: {false, true}
// Output: { 0, 1}
func EncodeBool(x bool) uint64 {
if x {
return 1
}
return 0
}

View File

@ -0,0 +1,316 @@
// 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 descfmt provides functionality to format descriptors.
package descfmt
import (
"fmt"
"io"
"reflect"
"strconv"
"strings"
"google.golang.org/protobuf/internal/detrand"
"google.golang.org/protobuf/internal/pragma"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type list interface {
Len() int
pragma.DoNotImplement
}
func FormatList(s fmt.State, r rune, vs list) {
io.WriteString(s, formatListOpt(vs, true, r == 'v' && (s.Flag('+') || s.Flag('#'))))
}
func formatListOpt(vs list, isRoot, allowMulti bool) string {
start, end := "[", "]"
if isRoot {
var name string
switch vs.(type) {
case pref.Names:
name = "Names"
case pref.FieldNumbers:
name = "FieldNumbers"
case pref.FieldRanges:
name = "FieldRanges"
case pref.EnumRanges:
name = "EnumRanges"
case pref.FileImports:
name = "FileImports"
case pref.Descriptor:
name = reflect.ValueOf(vs).MethodByName("Get").Type().Out(0).Name() + "s"
}
start, end = name+"{", "}"
}
var ss []string
switch vs := vs.(type) {
case pref.Names:
for i := 0; i < vs.Len(); i++ {
ss = append(ss, fmt.Sprint(vs.Get(i)))
}
return start + joinStrings(ss, false) + end
case pref.FieldNumbers:
for i := 0; i < vs.Len(); i++ {
ss = append(ss, fmt.Sprint(vs.Get(i)))
}
return start + joinStrings(ss, false) + end
case pref.FieldRanges:
for i := 0; i < vs.Len(); i++ {
r := vs.Get(i)
if r[0]+1 == r[1] {
ss = append(ss, fmt.Sprintf("%d", r[0]))
} else {
ss = append(ss, fmt.Sprintf("%d:%d", r[0], r[1])) // enum ranges are end exclusive
}
}
return start + joinStrings(ss, false) + end
case pref.EnumRanges:
for i := 0; i < vs.Len(); i++ {
r := vs.Get(i)
if r[0] == r[1] {
ss = append(ss, fmt.Sprintf("%d", r[0]))
} else {
ss = append(ss, fmt.Sprintf("%d:%d", r[0], int64(r[1])+1)) // enum ranges are end inclusive
}
}
return start + joinStrings(ss, false) + end
case pref.FileImports:
for i := 0; i < vs.Len(); i++ {
var rs records
rs.Append(reflect.ValueOf(vs.Get(i)), "Path", "Package", "IsPublic", "IsWeak")
ss = append(ss, "{"+rs.Join()+"}")
}
return start + joinStrings(ss, allowMulti) + end
default:
_, isEnumValue := vs.(pref.EnumValueDescriptors)
for i := 0; i < vs.Len(); i++ {
m := reflect.ValueOf(vs).MethodByName("Get")
v := m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
ss = append(ss, formatDescOpt(v.(pref.Descriptor), false, allowMulti && !isEnumValue))
}
return start + joinStrings(ss, allowMulti && isEnumValue) + end
}
}
// descriptorAccessors is a list of accessors to print for each descriptor.
//
// Do not print all accessors since some contain redundant information,
// while others are pointers that we do not want to follow since the descriptor
// is actually a cyclic graph.
//
// Using a list allows us to print the accessors in a sensible order.
var descriptorAccessors = map[reflect.Type][]string{
reflect.TypeOf((*pref.FileDescriptor)(nil)).Elem(): {"Path", "Package", "Imports", "Messages", "Enums", "Extensions", "Services"},
reflect.TypeOf((*pref.MessageDescriptor)(nil)).Elem(): {"IsMapEntry", "Fields", "Oneofs", "ReservedNames", "ReservedRanges", "RequiredNumbers", "ExtensionRanges", "Messages", "Enums", "Extensions"},
reflect.TypeOf((*pref.FieldDescriptor)(nil)).Elem(): {"Number", "Cardinality", "Kind", "HasJSONName", "JSONName", "HasPresence", "IsExtension", "IsPacked", "IsWeak", "IsList", "IsMap", "MapKey", "MapValue", "HasDefault", "Default", "ContainingOneof", "ContainingMessage", "Message", "Enum"},
reflect.TypeOf((*pref.OneofDescriptor)(nil)).Elem(): {"Fields"}, // not directly used; must keep in sync with formatDescOpt
reflect.TypeOf((*pref.EnumDescriptor)(nil)).Elem(): {"Values", "ReservedNames", "ReservedRanges"},
reflect.TypeOf((*pref.EnumValueDescriptor)(nil)).Elem(): {"Number"},
reflect.TypeOf((*pref.ServiceDescriptor)(nil)).Elem(): {"Methods"},
reflect.TypeOf((*pref.MethodDescriptor)(nil)).Elem(): {"Input", "Output", "IsStreamingClient", "IsStreamingServer"},
}
func FormatDesc(s fmt.State, r rune, t pref.Descriptor) {
io.WriteString(s, formatDescOpt(t, true, r == 'v' && (s.Flag('+') || s.Flag('#'))))
}
func formatDescOpt(t pref.Descriptor, isRoot, allowMulti bool) string {
rv := reflect.ValueOf(t)
rt := rv.MethodByName("ProtoType").Type().In(0)
start, end := "{", "}"
if isRoot {
start = rt.Name() + "{"
}
_, isFile := t.(pref.FileDescriptor)
rs := records{allowMulti: allowMulti}
if t.IsPlaceholder() {
if isFile {
rs.Append(rv, "Path", "Package", "IsPlaceholder")
} else {
rs.Append(rv, "FullName", "IsPlaceholder")
}
} else {
switch {
case isFile:
rs.Append(rv, "Syntax")
case isRoot:
rs.Append(rv, "Syntax", "FullName")
default:
rs.Append(rv, "Name")
}
switch t := t.(type) {
case pref.FieldDescriptor:
for _, s := range descriptorAccessors[rt] {
switch s {
case "MapKey":
if k := t.MapKey(); k != nil {
rs.recs = append(rs.recs, [2]string{"MapKey", k.Kind().String()})
}
case "MapValue":
if v := t.MapValue(); v != nil {
switch v.Kind() {
case pref.EnumKind:
rs.recs = append(rs.recs, [2]string{"MapValue", string(v.Enum().FullName())})
case pref.MessageKind, pref.GroupKind:
rs.recs = append(rs.recs, [2]string{"MapValue", string(v.Message().FullName())})
default:
rs.recs = append(rs.recs, [2]string{"MapValue", v.Kind().String()})
}
}
case "ContainingOneof":
if od := t.ContainingOneof(); od != nil {
rs.recs = append(rs.recs, [2]string{"Oneof", string(od.Name())})
}
case "ContainingMessage":
if t.IsExtension() {
rs.recs = append(rs.recs, [2]string{"Extendee", string(t.ContainingMessage().FullName())})
}
case "Message":
if !t.IsMap() {
rs.Append(rv, s)
}
default:
rs.Append(rv, s)
}
}
case pref.OneofDescriptor:
var ss []string
fs := t.Fields()
for i := 0; i < fs.Len(); i++ {
ss = append(ss, string(fs.Get(i).Name()))
}
if len(ss) > 0 {
rs.recs = append(rs.recs, [2]string{"Fields", "[" + joinStrings(ss, false) + "]"})
}
default:
rs.Append(rv, descriptorAccessors[rt]...)
}
if rv.MethodByName("GoType").IsValid() {
rs.Append(rv, "GoType")
}
}
return start + rs.Join() + end
}
type records struct {
recs [][2]string
allowMulti bool
}
func (rs *records) Append(v reflect.Value, accessors ...string) {
for _, a := range accessors {
var rv reflect.Value
if m := v.MethodByName(a); m.IsValid() {
rv = m.Call(nil)[0]
}
if v.Kind() == reflect.Struct && !rv.IsValid() {
rv = v.FieldByName(a)
}
if !rv.IsValid() {
panic(fmt.Sprintf("unknown accessor: %v.%s", v.Type(), a))
}
if _, ok := rv.Interface().(pref.Value); ok {
rv = rv.MethodByName("Interface").Call(nil)[0]
if !rv.IsNil() {
rv = rv.Elem()
}
}
// Ignore zero values.
var isZero bool
switch rv.Kind() {
case reflect.Interface, reflect.Slice:
isZero = rv.IsNil()
case reflect.Bool:
isZero = rv.Bool() == false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
isZero = rv.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
isZero = rv.Uint() == 0
case reflect.String:
isZero = rv.String() == ""
}
if n, ok := rv.Interface().(list); ok {
isZero = n.Len() == 0
}
if isZero {
continue
}
// Format the value.
var s string
v := rv.Interface()
switch v := v.(type) {
case list:
s = formatListOpt(v, false, rs.allowMulti)
case pref.FieldDescriptor, pref.OneofDescriptor, pref.EnumValueDescriptor, pref.MethodDescriptor:
s = string(v.(pref.Descriptor).Name())
case pref.Descriptor:
s = string(v.FullName())
case string:
s = strconv.Quote(v)
case []byte:
s = fmt.Sprintf("%q", v)
default:
s = fmt.Sprint(v)
}
rs.recs = append(rs.recs, [2]string{a, s})
}
}
func (rs *records) Join() string {
var ss []string
// In single line mode, simply join all records with commas.
if !rs.allowMulti {
for _, r := range rs.recs {
ss = append(ss, r[0]+formatColon(0)+r[1])
}
return joinStrings(ss, false)
}
// In allowMulti line mode, align single line records for more readable output.
var maxLen int
flush := func(i int) {
for _, r := range rs.recs[len(ss):i] {
ss = append(ss, r[0]+formatColon(maxLen-len(r[0]))+r[1])
}
maxLen = 0
}
for i, r := range rs.recs {
if isMulti := strings.Contains(r[1], "\n"); isMulti {
flush(i)
ss = append(ss, r[0]+formatColon(0)+strings.Join(strings.Split(r[1], "\n"), "\n\t"))
} else if maxLen < len(r[0]) {
maxLen = len(r[0])
}
}
flush(len(rs.recs))
return joinStrings(ss, true)
}
func formatColon(padding int) string {
// Deliberately introduce instability into the debug output to
// discourage users from performing string comparisons.
// This provides us flexibility to change the output in the future.
if detrand.Bool() {
return ":" + strings.Repeat(" ", 1+padding) // use non-breaking spaces (U+00a0)
} else {
return ":" + strings.Repeat(" ", 1+padding) // use regular spaces (U+0020)
}
}
func joinStrings(ss []string, isMulti bool) string {
if len(ss) == 0 {
return ""
}
if isMulti {
return "\n\t" + strings.Join(ss, "\n\t") + "\n"
}
return strings.Join(ss, ", ")
}

View File

@ -0,0 +1,29 @@
// 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 descopts contains the nil pointers to concrete descriptor options.
//
// This package exists as a form of reverse dependency injection so that certain
// packages (e.g., internal/filedesc and internal/filetype can avoid a direct
// dependency on the descriptor proto package).
package descopts
import pref "google.golang.org/protobuf/reflect/protoreflect"
// These variables are set by the init function in descriptor.pb.go via logic
// in internal/filetype. In other words, so long as the descriptor proto package
// is linked in, these variables will be populated.
//
// Each variable is populated with a nil pointer to the options struct.
var (
File pref.ProtoMessage
Enum pref.ProtoMessage
EnumValue pref.ProtoMessage
Message pref.ProtoMessage
Field pref.ProtoMessage
Oneof pref.ProtoMessage
ExtensionRange pref.ProtoMessage
Service pref.ProtoMessage
Method pref.ProtoMessage
)

View File

@ -0,0 +1,61 @@
// 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 detrand provides deterministically random functionality.
//
// The pseudo-randomness of these functions is seeded by the program binary
// itself and guarantees that the output does not change within a program,
// while ensuring that the output is unstable across different builds.
package detrand
import (
"encoding/binary"
"hash/fnv"
"os"
)
// Disable disables detrand such that all functions returns the zero value.
// This function is not concurrent-safe and must be called during program init.
func Disable() {
randSeed = 0
}
// Bool returns a deterministically random boolean.
func Bool() bool {
return randSeed%2 == 1
}
// randSeed is a best-effort at an approximate hash of the Go binary.
var randSeed = binaryHash()
func binaryHash() uint64 {
// Open the Go binary.
s, err := os.Executable()
if err != nil {
return 0
}
f, err := os.Open(s)
if err != nil {
return 0
}
defer f.Close()
// Hash the size and several samples of the Go binary.
const numSamples = 8
var buf [64]byte
h := fnv.New64()
fi, err := f.Stat()
if err != nil {
return 0
}
binary.LittleEndian.PutUint64(buf[:8], uint64(fi.Size()))
h.Write(buf[:8])
for i := int64(0); i < numSamples; i++ {
if _, err := f.ReadAt(buf[:], i*fi.Size()/numSamples); err != nil {
return 0
}
h.Write(buf[:])
}
return h.Sum64()
}

View File

@ -0,0 +1,213 @@
// 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 defval marshals and unmarshals textual forms of default values.
//
// This package handles both the form historically used in Go struct field tags
// and also the form used by google.protobuf.FieldDescriptorProto.default_value
// since they differ in superficial ways.
package defval
import (
"fmt"
"math"
"strconv"
ptext "google.golang.org/protobuf/internal/encoding/text"
errors "google.golang.org/protobuf/internal/errors"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// Format is the serialization format used to represent the default value.
type Format int
const (
_ Format = iota
// Descriptor uses the serialization format that protoc uses with the
// google.protobuf.FieldDescriptorProto.default_value field.
Descriptor
// GoTag uses the historical serialization format in Go struct field tags.
GoTag
)
// Unmarshal deserializes the default string s according to the given kind k.
// When k is an enum, a list of enum value descriptors must be provided.
func Unmarshal(s string, k pref.Kind, evs pref.EnumValueDescriptors, f Format) (pref.Value, pref.EnumValueDescriptor, error) {
switch k {
case pref.BoolKind:
if f == GoTag {
switch s {
case "1":
return pref.ValueOfBool(true), nil, nil
case "0":
return pref.ValueOfBool(false), nil, nil
}
} else {
switch s {
case "true":
return pref.ValueOfBool(true), nil, nil
case "false":
return pref.ValueOfBool(false), nil, nil
}
}
case pref.EnumKind:
if f == GoTag {
// Go tags use the numeric form of the enum value.
if n, err := strconv.ParseInt(s, 10, 32); err == nil {
if ev := evs.ByNumber(pref.EnumNumber(n)); ev != nil {
return pref.ValueOfEnum(ev.Number()), ev, nil
}
}
} else {
// Descriptor default_value use the enum identifier.
ev := evs.ByName(pref.Name(s))
if ev != nil {
return pref.ValueOfEnum(ev.Number()), ev, nil
}
}
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
if v, err := strconv.ParseInt(s, 10, 32); err == nil {
return pref.ValueOfInt32(int32(v)), nil, nil
}
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
if v, err := strconv.ParseInt(s, 10, 64); err == nil {
return pref.ValueOfInt64(int64(v)), nil, nil
}
case pref.Uint32Kind, pref.Fixed32Kind:
if v, err := strconv.ParseUint(s, 10, 32); err == nil {
return pref.ValueOfUint32(uint32(v)), nil, nil
}
case pref.Uint64Kind, pref.Fixed64Kind:
if v, err := strconv.ParseUint(s, 10, 64); err == nil {
return pref.ValueOfUint64(uint64(v)), nil, nil
}
case pref.FloatKind, pref.DoubleKind:
var v float64
var err error
switch s {
case "-inf":
v = math.Inf(-1)
case "inf":
v = math.Inf(+1)
case "nan":
v = math.NaN()
default:
v, err = strconv.ParseFloat(s, 64)
}
if err == nil {
if k == pref.FloatKind {
return pref.ValueOfFloat32(float32(v)), nil, nil
} else {
return pref.ValueOfFloat64(float64(v)), nil, nil
}
}
case pref.StringKind:
// String values are already unescaped and can be used as is.
return pref.ValueOfString(s), nil, nil
case pref.BytesKind:
if b, ok := unmarshalBytes(s); ok {
return pref.ValueOfBytes(b), nil, nil
}
}
return pref.Value{}, nil, errors.New("could not parse value for %v: %q", k, s)
}
// Marshal serializes v as the default string according to the given kind k.
// When specifying the Descriptor format for an enum kind, the associated
// enum value descriptor must be provided.
func Marshal(v pref.Value, ev pref.EnumValueDescriptor, k pref.Kind, f Format) (string, error) {
switch k {
case pref.BoolKind:
if f == GoTag {
if v.Bool() {
return "1", nil
} else {
return "0", nil
}
} else {
if v.Bool() {
return "true", nil
} else {
return "false", nil
}
}
case pref.EnumKind:
if f == GoTag {
return strconv.FormatInt(int64(v.Enum()), 10), nil
} else {
return string(ev.Name()), nil
}
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind, pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
return strconv.FormatInt(v.Int(), 10), nil
case pref.Uint32Kind, pref.Fixed32Kind, pref.Uint64Kind, pref.Fixed64Kind:
return strconv.FormatUint(v.Uint(), 10), nil
case pref.FloatKind, pref.DoubleKind:
f := v.Float()
switch {
case math.IsInf(f, -1):
return "-inf", nil
case math.IsInf(f, +1):
return "inf", nil
case math.IsNaN(f):
return "nan", nil
default:
if k == pref.FloatKind {
return strconv.FormatFloat(f, 'g', -1, 32), nil
} else {
return strconv.FormatFloat(f, 'g', -1, 64), nil
}
}
case pref.StringKind:
// String values are serialized as is without any escaping.
return v.String(), nil
case pref.BytesKind:
if s, ok := marshalBytes(v.Bytes()); ok {
return s, nil
}
}
return "", errors.New("could not format value for %v: %v", k, v)
}
// unmarshalBytes deserializes bytes by applying C unescaping.
func unmarshalBytes(s string) ([]byte, bool) {
// Bytes values use the same escaping as the text format,
// however they lack the surrounding double quotes.
v, err := ptext.UnmarshalString(`"` + s + `"`)
if err != nil {
return nil, false
}
return []byte(v), true
}
// marshalBytes serializes bytes by using C escaping.
// To match the exact output of protoc, this is identical to the
// CEscape function in strutil.cc of the protoc source code.
func marshalBytes(b []byte) (string, bool) {
var s []byte
for _, c := range b {
switch c {
case '\n':
s = append(s, `\n`...)
case '\r':
s = append(s, `\r`...)
case '\t':
s = append(s, `\t`...)
case '"':
s = append(s, `\"`...)
case '\'':
s = append(s, `\'`...)
case '\\':
s = append(s, `\\`...)
default:
if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
s = append(s, c)
} else {
s = append(s, fmt.Sprintf(`\%03o`, c)...)
}
}
}
return string(s), true
}

View File

@ -0,0 +1,258 @@
// 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 messageset encodes and decodes the obsolete MessageSet wire format.
package messageset
import (
"math"
"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,
// 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.
//
// message MessageSet {
// repeated group Item = 1 {
// required int32 type_id = 2;
// required string message = 3;
// }
// }
const (
FieldItem = protowire.Number(1)
FieldTypeID = protowire.Number(2)
FieldMessage = protowire.Number(3)
)
// ExtensionName is the field name for extensions of MessageSet.
//
// A valid MessageSet extension must be of the form:
// message MyMessage {
// extend proto2.bridge.MessageSet {
// optional MyMessage message_set_extension = 1234;
// }
// ...
// }
const ExtensionName = "message_set_extension"
// IsMessageSet returns whether the message uses the MessageSet wire format.
func IsMessageSet(md pref.MessageDescriptor) bool {
xmd, ok := md.(interface{ IsMessageSet() bool })
return ok && xmd.IsMessageSet()
}
// IsMessageSetExtension reports this field extends a MessageSet.
func IsMessageSetExtension(fd pref.FieldDescriptor) bool {
if fd.Name() != ExtensionName {
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
}
// SizeField returns the size of a MessageSet item field containing an extension
// with the given field number, not counting the contents of the message subfield.
func SizeField(num protowire.Number) int {
return 2*protowire.SizeTag(FieldItem) + protowire.SizeTag(FieldTypeID) + protowire.SizeVarint(uint64(num))
}
// Unmarshal parses a MessageSet.
//
// It calls fn with the type ID and value of each item in the MessageSet.
// Unknown fields are discarded.
//
// If wantLen is true, the item values include the varint length prefix.
// This is ugly, but simplifies the fast-path decoder in internal/impl.
func Unmarshal(b []byte, wantLen bool, fn func(typeID protowire.Number, value []byte) error) error {
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return protowire.ParseError(n)
}
b = b[n:]
if num != FieldItem || wtyp != protowire.StartGroupType {
n := protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return protowire.ParseError(n)
}
b = b[n:]
continue
}
typeID, value, n, err := ConsumeFieldValue(b, wantLen)
if err != nil {
return err
}
b = b[n:]
if typeID == 0 {
continue
}
if err := fn(typeID, value); err != nil {
return err
}
}
return nil
}
// ConsumeFieldValue parses b as a MessageSet item field value until and including
// the trailing end group marker. It assumes the start group tag has already been parsed.
// It returns the contents of the type_id and message subfields and the total
// item length.
//
// If wantLen is true, the returned message value includes the length prefix.
func ConsumeFieldValue(b []byte, wantLen bool) (typeid protowire.Number, message []byte, n int, err error) {
ilen := len(b)
for {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return 0, nil, 0, protowire.ParseError(n)
}
b = b[n:]
switch {
case num == FieldItem && wtyp == protowire.EndGroupType:
if wantLen && len(message) == 0 {
// The message field was missing, which should never happen.
// Be prepared for this case anyway.
message = protowire.AppendVarint(message, 0)
}
return typeid, message, ilen - len(b), nil
case num == FieldTypeID && wtyp == protowire.VarintType:
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, nil, 0, protowire.ParseError(n)
}
b = b[n:]
if v < 1 || v > math.MaxInt32 {
return 0, nil, 0, errors.New("invalid type_id in message set")
}
typeid = protowire.Number(v)
case num == FieldMessage && wtyp == protowire.BytesType:
m, n := protowire.ConsumeBytes(b)
if n < 0 {
return 0, nil, 0, protowire.ParseError(n)
}
if message == nil {
if wantLen {
message = b[:n:n]
} else {
message = m[:len(m):len(m)]
}
} else {
// This case should never happen in practice, but handle it for
// correctness: The MessageSet item contains multiple message
// fields, which need to be merged.
//
// In the case where we're returning the length, this becomes
// quite inefficient since we need to strip the length off
// the existing data and reconstruct it with the combined length.
if wantLen {
_, nn := protowire.ConsumeVarint(message)
m0 := message[nn:]
message = nil
message = protowire.AppendVarint(message, uint64(len(m0)+len(m)))
message = append(message, m0...)
message = append(message, m...)
} else {
message = append(message, m...)
}
}
b = b[n:]
default:
// We have no place to put it, so we just ignore unknown fields.
n := protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return 0, nil, 0, protowire.ParseError(n)
}
b = b[n:]
}
}
}
// AppendFieldStart appends the start of a MessageSet item field containing
// an extension with the given number. The caller must add the message
// subfield (including the tag).
func AppendFieldStart(b []byte, num protowire.Number) []byte {
b = protowire.AppendTag(b, FieldItem, protowire.StartGroupType)
b = protowire.AppendTag(b, FieldTypeID, protowire.VarintType)
b = protowire.AppendVarint(b, uint64(num))
return b
}
// AppendFieldEnd appends the trailing end group marker for a MessageSet item field.
func AppendFieldEnd(b []byte) []byte {
return protowire.AppendTag(b, FieldItem, protowire.EndGroupType)
}
// SizeUnknown returns the size of an unknown fields section in MessageSet format.
//
// See AppendUnknown.
func SizeUnknown(unknown []byte) (size int) {
for len(unknown) > 0 {
num, typ, n := protowire.ConsumeTag(unknown)
if n < 0 || typ != protowire.BytesType {
return 0
}
unknown = unknown[n:]
_, n = protowire.ConsumeBytes(unknown)
if n < 0 {
return 0
}
unknown = unknown[n:]
size += SizeField(num) + protowire.SizeTag(FieldMessage) + n
}
return size
}
// AppendUnknown appends unknown fields to b in MessageSet format.
//
// For historic reasons, unresolved items in a MessageSet are stored in a
// message's unknown fields section in non-MessageSet format. That is, an
// unknown item with typeID T and value V appears in the unknown fields as
// a field with number T and value V.
//
// This function converts the unknown fields back into MessageSet form.
func AppendUnknown(b, unknown []byte) ([]byte, error) {
for len(unknown) > 0 {
num, typ, n := protowire.ConsumeTag(unknown)
if n < 0 || typ != protowire.BytesType {
return nil, errors.New("invalid data in message set unknown fields")
}
unknown = unknown[n:]
_, n = protowire.ConsumeBytes(unknown)
if n < 0 {
return nil, errors.New("invalid data in message set unknown fields")
}
b = AppendFieldStart(b, num)
b = protowire.AppendTag(b, FieldMessage, protowire.BytesType)
b = append(b, unknown[:n]...)
b = AppendFieldEnd(b)
unknown = unknown[n:]
}
return b, nil
}

View File

@ -0,0 +1,207 @@
// 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 tag marshals and unmarshals the legacy struct tags as generated
// by historical versions of protoc-gen-go.
package tag
import (
"reflect"
"strconv"
"strings"
defval "google.golang.org/protobuf/internal/encoding/defval"
fdesc "google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/strs"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
var byteType = reflect.TypeOf(byte(0))
// Unmarshal decodes the tag into a prototype.Field.
//
// The goType is needed to determine the original protoreflect.Kind since the
// tag does not record sufficient information to determine that.
// The type is the underlying field type (e.g., a repeated field may be
// represented by []T, but the Go type passed in is just T).
// A list of enum value descriptors must be provided for enum fields.
// This does not populate the Enum or Message (except for weak message).
//
// This function is a best effort attempt; parsing errors are ignored.
func Unmarshal(tag string, goType reflect.Type, evs pref.EnumValueDescriptors) pref.FieldDescriptor {
f := new(fdesc.Field)
f.L0.ParentFile = fdesc.SurrogateProto2
for len(tag) > 0 {
i := strings.IndexByte(tag, ',')
if i < 0 {
i = len(tag)
}
switch s := tag[:i]; {
case strings.HasPrefix(s, "name="):
f.L0.FullName = pref.FullName(s[len("name="):])
case strings.Trim(s, "0123456789") == "":
n, _ := strconv.ParseUint(s, 10, 32)
f.L1.Number = pref.FieldNumber(n)
case s == "opt":
f.L1.Cardinality = pref.Optional
case s == "req":
f.L1.Cardinality = pref.Required
case s == "rep":
f.L1.Cardinality = pref.Repeated
case s == "varint":
switch goType.Kind() {
case reflect.Bool:
f.L1.Kind = pref.BoolKind
case reflect.Int32:
f.L1.Kind = pref.Int32Kind
case reflect.Int64:
f.L1.Kind = pref.Int64Kind
case reflect.Uint32:
f.L1.Kind = pref.Uint32Kind
case reflect.Uint64:
f.L1.Kind = pref.Uint64Kind
}
case s == "zigzag32":
if goType.Kind() == reflect.Int32 {
f.L1.Kind = pref.Sint32Kind
}
case s == "zigzag64":
if goType.Kind() == reflect.Int64 {
f.L1.Kind = pref.Sint64Kind
}
case s == "fixed32":
switch goType.Kind() {
case reflect.Int32:
f.L1.Kind = pref.Sfixed32Kind
case reflect.Uint32:
f.L1.Kind = pref.Fixed32Kind
case reflect.Float32:
f.L1.Kind = pref.FloatKind
}
case s == "fixed64":
switch goType.Kind() {
case reflect.Int64:
f.L1.Kind = pref.Sfixed64Kind
case reflect.Uint64:
f.L1.Kind = pref.Fixed64Kind
case reflect.Float64:
f.L1.Kind = pref.DoubleKind
}
case s == "bytes":
switch {
case goType.Kind() == reflect.String:
f.L1.Kind = pref.StringKind
case goType.Kind() == reflect.Slice && goType.Elem() == byteType:
f.L1.Kind = pref.BytesKind
default:
f.L1.Kind = pref.MessageKind
}
case s == "group":
f.L1.Kind = pref.GroupKind
case strings.HasPrefix(s, "enum="):
f.L1.Kind = pref.EnumKind
case strings.HasPrefix(s, "json="):
jsonName := s[len("json="):]
if jsonName != strs.JSONCamelCase(string(f.L0.FullName.Name())) {
f.L1.JSONName.Init(jsonName)
}
case s == "packed":
f.L1.HasPacked = true
f.L1.IsPacked = true
case strings.HasPrefix(s, "weak="):
f.L1.IsWeak = true
f.L1.Message = fdesc.PlaceholderMessage(pref.FullName(s[len("weak="):]))
case strings.HasPrefix(s, "def="):
// The default tag is special in that everything afterwards is the
// default regardless of the presence of commas.
s, i = tag[len("def="):], len(tag)
v, ev, _ := defval.Unmarshal(s, f.L1.Kind, evs, defval.GoTag)
f.L1.Default = fdesc.DefaultValue(v, ev)
case s == "proto3":
f.L0.ParentFile = fdesc.SurrogateProto3
}
tag = strings.TrimPrefix(tag[i:], ",")
}
// The generator uses the group message name instead of the field name.
// We obtain the real field name by lowercasing the group name.
if f.L1.Kind == pref.GroupKind {
f.L0.FullName = pref.FullName(strings.ToLower(string(f.L0.FullName)))
}
return f
}
// Marshal encodes the protoreflect.FieldDescriptor as a tag.
//
// The enumName must be provided if the kind is an enum.
// Historically, the formulation of the enum "name" was the proto package
// dot-concatenated with the generated Go identifier for the enum type.
// Depending on the context on how Marshal is called, there are different ways
// through which that information is determined. As such it is the caller's
// responsibility to provide a function to obtain that information.
func Marshal(fd pref.FieldDescriptor, enumName string) string {
var tag []string
switch fd.Kind() {
case pref.BoolKind, pref.EnumKind, pref.Int32Kind, pref.Uint32Kind, pref.Int64Kind, pref.Uint64Kind:
tag = append(tag, "varint")
case pref.Sint32Kind:
tag = append(tag, "zigzag32")
case pref.Sint64Kind:
tag = append(tag, "zigzag64")
case pref.Sfixed32Kind, pref.Fixed32Kind, pref.FloatKind:
tag = append(tag, "fixed32")
case pref.Sfixed64Kind, pref.Fixed64Kind, pref.DoubleKind:
tag = append(tag, "fixed64")
case pref.StringKind, pref.BytesKind, pref.MessageKind:
tag = append(tag, "bytes")
case pref.GroupKind:
tag = append(tag, "group")
}
tag = append(tag, strconv.Itoa(int(fd.Number())))
switch fd.Cardinality() {
case pref.Optional:
tag = append(tag, "opt")
case pref.Required:
tag = append(tag, "req")
case pref.Repeated:
tag = append(tag, "rep")
}
if fd.IsPacked() {
tag = append(tag, "packed")
}
name := string(fd.Name())
if fd.Kind() == pref.GroupKind {
// The name of the FieldDescriptor for a group field is
// lowercased. To find the original capitalization, we
// look in the field's MessageType.
name = string(fd.Message().Name())
}
tag = append(tag, "name="+name)
if jsonName := fd.JSONName(); jsonName != "" && jsonName != name && !fd.IsExtension() {
// NOTE: The jsonName != name condition is suspect, but it preserve
// the exact same semantics from the previous generator.
tag = append(tag, "json="+jsonName)
}
if fd.IsWeak() {
tag = append(tag, "weak="+string(fd.Message().FullName()))
}
// The previous implementation does not tag extension fields as proto3,
// even when the field is defined in a proto3 file. Match that behavior
// for consistency.
if fd.Syntax() == pref.Proto3 && !fd.IsExtension() {
tag = append(tag, "proto3")
}
if fd.Kind() == pref.EnumKind && enumName != "" {
tag = append(tag, "enum="+enumName)
}
if fd.ContainingOneof() != nil {
tag = append(tag, "oneof")
}
// This must appear last in the tag, since commas in strings aren't escaped.
if fd.HasDefault() {
def, _ := defval.Marshal(fd.Default(), fd.DefaultEnumValue(), fd.Kind(), defval.GoTag)
tag = append(tag, "def="+def)
}
return strings.Join(tag, ",")
}

View File

@ -0,0 +1,665 @@
// 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 text
import (
"bytes"
"fmt"
"io"
"regexp"
"strconv"
"unicode/utf8"
"google.golang.org/protobuf/internal/errors"
)
// Decoder is a token-based textproto decoder.
type Decoder struct {
// lastCall is last method called, either readCall or peekCall.
// Initial value is readCall.
lastCall call
// lastToken contains the last read token.
lastToken Token
// lastErr contains the last read error.
lastErr error
// openStack is a stack containing the byte characters for MessageOpen and
// ListOpen kinds. The top of stack represents the message or the list that
// the current token is nested in. An empty stack means the current token is
// at the top level message. The characters '{' and '<' both represent the
// MessageOpen kind.
openStack []byte
// orig is used in reporting line and column.
orig []byte
// in contains the unconsumed input.
in []byte
}
// NewDecoder returns a Decoder to read the given []byte.
func NewDecoder(b []byte) *Decoder {
return &Decoder{orig: b, in: b}
}
// ErrUnexpectedEOF means that EOF was encountered in the middle of the input.
var ErrUnexpectedEOF = errors.New("%v", io.ErrUnexpectedEOF)
// call specifies which Decoder method was invoked.
type call uint8
const (
readCall call = iota
peekCall
)
// Peek looks ahead and returns the next token and error without advancing a read.
func (d *Decoder) Peek() (Token, error) {
defer func() { d.lastCall = peekCall }()
if d.lastCall == readCall {
d.lastToken, d.lastErr = d.Read()
}
return d.lastToken, d.lastErr
}
// Read returns the next token.
// It will return an error if there is no valid token.
func (d *Decoder) Read() (Token, error) {
defer func() { d.lastCall = readCall }()
if d.lastCall == peekCall {
return d.lastToken, d.lastErr
}
tok, err := d.parseNext(d.lastToken.kind)
if err != nil {
return Token{}, err
}
switch tok.kind {
case comma, semicolon:
tok, err = d.parseNext(tok.kind)
if err != nil {
return Token{}, err
}
}
d.lastToken = tok
return tok, nil
}
const (
mismatchedFmt = "mismatched close character %q"
unexpectedFmt = "unexpected character %q"
)
// parseNext parses the next Token based on given last kind.
func (d *Decoder) parseNext(lastKind Kind) (Token, error) {
// Trim leading spaces.
d.consume(0)
isEOF := false
if len(d.in) == 0 {
isEOF = true
}
switch lastKind {
case EOF:
return d.consumeToken(EOF, 0, 0), nil
case bof:
// Start of top level message. Next token can be EOF or Name.
if isEOF {
return d.consumeToken(EOF, 0, 0), nil
}
return d.parseFieldName()
case Name:
// Next token can be MessageOpen, ListOpen or Scalar.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case '{', '<':
d.pushOpenStack(ch)
return d.consumeToken(MessageOpen, 1, 0), nil
case '[':
d.pushOpenStack(ch)
return d.consumeToken(ListOpen, 1, 0), nil
default:
return d.parseScalar()
}
case Scalar:
openKind, closeCh := d.currentOpenKind()
switch openKind {
case bof:
// Top level message.
// Next token can be EOF, comma, semicolon or Name.
if isEOF {
return d.consumeToken(EOF, 0, 0), nil
}
switch d.in[0] {
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
case MessageOpen:
// Next token can be MessageClose, comma, semicolon or Name.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[closeCh]:
return Token{}, d.newSyntaxError(mismatchedFmt, ch)
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
case ListOpen:
// Next token can be ListClose or comma.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case ']':
d.popOpenStack()
return d.consumeToken(ListClose, 1, 0), nil
case ',':
return d.consumeToken(comma, 1, 0), nil
default:
return Token{}, d.newSyntaxError(unexpectedFmt, ch)
}
}
case MessageOpen:
// Next token can be MessageClose or Name.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
_, closeCh := d.currentOpenKind()
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[closeCh]:
return Token{}, d.newSyntaxError(mismatchedFmt, ch)
default:
return d.parseFieldName()
}
case MessageClose:
openKind, closeCh := d.currentOpenKind()
switch openKind {
case bof:
// Top level message.
// Next token can be EOF, comma, semicolon or Name.
if isEOF {
return d.consumeToken(EOF, 0, 0), nil
}
switch ch := d.in[0]; ch {
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
case MessageOpen:
// Next token can be MessageClose, comma, semicolon or Name.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[closeCh]:
return Token{}, d.newSyntaxError(mismatchedFmt, ch)
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
case ListOpen:
// Next token can be ListClose or comma
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(ListClose, 1, 0), nil
case ',':
return d.consumeToken(comma, 1, 0), nil
default:
return Token{}, d.newSyntaxError(unexpectedFmt, ch)
}
}
case ListOpen:
// Next token can be ListClose, MessageStart or Scalar.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case ']':
d.popOpenStack()
return d.consumeToken(ListClose, 1, 0), nil
case '{', '<':
d.pushOpenStack(ch)
return d.consumeToken(MessageOpen, 1, 0), nil
default:
return d.parseScalar()
}
case ListClose:
openKind, closeCh := d.currentOpenKind()
switch openKind {
case bof:
// Top level message.
// Next token can be EOF, comma, semicolon or Name.
if isEOF {
return d.consumeToken(EOF, 0, 0), nil
}
switch ch := d.in[0]; ch {
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
case MessageOpen:
// Next token can be MessageClose, comma, semicolon or Name.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[closeCh]:
return Token{}, d.newSyntaxError(mismatchedFmt, ch)
case ',':
return d.consumeToken(comma, 1, 0), nil
case ';':
return d.consumeToken(semicolon, 1, 0), nil
default:
return d.parseFieldName()
}
default:
// It is not possible to have this case. Let it panic below.
}
case comma, semicolon:
openKind, closeCh := d.currentOpenKind()
switch openKind {
case bof:
// Top level message. Next token can be EOF or Name.
if isEOF {
return d.consumeToken(EOF, 0, 0), nil
}
return d.parseFieldName()
case MessageOpen:
// Next token can be MessageClose or Name.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case closeCh:
d.popOpenStack()
return d.consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[closeCh]:
return Token{}, d.newSyntaxError(mismatchedFmt, ch)
default:
return d.parseFieldName()
}
case ListOpen:
if lastKind == semicolon {
// It is not be possible to have this case as logic here
// should not have produced a semicolon Token when inside a
// list. Let it panic below.
break
}
// Next token can be MessageOpen or Scalar.
if isEOF {
return Token{}, ErrUnexpectedEOF
}
switch ch := d.in[0]; ch {
case '{', '<':
d.pushOpenStack(ch)
return d.consumeToken(MessageOpen, 1, 0), nil
default:
return d.parseScalar()
}
}
}
line, column := d.Position(len(d.orig) - len(d.in))
panic(fmt.Sprintf("Decoder.parseNext: bug at handling line %d:%d with lastKind=%v", line, column, lastKind))
}
var otherCloseChar = map[byte]byte{
'}': '>',
'>': '}',
}
// currentOpenKind indicates whether current position is inside a message, list
// or top-level message by returning MessageOpen, ListOpen or bof respectively.
// If the returned kind is either a MessageOpen or ListOpen, it also returns the
// corresponding closing character.
func (d *Decoder) currentOpenKind() (Kind, byte) {
if len(d.openStack) == 0 {
return bof, 0
}
openCh := d.openStack[len(d.openStack)-1]
switch openCh {
case '{':
return MessageOpen, '}'
case '<':
return MessageOpen, '>'
case '[':
return ListOpen, ']'
}
panic(fmt.Sprintf("Decoder: openStack contains invalid byte %s", string(openCh)))
}
func (d *Decoder) pushOpenStack(ch byte) {
d.openStack = append(d.openStack, ch)
}
func (d *Decoder) popOpenStack() {
d.openStack = d.openStack[:len(d.openStack)-1]
}
// parseFieldName parses field name and separator.
func (d *Decoder) parseFieldName() (tok Token, err error) {
defer func() {
if err == nil && d.tryConsumeChar(':') {
tok.attrs |= hasSeparator
}
}()
// Extension or Any type URL.
if d.in[0] == '[' {
return d.parseTypeName()
}
// Identifier.
if size := parseIdent(d.in, false); size > 0 {
return d.consumeToken(Name, size, uint8(IdentName)), nil
}
// Field number. Identify if input is a valid number that is not negative
// and is decimal integer within 32-bit range.
if num := parseNumber(d.in); num.size > 0 {
if !num.neg && num.kind == numDec {
if _, err := strconv.ParseInt(string(d.in[:num.size]), 10, 32); err == nil {
return d.consumeToken(Name, num.size, uint8(FieldNumber)), nil
}
}
return Token{}, d.newSyntaxError("invalid field number: %s", d.in[:num.size])
}
return Token{}, d.newSyntaxError("invalid field name: %s", errRegexp.Find(d.in))
}
// parseTypeName parses Any type URL or extension field name. The name is
// enclosed in [ and ] characters. The C++ parser does not handle many legal URL
// strings. This implementation is more liberal and allows for the pattern
// ^[-_a-zA-Z0-9]+([./][-_a-zA-Z0-9]+)*`). Whitespaces and comments are allowed
// in between [ ], '.', '/' and the sub names.
func (d *Decoder) parseTypeName() (Token, error) {
startPos := len(d.orig) - len(d.in)
// Use alias s to advance first in order to use d.in for error handling.
// Caller already checks for [ as first character.
s := consume(d.in[1:], 0)
if len(s) == 0 {
return Token{}, ErrUnexpectedEOF
}
var name []byte
for len(s) > 0 && isTypeNameChar(s[0]) {
name = append(name, s[0])
s = s[1:]
}
s = consume(s, 0)
var closed bool
for len(s) > 0 && !closed {
switch {
case s[0] == ']':
s = s[1:]
closed = true
case s[0] == '/', s[0] == '.':
if len(name) > 0 && (name[len(name)-1] == '/' || name[len(name)-1] == '.') {
return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s",
d.orig[startPos:len(d.orig)-len(s)+1])
}
name = append(name, s[0])
s = s[1:]
s = consume(s, 0)
for len(s) > 0 && isTypeNameChar(s[0]) {
name = append(name, s[0])
s = s[1:]
}
s = consume(s, 0)
default:
return Token{}, d.newSyntaxError(
"invalid type URL/extension field name: %s", d.orig[startPos:len(d.orig)-len(s)+1])
}
}
if !closed {
return Token{}, ErrUnexpectedEOF
}
// First character cannot be '.'. Last character cannot be '.' or '/'.
size := len(name)
if size == 0 || name[0] == '.' || name[size-1] == '.' || name[size-1] == '/' {
return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s",
d.orig[startPos:len(d.orig)-len(s)])
}
d.in = s
endPos := len(d.orig) - len(d.in)
d.consume(0)
return Token{
kind: Name,
attrs: uint8(TypeName),
pos: startPos,
raw: d.orig[startPos:endPos],
str: string(name),
}, nil
}
func isTypeNameChar(b byte) bool {
return (b == '-' || b == '_' ||
('0' <= b && b <= '9') ||
('a' <= b && b <= 'z') ||
('A' <= b && b <= 'Z'))
}
func isWhiteSpace(b byte) bool {
switch b {
case ' ', '\n', '\r', '\t':
return true
default:
return false
}
}
// parseIdent parses an unquoted proto identifier and returns size.
// If allowNeg is true, it allows '-' to be the first character in the
// identifier. This is used when parsing literal values like -infinity, etc.
// Regular expression matches an identifier: `^[_a-zA-Z][_a-zA-Z0-9]*`
func parseIdent(input []byte, allowNeg bool) int {
var size int
s := input
if len(s) == 0 {
return 0
}
if allowNeg && s[0] == '-' {
s = s[1:]
size++
if len(s) == 0 {
return 0
}
}
switch {
case s[0] == '_',
'a' <= s[0] && s[0] <= 'z',
'A' <= s[0] && s[0] <= 'Z':
s = s[1:]
size++
default:
return 0
}
for len(s) > 0 && (s[0] == '_' ||
'a' <= s[0] && s[0] <= 'z' ||
'A' <= s[0] && s[0] <= 'Z' ||
'0' <= s[0] && s[0] <= '9') {
s = s[1:]
size++
}
if len(s) > 0 && !isDelim(s[0]) {
return 0
}
return size
}
// parseScalar parses for a string, literal or number value.
func (d *Decoder) parseScalar() (Token, error) {
if d.in[0] == '"' || d.in[0] == '\'' {
return d.parseStringValue()
}
if tok, ok := d.parseLiteralValue(); ok {
return tok, nil
}
if tok, ok := d.parseNumberValue(); ok {
return tok, nil
}
return Token{}, d.newSyntaxError("invalid scalar value: %s", errRegexp.Find(d.in))
}
// parseLiteralValue parses a literal value. A literal value is used for
// bools, special floats and enums. This function simply identifies that the
// field value is a literal.
func (d *Decoder) parseLiteralValue() (Token, bool) {
size := parseIdent(d.in, true)
if size == 0 {
return Token{}, false
}
return d.consumeToken(Scalar, size, literalValue), true
}
// consumeToken constructs a Token for given Kind from d.in and consumes given
// size-length from it.
func (d *Decoder) consumeToken(kind Kind, size int, attrs uint8) Token {
// Important to compute raw and pos before consuming.
tok := Token{
kind: kind,
attrs: attrs,
pos: len(d.orig) - len(d.in),
raw: d.in[:size],
}
d.consume(size)
return tok
}
// newSyntaxError returns a syntax error with line and column information for
// current position.
func (d *Decoder) newSyntaxError(f string, x ...interface{}) error {
e := errors.New(f, x...)
line, column := d.Position(len(d.orig) - len(d.in))
return errors.New("syntax error (line %d:%d): %v", line, column, e)
}
// Position returns line and column number of given index of the original input.
// It will panic if index is out of range.
func (d *Decoder) Position(idx int) (line int, column int) {
b := d.orig[:idx]
line = bytes.Count(b, []byte("\n")) + 1
if i := bytes.LastIndexByte(b, '\n'); i >= 0 {
b = b[i+1:]
}
column = utf8.RuneCount(b) + 1 // ignore multi-rune characters
return line, column
}
func (d *Decoder) tryConsumeChar(c byte) bool {
if len(d.in) > 0 && d.in[0] == c {
d.consume(1)
return true
}
return false
}
// consume consumes n bytes of input and any subsequent whitespace or comments.
func (d *Decoder) consume(n int) {
d.in = consume(d.in, n)
return
}
// consume consumes n bytes of input and any subsequent whitespace or comments.
func consume(b []byte, n int) []byte {
b = b[n:]
for len(b) > 0 {
switch b[0] {
case ' ', '\n', '\r', '\t':
b = b[1:]
case '#':
if i := bytes.IndexByte(b, '\n'); i >= 0 {
b = b[i+len("\n"):]
} else {
b = nil
}
default:
return b
}
}
return b
}
// Any sequence that looks like a non-delimiter (for error reporting).
var errRegexp = regexp.MustCompile(`^([-+._a-zA-Z0-9\/]+|.)`)
// isDelim returns true if given byte is a delimiter character.
func isDelim(c byte) bool {
return !(c == '-' || c == '+' || c == '.' || c == '_' ||
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9'))
}

View File

@ -0,0 +1,190 @@
// 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 text
// parseNumberValue parses a number from the input and returns a Token object.
func (d *Decoder) parseNumberValue() (Token, bool) {
in := d.in
num := parseNumber(in)
if num.size == 0 {
return Token{}, false
}
numAttrs := num.kind
if num.neg {
numAttrs |= isNegative
}
strSize := num.size
last := num.size - 1
if num.kind == numFloat && (d.in[last] == 'f' || d.in[last] == 'F') {
strSize = last
}
tok := Token{
kind: Scalar,
attrs: numberValue,
pos: len(d.orig) - len(d.in),
raw: d.in[:num.size],
str: string(d.in[:strSize]),
numAttrs: numAttrs,
}
d.consume(num.size)
return tok, true
}
const (
numDec uint8 = (1 << iota) / 2
numHex
numOct
numFloat
)
// number is the result of parsing out a valid number from parseNumber. It
// contains data for doing float or integer conversion via the strconv package
// in conjunction with the input bytes.
type number struct {
kind uint8
neg bool
size int
}
// parseNumber constructs a number object from given input. It allows for the
// following patterns:
// integer: ^-?([1-9][0-9]*|0[xX][0-9a-fA-F]+|0[0-7]*)
// float: ^-?((0|[1-9][0-9]*)?([.][0-9]*)?([eE][+-]?[0-9]+)?[fF]?)
// It also returns the number of parsed bytes for the given number, 0 if it is
// not a number.
func parseNumber(input []byte) number {
kind := numDec
var size int
var neg bool
s := input
if len(s) == 0 {
return number{}
}
// Optional -
if s[0] == '-' {
neg = true
s = s[1:]
size++
if len(s) == 0 {
return number{}
}
}
// C++ allows for whitespace and comments in between the negative sign and
// the rest of the number. This logic currently does not but is consistent
// with v1.
switch {
case s[0] == '0':
if len(s) > 1 {
switch {
case s[1] == 'x' || s[1] == 'X':
// Parse as hex number.
kind = numHex
n := 2
s = s[2:]
for len(s) > 0 && (('0' <= s[0] && s[0] <= '9') ||
('a' <= s[0] && s[0] <= 'f') ||
('A' <= s[0] && s[0] <= 'F')) {
s = s[1:]
n++
}
if n == 2 {
return number{}
}
size += n
case '0' <= s[1] && s[1] <= '7':
// Parse as octal number.
kind = numOct
n := 2
s = s[2:]
for len(s) > 0 && '0' <= s[0] && s[0] <= '7' {
s = s[1:]
n++
}
size += n
}
if kind&(numHex|numOct) > 0 {
if len(s) > 0 && !isDelim(s[0]) {
return number{}
}
return number{kind: kind, neg: neg, size: size}
}
}
s = s[1:]
size++
case '1' <= s[0] && s[0] <= '9':
n := 1
s = s[1:]
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
n++
}
size += n
case s[0] == '.':
// Set kind to numFloat to signify the intent to parse as float. And
// that it needs to have other digits after '.'.
kind = numFloat
default:
return number{}
}
// . followed by 0 or more digits.
if len(s) > 0 && s[0] == '.' {
n := 1
s = s[1:]
// If decimal point was before any digits, it should be followed by
// other digits.
if len(s) == 0 && kind == numFloat {
return number{}
}
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
n++
}
size += n
kind = numFloat
}
// e or E followed by an optional - or + and 1 or more digits.
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
kind = numFloat
s = s[1:]
n := 1
if s[0] == '+' || s[0] == '-' {
s = s[1:]
n++
if len(s) == 0 {
return number{}
}
}
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
n++
}
size += n
}
// Optional suffix f or F for floats.
if len(s) > 0 && (s[0] == 'f' || s[0] == 'F') {
kind = numFloat
s = s[1:]
size++
}
// Check that next byte is a delimiter or it is at the end.
if len(s) > 0 && !isDelim(s[0]) {
return number{}
}
return number{kind: kind, neg: neg, size: size}
}

View File

@ -0,0 +1,161 @@
// 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 text
import (
"bytes"
"strconv"
"strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
"google.golang.org/protobuf/internal/strs"
)
// parseStringValue parses string field token.
// This differs from parseString since the text format allows
// multiple back-to-back string literals where they are semantically treated
// as a single large string with all values concatenated.
//
// E.g., `"foo" "bar" "baz"` => "foobarbaz"
func (d *Decoder) parseStringValue() (Token, error) {
// Note that the ending quote is sufficient to unambiguously mark the end
// of a string. Thus, the text grammar does not require intervening
// whitespace or control characters in-between strings.
// Thus, the following is valid:
// `"foo"'bar'"baz"` => "foobarbaz"
in0 := d.in
var ss []string
for len(d.in) > 0 && (d.in[0] == '"' || d.in[0] == '\'') {
s, err := d.parseString()
if err != nil {
return Token{}, err
}
ss = append(ss, s)
}
// d.in already points to the end of the value at this point.
return Token{
kind: Scalar,
attrs: stringValue,
pos: len(d.orig) - len(in0),
raw: in0[:len(in0)-len(d.in)],
str: strings.Join(ss, ""),
}, nil
}
// parseString parses a string value enclosed in " or '.
func (d *Decoder) parseString() (string, error) {
in := d.in
if len(in) == 0 {
return "", ErrUnexpectedEOF
}
quote := in[0]
in = in[1:]
i := indexNeedEscapeInBytes(in)
in, out := in[i:], in[:i:i] // set cap to prevent mutations
for len(in) > 0 {
switch r, n := utf8.DecodeRune(in); {
case r == utf8.RuneError && n == 1:
return "", d.newSyntaxError("invalid UTF-8 detected")
case r == 0 || r == '\n':
return "", d.newSyntaxError("invalid character %q in string", r)
case r == rune(quote):
in = in[1:]
d.consume(len(d.in) - len(in))
return string(out), nil
case r == '\\':
if len(in) < 2 {
return "", ErrUnexpectedEOF
}
switch r := in[1]; r {
case '"', '\'', '\\', '?':
in, out = in[2:], append(out, r)
case 'a':
in, out = in[2:], append(out, '\a')
case 'b':
in, out = in[2:], append(out, '\b')
case 'n':
in, out = in[2:], append(out, '\n')
case 'r':
in, out = in[2:], append(out, '\r')
case 't':
in, out = in[2:], append(out, '\t')
case 'v':
in, out = in[2:], append(out, '\v')
case 'f':
in, out = in[2:], append(out, '\f')
case '0', '1', '2', '3', '4', '5', '6', '7':
// One, two, or three octal characters.
n := len(in[1:]) - len(bytes.TrimLeft(in[1:], "01234567"))
if n > 3 {
n = 3
}
v, err := strconv.ParseUint(string(in[1:1+n]), 8, 8)
if err != nil {
return "", d.newSyntaxError("invalid octal escape code %q in string", in[:1+n])
}
in, out = in[1+n:], append(out, byte(v))
case 'x':
// One or two hexadecimal characters.
n := len(in[2:]) - len(bytes.TrimLeft(in[2:], "0123456789abcdefABCDEF"))
if n > 2 {
n = 2
}
v, err := strconv.ParseUint(string(in[2:2+n]), 16, 8)
if err != nil {
return "", d.newSyntaxError("invalid hex escape code %q in string", in[:2+n])
}
in, out = in[2+n:], append(out, byte(v))
case 'u', 'U':
// Four or eight hexadecimal characters
n := 6
if r == 'U' {
n = 10
}
if len(in) < n {
return "", ErrUnexpectedEOF
}
v, err := strconv.ParseUint(string(in[2:n]), 16, 32)
if utf8.MaxRune < v || err != nil {
return "", d.newSyntaxError("invalid Unicode escape code %q in string", in[:n])
}
in = in[n:]
r := rune(v)
if utf16.IsSurrogate(r) {
if len(in) < 6 {
return "", ErrUnexpectedEOF
}
v, err := strconv.ParseUint(string(in[2:6]), 16, 16)
r = utf16.DecodeRune(r, rune(v))
if in[0] != '\\' || in[1] != 'u' || r == unicode.ReplacementChar || err != nil {
return "", d.newSyntaxError("invalid Unicode escape code %q in string", in[:6])
}
in = in[6:]
}
out = append(out, string(r)...)
default:
return "", d.newSyntaxError("invalid escape code %q in string", in[:2])
}
default:
i := indexNeedEscapeInBytes(in[n:])
in, out = in[n+i:], append(out, in[:n+i]...)
}
}
return "", ErrUnexpectedEOF
}
// indexNeedEscapeInString returns the index of the character that needs
// escaping. If no characters need escaping, this returns the input length.
func indexNeedEscapeInBytes(b []byte) int { return indexNeedEscapeInString(strs.UnsafeString(b)) }
// UnmarshalString returns an unescaped string given a textproto string value.
// String value needs to contain single or double quotes. This is only used by
// internal/encoding/defval package for unmarshaling bytes.
func UnmarshalString(s string) (string, error) {
d := NewDecoder([]byte(s))
return d.parseString()
}

View File

@ -0,0 +1,373 @@
// 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 text
import (
"bytes"
"fmt"
"math"
"strconv"
"strings"
"google.golang.org/protobuf/internal/flags"
)
// Kind represents a token kind expressible in the textproto format.
type Kind uint8
// Kind values.
const (
Invalid Kind = iota
EOF
Name // Name indicates the field name.
Scalar // Scalar are scalar values, e.g. "string", 47, ENUM_LITERAL, true.
MessageOpen
MessageClose
ListOpen
ListClose
// comma and semi-colon are only for parsing in between values and should not be exposed.
comma
semicolon
// bof indicates beginning of file, which is the default token
// kind at the beginning of parsing.
bof = Invalid
)
func (t Kind) String() string {
switch t {
case Invalid:
return "<invalid>"
case EOF:
return "eof"
case Scalar:
return "scalar"
case Name:
return "name"
case MessageOpen:
return "{"
case MessageClose:
return "}"
case ListOpen:
return "["
case ListClose:
return "]"
case comma:
return ","
case semicolon:
return ";"
default:
return fmt.Sprintf("<invalid:%v>", uint8(t))
}
}
// NameKind represents different types of field names.
type NameKind uint8
// NameKind values.
const (
IdentName NameKind = iota + 1
TypeName
FieldNumber
)
func (t NameKind) String() string {
switch t {
case IdentName:
return "IdentName"
case TypeName:
return "TypeName"
case FieldNumber:
return "FieldNumber"
default:
return fmt.Sprintf("<invalid:%v>", uint8(t))
}
}
// Bit mask in Token.attrs to indicate if a Name token is followed by the
// separator char ':'. The field name separator char is optional for message
// field or repeated message field, but required for all other types. Decoder
// simply indicates whether a Name token is followed by separator or not. It is
// up to the prototext package to validate.
const hasSeparator = 1 << 7
// Scalar value types.
const (
numberValue = iota + 1
stringValue
literalValue
)
// Bit mask in Token.numAttrs to indicate that the number is a negative.
const isNegative = 1 << 7
// Token provides a parsed token kind and value. Values are provided by the
// different accessor methods.
type Token struct {
// Kind of the Token object.
kind Kind
// attrs contains metadata for the following Kinds:
// Name: hasSeparator bit and one of NameKind.
// Scalar: one of numberValue, stringValue, literalValue.
attrs uint8
// numAttrs contains metadata for numberValue:
// - highest bit is whether negative or positive.
// - lower bits indicate one of numDec, numHex, numOct, numFloat.
numAttrs uint8
// pos provides the position of the token in the original input.
pos int
// raw bytes of the serialized token.
// This is a subslice into the original input.
raw []byte
// str contains parsed string for the following:
// - stringValue of Scalar kind
// - numberValue of Scalar kind
// - TypeName of Name kind
str string
}
// Kind returns the token kind.
func (t Token) Kind() Kind {
return t.kind
}
// RawString returns the read value in string.
func (t Token) RawString() string {
return string(t.raw)
}
// Pos returns the token position from the input.
func (t Token) Pos() int {
return t.pos
}
// NameKind returns IdentName, TypeName or FieldNumber.
// It panics if type is not Name.
func (t Token) NameKind() NameKind {
if t.kind == Name {
return NameKind(t.attrs &^ hasSeparator)
}
panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))
}
// HasSeparator returns true if the field name is followed by the separator char
// ':', else false. It panics if type is not Name.
func (t Token) HasSeparator() bool {
if t.kind == Name {
return t.attrs&hasSeparator != 0
}
panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))
}
// IdentName returns the value for IdentName type.
func (t Token) IdentName() string {
if t.kind == Name && t.attrs&uint8(IdentName) != 0 {
return string(t.raw)
}
panic(fmt.Sprintf("Token is not an IdentName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
}
// TypeName returns the value for TypeName type.
func (t Token) TypeName() string {
if t.kind == Name && t.attrs&uint8(TypeName) != 0 {
return t.str
}
panic(fmt.Sprintf("Token is not a TypeName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
}
// FieldNumber returns the value for FieldNumber type. It returns a
// non-negative int32 value. Caller will still need to validate for the correct
// field number range.
func (t Token) FieldNumber() int32 {
if t.kind != Name || t.attrs&uint8(FieldNumber) == 0 {
panic(fmt.Sprintf("Token is not a FieldNumber: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
}
// Following should not return an error as it had already been called right
// before this Token was constructed.
num, _ := strconv.ParseInt(string(t.raw), 10, 32)
return int32(num)
}
// String returns the string value for a Scalar type.
func (t Token) String() (string, bool) {
if t.kind != Scalar || t.attrs != stringValue {
return "", false
}
return t.str, true
}
// Enum returns the literal value for a Scalar type for use as enum literals.
func (t Token) Enum() (string, bool) {
if t.kind != Scalar || t.attrs != literalValue || (len(t.raw) > 0 && t.raw[0] == '-') {
return "", false
}
return string(t.raw), true
}
// Bool returns the bool value for a Scalar type.
func (t Token) Bool() (bool, bool) {
if t.kind != Scalar {
return false, false
}
switch t.attrs {
case literalValue:
if b, ok := boolLits[string(t.raw)]; ok {
return b, true
}
case numberValue:
// Unsigned integer representation of 0 or 1 is permitted: 00, 0x0, 01,
// 0x1, etc.
n, err := strconv.ParseUint(t.str, 0, 64)
if err == nil {
switch n {
case 0:
return false, true
case 1:
return true, true
}
}
}
return false, false
}
// These exact boolean literals are the ones supported in C++.
var boolLits = map[string]bool{
"t": true,
"true": true,
"True": true,
"f": false,
"false": false,
"False": false,
}
// Uint64 returns the uint64 value for a Scalar type.
func (t Token) Uint64() (uint64, bool) {
if t.kind != Scalar || t.attrs != numberValue ||
t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {
return 0, false
}
n, err := strconv.ParseUint(t.str, 0, 64)
if err != nil {
return 0, false
}
return n, true
}
// Uint32 returns the uint32 value for a Scalar type.
func (t Token) Uint32() (uint32, bool) {
if t.kind != Scalar || t.attrs != numberValue ||
t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {
return 0, false
}
n, err := strconv.ParseUint(t.str, 0, 32)
if err != nil {
return 0, false
}
return uint32(n), true
}
// Int64 returns the int64 value for a Scalar type.
func (t Token) Int64() (int64, bool) {
if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {
return 0, false
}
if n, err := strconv.ParseInt(t.str, 0, 64); err == nil {
return n, true
}
// C++ accepts large positive hex numbers as negative values.
// This feature is here for proto1 backwards compatibility purposes.
if flags.ProtoLegacy && (t.numAttrs == numHex) {
if n, err := strconv.ParseUint(t.str, 0, 64); err == nil {
return int64(n), true
}
}
return 0, false
}
// Int32 returns the int32 value for a Scalar type.
func (t Token) Int32() (int32, bool) {
if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {
return 0, false
}
if n, err := strconv.ParseInt(t.str, 0, 32); err == nil {
return int32(n), true
}
// C++ accepts large positive hex numbers as negative values.
// This feature is here for proto1 backwards compatibility purposes.
if flags.ProtoLegacy && (t.numAttrs == numHex) {
if n, err := strconv.ParseUint(t.str, 0, 32); err == nil {
return int32(n), true
}
}
return 0, false
}
// Float64 returns the float64 value for a Scalar type.
func (t Token) Float64() (float64, bool) {
if t.kind != Scalar {
return 0, false
}
switch t.attrs {
case literalValue:
if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {
return f, true
}
case numberValue:
n, err := strconv.ParseFloat(t.str, 64)
if err == nil {
return n, true
}
nerr := err.(*strconv.NumError)
if nerr.Err == strconv.ErrRange {
return n, true
}
}
return 0, false
}
// Float32 returns the float32 value for a Scalar type.
func (t Token) Float32() (float32, bool) {
if t.kind != Scalar {
return 0, false
}
switch t.attrs {
case literalValue:
if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {
return float32(f), true
}
case numberValue:
n, err := strconv.ParseFloat(t.str, 64)
if err == nil {
// Overflows are treated as (-)infinity.
return float32(n), true
}
nerr := err.(*strconv.NumError)
if nerr.Err == strconv.ErrRange {
return float32(n), true
}
}
return 0, false
}
// These are the supported float literals which C++ permits case-insensitive
// variants of these.
var floatLits = map[string]float64{
"nan": math.NaN(),
"inf": math.Inf(1),
"infinity": math.Inf(1),
"-inf": math.Inf(-1),
"-infinity": math.Inf(-1),
}
// TokenEquals returns true if given Tokens are equal, else false.
func TokenEquals(x, y Token) bool {
return x.kind == y.kind &&
x.attrs == y.attrs &&
x.numAttrs == y.numAttrs &&
x.pos == y.pos &&
bytes.Equal(x.raw, y.raw) &&
x.str == y.str
}

View File

@ -0,0 +1,29 @@
// 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 text implements the text format for protocol buffers.
// This package has no semantic understanding for protocol buffers and is only
// a parser and composer for the format.
//
// There is no formal specification for the protobuf text format, as such the
// C++ implementation (see google::protobuf::TextFormat) is the reference
// implementation of the text format.
//
// This package is neither a superset nor a subset of the C++ implementation.
// This implementation permits a more liberal grammar in some cases to be
// backwards compatible with the historical Go implementation.
// Future parsings unique to Go should not be added.
// Some grammars allowed by the C++ implementation are deliberately
// not implemented here because they are considered a bug by the protobuf team
// and should not be replicated.
//
// The Go implementation should implement a sufficient amount of the C++
// grammar such that the default text serialization by C++ can be parsed by Go.
// However, just because the C++ parser accepts some input does not mean that
// the Go implementation should as well.
//
// The text format is almost a superset of JSON except:
// * message keys are not quoted strings, but identifiers
// * the top-level value must be a message without the delimiters
package text

View File

@ -0,0 +1,267 @@
// 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 text
import (
"math"
"math/bits"
"strconv"
"strings"
"unicode/utf8"
"google.golang.org/protobuf/internal/detrand"
"google.golang.org/protobuf/internal/errors"
)
// encType represents an encoding type.
type encType uint8
const (
_ encType = (1 << iota) / 2
name
scalar
messageOpen
messageClose
)
// Encoder provides methods to write out textproto constructs and values. The user is
// responsible for producing valid sequences of constructs and values.
type Encoder struct {
encoderState
indent string
newline string // set to "\n" if len(indent) > 0
delims [2]byte
outputASCII bool
}
type encoderState struct {
lastType encType
indents []byte
out []byte
}
// NewEncoder returns an Encoder.
//
// If indent is a non-empty string, it causes every entry in a List or Message
// to be preceded by the indent and trailed by a newline.
//
// If delims is not the zero value, it controls the delimiter characters used
// for messages (e.g., "{}" vs "<>").
//
// If outputASCII is true, strings will be serialized in such a way that
// multi-byte UTF-8 sequences are escaped. This property ensures that the
// overall output is ASCII (as opposed to UTF-8).
func NewEncoder(indent string, delims [2]byte, outputASCII bool) (*Encoder, error) {
e := &Encoder{}
if len(indent) > 0 {
if strings.Trim(indent, " \t") != "" {
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}:
e.delims = [2]byte{'{', '}'}
case [2]byte{'{', '}'}, [2]byte{'<', '>'}:
e.delims = delims
default:
return nil, errors.New("delimiters may only be \"{}\" or \"<>\"")
}
e.outputASCII = outputASCII
return e, nil
}
// Bytes returns the content of the written bytes.
func (e *Encoder) Bytes() []byte {
return e.out
}
// StartMessage writes out the '{' or '<' symbol.
func (e *Encoder) StartMessage() {
e.prepareNext(messageOpen)
e.out = append(e.out, e.delims[0])
}
// EndMessage writes out the '}' or '>' symbol.
func (e *Encoder) EndMessage() {
e.prepareNext(messageClose)
e.out = append(e.out, e.delims[1])
}
// WriteName writes out the field name and the separator ':'.
func (e *Encoder) WriteName(s string) {
e.prepareNext(name)
e.out = append(e.out, s...)
e.out = append(e.out, ':')
}
// WriteBool writes out the given boolean value.
func (e *Encoder) WriteBool(b bool) {
if b {
e.WriteLiteral("true")
} else {
e.WriteLiteral("false")
}
}
// WriteString writes out the given string value.
func (e *Encoder) WriteString(s string) {
e.prepareNext(scalar)
e.out = appendString(e.out, s, e.outputASCII)
}
func appendString(out []byte, in string, outputASCII bool) []byte {
out = append(out, '"')
i := indexNeedEscapeInString(in)
in, out = in[i:], append(out, in[:i]...)
for len(in) > 0 {
switch r, n := utf8.DecodeRuneInString(in); {
case r == utf8.RuneError && n == 1:
// We do not report invalid UTF-8 because strings in the text format
// are used to represent both the proto string and bytes type.
r = rune(in[0])
fallthrough
case r < ' ' || r == '"' || r == '\\':
out = append(out, '\\')
switch r {
case '"', '\\':
out = append(out, byte(r))
case '\n':
out = append(out, 'n')
case '\r':
out = append(out, 'r')
case '\t':
out = append(out, 't')
default:
out = append(out, 'x')
out = append(out, "00"[1+(bits.Len32(uint32(r))-1)/4:]...)
out = strconv.AppendUint(out, uint64(r), 16)
}
in = in[n:]
case outputASCII && r >= utf8.RuneSelf:
out = append(out, '\\')
if r <= math.MaxUint16 {
out = append(out, 'u')
out = append(out, "0000"[1+(bits.Len32(uint32(r))-1)/4:]...)
out = strconv.AppendUint(out, uint64(r), 16)
} else {
out = append(out, 'U')
out = append(out, "00000000"[1+(bits.Len32(uint32(r))-1)/4:]...)
out = strconv.AppendUint(out, uint64(r), 16)
}
in = in[n:]
default:
i := indexNeedEscapeInString(in[n:])
in, out = in[n+i:], append(out, in[:n+i]...)
}
}
out = append(out, '"')
return out
}
// indexNeedEscapeInString returns the index of the character that needs
// 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 {
return i
}
}
return len(s)
}
// WriteFloat writes out the given float value for given bitSize.
func (e *Encoder) WriteFloat(n float64, bitSize int) {
e.prepareNext(scalar)
e.out = appendFloat(e.out, n, bitSize)
}
func appendFloat(out []byte, n float64, bitSize int) []byte {
switch {
case math.IsNaN(n):
return append(out, "nan"...)
case math.IsInf(n, +1):
return append(out, "inf"...)
case math.IsInf(n, -1):
return append(out, "-inf"...)
default:
return strconv.AppendFloat(out, n, 'g', -1, bitSize)
}
}
// WriteInt writes out the given signed integer value.
func (e *Encoder) WriteInt(n int64) {
e.prepareNext(scalar)
e.out = append(e.out, strconv.FormatInt(n, 10)...)
}
// WriteUint writes out the given unsigned integer value.
func (e *Encoder) WriteUint(n uint64) {
e.prepareNext(scalar)
e.out = append(e.out, strconv.FormatUint(n, 10)...)
}
// WriteLiteral writes out the given string as a literal value without quotes.
// This is used for writing enum literal strings.
func (e *Encoder) WriteLiteral(s string) {
e.prepareNext(scalar)
e.out = append(e.out, s...)
}
// prepareNext adds possible space and indentation for the next value based
// on last encType and indent option. It also updates e.lastType to next.
func (e *Encoder) prepareNext(next encType) {
defer func() {
e.lastType = next
}()
// Single line.
if len(e.indent) == 0 {
// Add space after each field before the next one.
if e.lastType&(scalar|messageClose) != 0 && next == name {
e.out = append(e.out, ' ')
// Add a random extra space to make output unstable.
if detrand.Bool() {
e.out = append(e.out, ' ')
}
}
return
}
// Multi-line.
switch {
case e.lastType == name:
e.out = append(e.out, ' ')
// Add a random extra space after name: to make output unstable.
if detrand.Bool() {
e.out = append(e.out, ' ')
}
case e.lastType == messageOpen && next != messageClose:
e.indents = append(e.indents, e.indent...)
e.out = append(e.out, '\n')
e.out = append(e.out, e.indents...)
case e.lastType&(scalar|messageClose) != 0:
if next == messageClose {
e.indents = e.indents[:len(e.indents)-len(e.indent)]
}
e.out = append(e.out, '\n')
e.out = append(e.out, e.indents...)
}
}
// Snapshot returns the current snapshot for use in Reset.
func (e *Encoder) Snapshot() encoderState {
return e.encoderState
}
// Reset resets the Encoder to the given encoderState from a Snapshot.
func (e *Encoder) Reset(es encoderState) {
e.encoderState = es
}

View File

@ -0,0 +1,89 @@
// 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 errors implements functions to manipulate errors.
package errors
import (
"errors"
"fmt"
"google.golang.org/protobuf/internal/detrand"
)
// Error is a sentinel matching all errors produced by this package.
var Error = errors.New("protobuf error")
// New formats a string according to the format specifier and arguments and
// returns an error that has a "proto" prefix.
func New(f string, x ...interface{}) error {
return &prefixError{s: format(f, x...)}
}
type prefixError struct{ s string }
var prefix = func() string {
// Deliberately introduce instability into the error message string to
// discourage users from performing error string comparisons.
if detrand.Bool() {
return "proto: " // use non-breaking spaces (U+00a0)
} else {
return "proto: " // use regular spaces (U+0020)
}
}()
func (e *prefixError) Error() string {
return prefix + e.s
}
func (e *prefixError) Unwrap() error {
return Error
}
// Wrap returns an error that has a "proto" prefix, the formatted string described
// by the format specifier and arguments, and a suffix of err. The error wraps err.
func Wrap(err error, f string, x ...interface{}) error {
return &wrapError{
s: format(f, x...),
err: err,
}
}
type wrapError struct {
s string
err error
}
func (e *wrapError) Error() string {
return format("%v%v: %v", prefix, e.s, e.err)
}
func (e *wrapError) Unwrap() error {
return e.err
}
func (e *wrapError) Is(target error) bool {
return target == Error
}
func format(f string, x ...interface{}) string {
// avoid "proto: " prefix when chaining
for i := 0; i < len(x); i++ {
switch e := x[i].(type) {
case *prefixError:
x[i] = e.s
case *wrapError:
x[i] = format("%v: %v", e.s, e.err)
}
}
return fmt.Sprintf(f, x...)
}
func InvalidUTF8(name string) error {
return New("field %v contains invalid UTF-8", name)
}
func RequiredNotSet(name string) error {
return New("required field %v not set", name)
}

View File

@ -0,0 +1,39 @@
// 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.
// +build !go1.13
package errors
import "reflect"
// Is is a copy of Go 1.13's errors.Is for use with older Go versions.
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflect.TypeOf(target).Comparable()
for {
if isComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
if err = unwrap(err); err == nil {
return false
}
}
}
func unwrap(err error) error {
u, ok := err.(interface {
Unwrap() error
})
if !ok {
return nil
}
return u.Unwrap()
}

View File

@ -0,0 +1,12 @@
// 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.
// +build go1.13
package errors
import "errors"
// Is is errors.Is.
func Is(err, target error) bool { return errors.Is(err, target) }

View File

@ -0,0 +1,40 @@
// 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

@ -0,0 +1,155 @@
// 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 filedesc provides functionality for constructing descriptors.
package filedesc
import (
"google.golang.org/protobuf/encoding/protowire"
"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"
)
// Builder construct a protoreflect.FileDescriptor from the raw descriptor.
type Builder struct {
// GoPackagePath is the Go package path that is invoking this builder.
GoPackagePath string
// RawDescriptor is the wire-encoded bytes of FileDescriptorProto
// and must be populated.
RawDescriptor []byte
// NumEnums is the total number of enums declared in the file.
NumEnums int32
// NumMessages is the total number of messages declared in the file.
// It includes the implicit message declarations for map entries.
NumMessages int32
// NumExtensions is the total number of extensions declared in the file.
NumExtensions int32
// NumServices is the total number of services declared in the file.
NumServices int32
// TypeResolver resolves extension field types for descriptor options.
// If nil, it uses protoregistry.GlobalTypes.
TypeResolver interface {
preg.ExtensionTypeResolver
}
// FileRegistry is use to lookup file, enum, and message dependencies.
// Once constructed, the file descriptor is registered here.
// If nil, it uses protoregistry.GlobalFiles.
FileRegistry interface {
FindFileByPath(string) (protoreflect.FileDescriptor, error)
FindDescriptorByName(pref.FullName) (pref.Descriptor, error)
RegisterFile(pref.FileDescriptor) error
}
}
// resolverByIndex is an interface Builder.FileRegistry may implement.
// If so, it permits looking up an enum or message dependency based on the
// sub-list and element index into filetype.Builder.DependencyIndexes.
type resolverByIndex interface {
FindEnumByIndex(int32, int32, []Enum, []Message) pref.EnumDescriptor
FindMessageByIndex(int32, int32, []Enum, []Message) pref.MessageDescriptor
}
// Indexes of each sub-list in filetype.Builder.DependencyIndexes.
const (
listFieldDeps int32 = iota
listExtTargets
listExtDeps
listMethInDeps
listMethOutDeps
)
// Out is the output of the Builder.
type Out struct {
File pref.FileDescriptor
// Enums is all enum descriptors in "flattened ordering".
Enums []Enum
// Messages is all message descriptors in "flattened ordering".
// It includes the implicit message declarations for map entries.
Messages []Message
// Extensions is all extension descriptors in "flattened ordering".
Extensions []Extension
// Service is all service descriptors in "flattened ordering".
Services []Service
}
// Build constructs a FileDescriptor given the parameters set in Builder.
// It assumes that the inputs are well-formed and panics if any inconsistencies
// are encountered.
//
// If NumEnums+NumMessages+NumExtensions+NumServices is zero,
// then Build automatically derives them from the raw descriptor.
func (db Builder) Build() (out Out) {
// Populate the counts if uninitialized.
if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
db.unmarshalCounts(db.RawDescriptor, true)
}
// Initialize resolvers and registries if unpopulated.
if db.TypeResolver == nil {
db.TypeResolver = preg.GlobalTypes
}
if db.FileRegistry == nil {
db.FileRegistry = preg.GlobalFiles
}
fd := newRawFile(db)
out.File = fd
out.Enums = fd.allEnums
out.Messages = fd.allMessages
out.Extensions = fd.allExtensions
out.Services = fd.allServices
if err := db.FileRegistry.RegisterFile(fd); err != nil {
panic(err)
}
return out
}
// unmarshalCounts counts the number of enum, message, extension, and service
// declarations in the raw message, which is either a FileDescriptorProto
// or a MessageDescriptorProto depending on whether isFile is set.
func (db *Builder) unmarshalCounts(b []byte, isFile bool) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
if isFile {
switch num {
case genid.FileDescriptorProto_EnumType_field_number:
db.NumEnums++
case genid.FileDescriptorProto_MessageType_field_number:
db.unmarshalCounts(v, false)
db.NumMessages++
case genid.FileDescriptorProto_Extension_field_number:
db.NumExtensions++
case genid.FileDescriptorProto_Service_field_number:
db.NumServices++
}
} else {
switch num {
case genid.DescriptorProto_EnumType_field_number:
db.NumEnums++
case genid.DescriptorProto_NestedType_field_number:
db.unmarshalCounts(v, false)
db.NumMessages++
case genid.DescriptorProto_Extension_field_number:
db.NumExtensions++
}
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}

View File

@ -0,0 +1,614 @@
// 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 filedesc
import (
"bytes"
"fmt"
"sync"
"sync/atomic"
"google.golang.org/protobuf/internal/descfmt"
"google.golang.org/protobuf/internal/descopts"
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/strs"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// The types in this file may have a suffix:
// • L0: Contains fields common to all descriptors (except File) and
// must be initialized up front.
// • L1: Contains fields specific to a descriptor and
// must be initialized up front.
// • L2: Contains fields that are lazily initialized when constructing
// from the raw file descriptor. When constructing as a literal, the L2
// fields must be initialized up front.
//
// The types are exported so that packages like reflect/protodesc can
// directly construct descriptors.
type (
File struct {
fileRaw
L1 FileL1
once uint32 // atomically set if L2 is valid
mu sync.Mutex // protects L2
L2 *FileL2
}
FileL1 struct {
Syntax pref.Syntax
Path string
Package pref.FullName
Enums Enums
Messages Messages
Extensions Extensions
Services Services
}
FileL2 struct {
Options func() pref.ProtoMessage
Imports FileImports
Locations SourceLocations
}
)
func (fd *File) ParentFile() pref.FileDescriptor { return fd }
func (fd *File) Parent() pref.Descriptor { return nil }
func (fd *File) Index() int { return 0 }
func (fd *File) Syntax() pref.Syntax { return fd.L1.Syntax }
func (fd *File) Name() pref.Name { return fd.L1.Package.Name() }
func (fd *File) FullName() pref.FullName { return fd.L1.Package }
func (fd *File) IsPlaceholder() bool { return false }
func (fd *File) Options() pref.ProtoMessage {
if f := fd.lazyInit().Options; f != nil {
return f()
}
return descopts.File
}
func (fd *File) Path() string { return fd.L1.Path }
func (fd *File) Package() pref.FullName { return fd.L1.Package }
func (fd *File) Imports() pref.FileImports { return &fd.lazyInit().Imports }
func (fd *File) Enums() pref.EnumDescriptors { return &fd.L1.Enums }
func (fd *File) Messages() pref.MessageDescriptors { return &fd.L1.Messages }
func (fd *File) Extensions() pref.ExtensionDescriptors { return &fd.L1.Extensions }
func (fd *File) Services() pref.ServiceDescriptors { return &fd.L1.Services }
func (fd *File) SourceLocations() pref.SourceLocations { return &fd.lazyInit().Locations }
func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
func (fd *File) ProtoType(pref.FileDescriptor) {}
func (fd *File) ProtoInternal(pragma.DoNotImplement) {}
func (fd *File) lazyInit() *FileL2 {
if atomic.LoadUint32(&fd.once) == 0 {
fd.lazyInitOnce()
}
return fd.L2
}
func (fd *File) lazyInitOnce() {
fd.mu.Lock()
if fd.L2 == nil {
fd.lazyRawInit() // recursively initializes all L2 structures
}
atomic.StoreUint32(&fd.once, 1)
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.
//
// WARNING: This method is exempt from the compatibility promise and may be
// removed in the future without warning.
func (fd *File) GoPackagePath() string {
return fd.builder.GoPackagePath
}
type (
Enum struct {
Base
L1 EnumL1
L2 *EnumL2 // protected by fileDesc.once
}
EnumL1 struct {
eagerValues bool // controls whether EnumL2.Values is already populated
}
EnumL2 struct {
Options func() pref.ProtoMessage
Values EnumValues
ReservedNames Names
ReservedRanges EnumRanges
}
EnumValue struct {
Base
L1 EnumValueL1
}
EnumValueL1 struct {
Options func() pref.ProtoMessage
Number pref.EnumNumber
}
)
func (ed *Enum) Options() pref.ProtoMessage {
if f := ed.lazyInit().Options; f != nil {
return f()
}
return descopts.Enum
}
func (ed *Enum) Values() pref.EnumValueDescriptors {
if ed.L1.eagerValues {
return &ed.L2.Values
}
return &ed.lazyInit().Values
}
func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames }
func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges }
func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
func (ed *Enum) ProtoType(pref.EnumDescriptor) {}
func (ed *Enum) lazyInit() *EnumL2 {
ed.L0.ParentFile.lazyInit() // implicitly initializes L2
return ed.L2
}
func (ed *EnumValue) Options() pref.ProtoMessage {
if f := ed.L1.Options; f != nil {
return f()
}
return descopts.EnumValue
}
func (ed *EnumValue) Number() pref.EnumNumber { return ed.L1.Number }
func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
func (ed *EnumValue) ProtoType(pref.EnumValueDescriptor) {}
type (
Message struct {
Base
L1 MessageL1
L2 *MessageL2 // protected by fileDesc.once
}
MessageL1 struct {
Enums Enums
Messages Messages
Extensions Extensions
IsMapEntry bool // promoted from google.protobuf.MessageOptions
IsMessageSet bool // promoted from google.protobuf.MessageOptions
}
MessageL2 struct {
Options func() pref.ProtoMessage
Fields Fields
Oneofs Oneofs
ReservedNames Names
ReservedRanges FieldRanges
RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality
ExtensionRanges FieldRanges
ExtensionRangeOptions []func() pref.ProtoMessage // must be same length as ExtensionRanges
}
Field struct {
Base
L1 FieldL1
}
FieldL1 struct {
Options func() pref.ProtoMessage
Number pref.FieldNumber
Cardinality pref.Cardinality // must be consistent with Message.RequiredNumbers
Kind pref.Kind
JSONName jsonName
IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
IsWeak bool // promoted from google.protobuf.FieldOptions
HasPacked bool // promoted from google.protobuf.FieldOptions
IsPacked bool // promoted from google.protobuf.FieldOptions
HasEnforceUTF8 bool // promoted from google.protobuf.FieldOptions
EnforceUTF8 bool // promoted from google.protobuf.FieldOptions
Default defaultValue
ContainingOneof pref.OneofDescriptor // must be consistent with Message.Oneofs.Fields
Enum pref.EnumDescriptor
Message pref.MessageDescriptor
}
Oneof struct {
Base
L1 OneofL1
}
OneofL1 struct {
Options func() pref.ProtoMessage
Fields OneofFields // must be consistent with Message.Fields.ContainingOneof
}
)
func (md *Message) Options() pref.ProtoMessage {
if f := md.lazyInit().Options; f != nil {
return f()
}
return descopts.Message
}
func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry }
func (md *Message) Fields() pref.FieldDescriptors { return &md.lazyInit().Fields }
func (md *Message) Oneofs() pref.OneofDescriptors { return &md.lazyInit().Oneofs }
func (md *Message) ReservedNames() pref.Names { return &md.lazyInit().ReservedNames }
func (md *Message) ReservedRanges() pref.FieldRanges { return &md.lazyInit().ReservedRanges }
func (md *Message) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().RequiredNumbers }
func (md *Message) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().ExtensionRanges }
func (md *Message) ExtensionRangeOptions(i int) pref.ProtoMessage {
if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
return f()
}
return descopts.ExtensionRange
}
func (md *Message) Enums() pref.EnumDescriptors { return &md.L1.Enums }
func (md *Message) Messages() pref.MessageDescriptors { return &md.L1.Messages }
func (md *Message) Extensions() pref.ExtensionDescriptors { return &md.L1.Extensions }
func (md *Message) ProtoType(pref.MessageDescriptor) {}
func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
func (md *Message) lazyInit() *MessageL2 {
md.L0.ParentFile.lazyInit() // implicitly initializes L2
return md.L2
}
// IsMessageSet is a pseudo-internal API for checking whether a message
// should serialize in the proto1 message format.
//
// WARNING: This method is exempt from the compatibility promise and may be
// removed in the future without warning.
func (md *Message) IsMessageSet() bool {
return md.L1.IsMessageSet
}
func (fd *Field) Options() pref.ProtoMessage {
if f := fd.L1.Options; f != nil {
return f()
}
return descopts.Field
}
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) HasPresence() bool {
return fd.L1.Cardinality != pref.Repeated && (fd.L0.ParentFile.L1.Syntax == pref.Proto2 || fd.L1.Message != nil || fd.L1.ContainingOneof != nil)
}
func (fd *Field) HasOptionalKeyword() bool {
return (fd.L0.ParentFile.L1.Syntax == pref.Proto2 && fd.L1.Cardinality == pref.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional
}
func (fd *Field) IsPacked() bool {
if !fd.L1.HasPacked && fd.L0.ParentFile.L1.Syntax != pref.Proto2 && fd.L1.Cardinality == pref.Repeated {
switch fd.L1.Kind {
case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind:
default:
return true
}
}
return fd.L1.IsPacked
}
func (fd *Field) IsExtension() bool { return false }
func (fd *Field) IsWeak() bool { return fd.L1.IsWeak }
func (fd *Field) IsList() bool { return fd.Cardinality() == pref.Repeated && !fd.IsMap() }
func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() }
func (fd *Field) MapKey() pref.FieldDescriptor {
if !fd.IsMap() {
return nil
}
return fd.Message().Fields().ByNumber(genid.MapEntry_Key_field_number)
}
func (fd *Field) MapValue() pref.FieldDescriptor {
if !fd.IsMap() {
return nil
}
return fd.Message().Fields().ByNumber(genid.MapEntry_Value_field_number)
}
func (fd *Field) HasDefault() bool { return fd.L1.Default.has }
func (fd *Field) Default() pref.Value { return fd.L1.Default.get(fd) }
func (fd *Field) DefaultEnumValue() pref.EnumValueDescriptor { return fd.L1.Default.enum }
func (fd *Field) ContainingOneof() pref.OneofDescriptor { return fd.L1.ContainingOneof }
func (fd *Field) ContainingMessage() pref.MessageDescriptor {
return fd.L0.Parent.(pref.MessageDescriptor)
}
func (fd *Field) Enum() pref.EnumDescriptor {
return fd.L1.Enum
}
func (fd *Field) Message() pref.MessageDescriptor {
if fd.L1.IsWeak {
if d, _ := protoregistry.GlobalFiles.FindDescriptorByName(fd.L1.Message.FullName()); d != nil {
return d.(pref.MessageDescriptor)
}
}
return fd.L1.Message
}
func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
func (fd *Field) ProtoType(pref.FieldDescriptor) {}
// EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8
// validation for the string field. This exists for Google-internal use only
// since proto3 did not enforce UTF-8 validity prior to the open-source release.
// If this method does not exist, the default is to enforce valid UTF-8.
//
// WARNING: This method is exempt from the compatibility promise and may be
// removed in the future without warning.
func (fd *Field) EnforceUTF8() bool {
if fd.L1.HasEnforceUTF8 {
return fd.L1.EnforceUTF8
}
return fd.L0.ParentFile.L1.Syntax == pref.Proto3
}
func (od *Oneof) IsSynthetic() bool {
return od.L0.ParentFile.L1.Syntax == pref.Proto3 && len(od.L1.Fields.List) == 1 && od.L1.Fields.List[0].HasOptionalKeyword()
}
func (od *Oneof) Options() pref.ProtoMessage {
if f := od.L1.Options; f != nil {
return f()
}
return descopts.Oneof
}
func (od *Oneof) Fields() pref.FieldDescriptors { return &od.L1.Fields }
func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) }
func (od *Oneof) ProtoType(pref.OneofDescriptor) {}
type (
Extension struct {
Base
L1 ExtensionL1
L2 *ExtensionL2 // protected by fileDesc.once
}
ExtensionL1 struct {
Number pref.FieldNumber
Extendee pref.MessageDescriptor
Cardinality pref.Cardinality
Kind pref.Kind
}
ExtensionL2 struct {
Options func() pref.ProtoMessage
JSONName jsonName
IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
IsPacked bool // promoted from google.protobuf.FieldOptions
Default defaultValue
Enum pref.EnumDescriptor
Message pref.MessageDescriptor
}
)
func (xd *Extension) Options() pref.ProtoMessage {
if f := xd.lazyInit().Options; f != nil {
return f()
}
return descopts.Field
}
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) 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
}
func (xd *Extension) IsPacked() bool { return xd.lazyInit().IsPacked }
func (xd *Extension) IsExtension() bool { return true }
func (xd *Extension) IsWeak() bool { return false }
func (xd *Extension) IsList() bool { return xd.Cardinality() == pref.Repeated }
func (xd *Extension) IsMap() bool { return false }
func (xd *Extension) MapKey() pref.FieldDescriptor { return nil }
func (xd *Extension) MapValue() pref.FieldDescriptor { return nil }
func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has }
func (xd *Extension) Default() pref.Value { return xd.lazyInit().Default.get(xd) }
func (xd *Extension) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().Default.enum }
func (xd *Extension) ContainingOneof() pref.OneofDescriptor { return nil }
func (xd *Extension) ContainingMessage() pref.MessageDescriptor { return xd.L1.Extendee }
func (xd *Extension) Enum() pref.EnumDescriptor { return xd.lazyInit().Enum }
func (xd *Extension) Message() pref.MessageDescriptor { return xd.lazyInit().Message }
func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) }
func (xd *Extension) ProtoType(pref.FieldDescriptor) {}
func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {}
func (xd *Extension) lazyInit() *ExtensionL2 {
xd.L0.ParentFile.lazyInit() // implicitly initializes L2
return xd.L2
}
type (
Service struct {
Base
L1 ServiceL1
L2 *ServiceL2 // protected by fileDesc.once
}
ServiceL1 struct{}
ServiceL2 struct {
Options func() pref.ProtoMessage
Methods Methods
}
Method struct {
Base
L1 MethodL1
}
MethodL1 struct {
Options func() pref.ProtoMessage
Input pref.MessageDescriptor
Output pref.MessageDescriptor
IsStreamingClient bool
IsStreamingServer bool
}
)
func (sd *Service) Options() pref.ProtoMessage {
if f := sd.lazyInit().Options; f != nil {
return f()
}
return descopts.Service
}
func (sd *Service) Methods() pref.MethodDescriptors { return &sd.lazyInit().Methods }
func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) }
func (sd *Service) ProtoType(pref.ServiceDescriptor) {}
func (sd *Service) ProtoInternal(pragma.DoNotImplement) {}
func (sd *Service) lazyInit() *ServiceL2 {
sd.L0.ParentFile.lazyInit() // implicitly initializes L2
return sd.L2
}
func (md *Method) Options() pref.ProtoMessage {
if f := md.L1.Options; f != nil {
return f()
}
return descopts.Method
}
func (md *Method) Input() pref.MessageDescriptor { return md.L1.Input }
func (md *Method) Output() pref.MessageDescriptor { return md.L1.Output }
func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient }
func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer }
func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
func (md *Method) ProtoType(pref.MethodDescriptor) {}
func (md *Method) ProtoInternal(pragma.DoNotImplement) {}
// Surrogate files are can be used to create standalone descriptors
// where the syntax is only information derived from the parent file.
var (
SurrogateProto2 = &File{L1: FileL1{Syntax: pref.Proto2}, L2: &FileL2{}}
SurrogateProto3 = &File{L1: FileL1{Syntax: pref.Proto3}, L2: &FileL2{}}
)
type (
Base struct {
L0 BaseL0
}
BaseL0 struct {
FullName pref.FullName // must be populated
ParentFile *File // must be populated
Parent pref.Descriptor
Index int
}
)
func (d *Base) Name() pref.Name { return d.L0.FullName.Name() }
func (d *Base) FullName() pref.FullName { return d.L0.FullName }
func (d *Base) ParentFile() pref.FileDescriptor {
if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 {
return nil // surrogate files are not real parents
}
return d.L0.ParentFile
}
func (d *Base) Parent() pref.Descriptor { return d.L0.Parent }
func (d *Base) Index() int { return d.L0.Index }
func (d *Base) Syntax() pref.Syntax { return d.L0.ParentFile.Syntax() }
func (d *Base) IsPlaceholder() bool { return false }
func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
type jsonName struct {
has bool
once sync.Once
name 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
}
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 DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue {
dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
if b, ok := v.Interface().([]byte); ok {
// Store a copy of the default bytes, so that we can detect
// accidental mutations of the original value.
dv.bytes = append([]byte(nil), b...)
}
return dv
}
func unmarshalDefault(b []byte, k pref.Kind, pf *File, ed pref.EnumDescriptor) defaultValue {
var evs pref.EnumValueDescriptors
if k == pref.EnumKind {
// If the enum is declared within the same file, be careful not to
// blindly call the Values method, lest we bind ourselves in a deadlock.
if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf {
evs = &e.L2.Values
} else {
evs = ed.Values()
}
// If we are unable to resolve the enum dependency, use a placeholder
// enum value since we will not be able to parse the default value.
if ed.IsPlaceholder() && pref.Name(b).IsValid() {
v := pref.ValueOfEnum(0)
ev := PlaceholderEnumValue(ed.FullName().Parent().Append(pref.Name(b)))
return DefaultValue(v, ev)
}
}
v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
if err != nil {
panic(err)
}
return DefaultValue(v, ev)
}
type defaultValue struct {
has bool
val pref.Value
enum pref.EnumValueDescriptor
bytes []byte
}
func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value {
// Return the zero value as the default if unpopulated.
if !dv.has {
if fd.Cardinality() == pref.Repeated {
return pref.Value{}
}
switch fd.Kind() {
case pref.BoolKind:
return pref.ValueOfBool(false)
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
return pref.ValueOfInt32(0)
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
return pref.ValueOfInt64(0)
case pref.Uint32Kind, pref.Fixed32Kind:
return pref.ValueOfUint32(0)
case pref.Uint64Kind, pref.Fixed64Kind:
return pref.ValueOfUint64(0)
case pref.FloatKind:
return pref.ValueOfFloat32(0)
case pref.DoubleKind:
return pref.ValueOfFloat64(0)
case pref.StringKind:
return pref.ValueOfString("")
case pref.BytesKind:
return pref.ValueOfBytes(nil)
case pref.EnumKind:
if evs := fd.Enum().Values(); evs.Len() > 0 {
return pref.ValueOfEnum(evs.Get(0).Number())
}
return pref.ValueOfEnum(0)
}
}
if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
// TODO: Avoid panic if we're running with the race detector
// and instead spawn a goroutine that periodically resets
// this value back to the original to induce a race.
panic(fmt.Sprintf("detected mutation on the default bytes for %v", fd.FullName()))
}
return dv.val
}

View File

@ -0,0 +1,471 @@
// 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 filedesc
import (
"sync"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/strs"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// fileRaw is a data struct used when initializing a file descriptor from
// a raw FileDescriptorProto.
type fileRaw struct {
builder Builder
allEnums []Enum
allMessages []Message
allExtensions []Extension
allServices []Service
}
func newRawFile(db Builder) *File {
fd := &File{fileRaw: fileRaw{builder: db}}
fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
fd.unmarshalSeed(db.RawDescriptor)
// Extended message targets are eagerly resolved since registration
// needs this information at program init time.
for i := range fd.allExtensions {
xd := &fd.allExtensions[i]
xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
}
fd.checkDecls()
return fd
}
// initDecls pre-allocates slices for the exact number of enums, messages
// (including map entries), extensions, and services declared in the proto file.
// This is done to avoid regrowing the slice, which would change the address
// for any previously seen declaration.
//
// The alloc methods "allocates" slices by pulling from the capacity.
func (fd *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
fd.allEnums = make([]Enum, 0, numEnums)
fd.allMessages = make([]Message, 0, numMessages)
fd.allExtensions = make([]Extension, 0, numExtensions)
fd.allServices = make([]Service, 0, numServices)
}
func (fd *File) allocEnums(n int) []Enum {
total := len(fd.allEnums)
es := fd.allEnums[total : total+n]
fd.allEnums = fd.allEnums[:total+n]
return es
}
func (fd *File) allocMessages(n int) []Message {
total := len(fd.allMessages)
ms := fd.allMessages[total : total+n]
fd.allMessages = fd.allMessages[:total+n]
return ms
}
func (fd *File) allocExtensions(n int) []Extension {
total := len(fd.allExtensions)
xs := fd.allExtensions[total : total+n]
fd.allExtensions = fd.allExtensions[:total+n]
return xs
}
func (fd *File) allocServices(n int) []Service {
total := len(fd.allServices)
xs := fd.allServices[total : total+n]
fd.allServices = fd.allServices[:total+n]
return xs
}
// checkDecls performs a sanity check that the expected number of expected
// declarations matches the number that were found in the descriptor proto.
func (fd *File) checkDecls() {
switch {
case len(fd.allEnums) != cap(fd.allEnums):
case len(fd.allMessages) != cap(fd.allMessages):
case len(fd.allExtensions) != cap(fd.allExtensions):
case len(fd.allServices) != cap(fd.allServices):
default:
return
}
panic("mismatching cardinality")
}
func (fd *File) unmarshalSeed(b []byte) {
sb := getBuilder()
defer putBuilder(sb)
var prevField pref.FieldNumber
var numEnums, numMessages, numExtensions, numServices int
var posEnums, posMessages, posExtensions, posServices int
b0 := b
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.FileDescriptorProto_Syntax_field_number:
switch string(v) {
case "proto2":
fd.L1.Syntax = pref.Proto2
case "proto3":
fd.L1.Syntax = pref.Proto3
default:
panic("invalid syntax")
}
case genid.FileDescriptorProto_Name_field_number:
fd.L1.Path = sb.MakeString(v)
case genid.FileDescriptorProto_Package_field_number:
fd.L1.Package = pref.FullName(sb.MakeString(v))
case genid.FileDescriptorProto_EnumType_field_number:
if prevField != genid.FileDescriptorProto_EnumType_field_number {
if numEnums > 0 {
panic("non-contiguous repeated field")
}
posEnums = len(b0) - len(b) - n - m
}
numEnums++
case genid.FileDescriptorProto_MessageType_field_number:
if prevField != genid.FileDescriptorProto_MessageType_field_number {
if numMessages > 0 {
panic("non-contiguous repeated field")
}
posMessages = len(b0) - len(b) - n - m
}
numMessages++
case genid.FileDescriptorProto_Extension_field_number:
if prevField != genid.FileDescriptorProto_Extension_field_number {
if numExtensions > 0 {
panic("non-contiguous repeated field")
}
posExtensions = len(b0) - len(b) - n - m
}
numExtensions++
case genid.FileDescriptorProto_Service_field_number:
if prevField != genid.FileDescriptorProto_Service_field_number {
if numServices > 0 {
panic("non-contiguous repeated field")
}
posServices = len(b0) - len(b) - n - m
}
numServices++
}
prevField = num
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
prevField = -1 // ignore known field numbers of unknown wire type
}
}
// If syntax is missing, it is assumed to be proto2.
if fd.L1.Syntax == 0 {
fd.L1.Syntax = pref.Proto2
}
// Must allocate all declarations before parsing each descriptor type
// to ensure we handled all descriptors in "flattened ordering".
if numEnums > 0 {
fd.L1.Enums.List = fd.allocEnums(numEnums)
}
if numMessages > 0 {
fd.L1.Messages.List = fd.allocMessages(numMessages)
}
if numExtensions > 0 {
fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
}
if numServices > 0 {
fd.L1.Services.List = fd.allocServices(numServices)
}
if numEnums > 0 {
b := b0[posEnums:]
for i := range fd.L1.Enums.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
fd.L1.Enums.List[i].unmarshalSeed(v, sb, fd, fd, i)
b = b[n+m:]
}
}
if numMessages > 0 {
b := b0[posMessages:]
for i := range fd.L1.Messages.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
fd.L1.Messages.List[i].unmarshalSeed(v, sb, fd, fd, i)
b = b[n+m:]
}
}
if numExtensions > 0 {
b := b0[posExtensions:]
for i := range fd.L1.Extensions.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
fd.L1.Extensions.List[i].unmarshalSeed(v, sb, fd, fd, i)
b = b[n+m:]
}
}
if numServices > 0 {
b := b0[posServices:]
for i := range fd.L1.Services.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
fd.L1.Services.List[i].unmarshalSeed(v, sb, fd, fd, i)
b = b[n+m:]
}
}
}
func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
ed.L0.ParentFile = pf
ed.L0.Parent = pd
ed.L0.Index = i
var numValues int
for b := b; len(b) > 0; {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.EnumDescriptorProto_Name_field_number:
ed.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.EnumDescriptorProto_Value_field_number:
numValues++
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
// Only construct enum value descriptors for top-level enums since
// they are needed for registration.
if pd != pf {
return
}
ed.L1.eagerValues = true
ed.L2 = new(EnumL2)
ed.L2.Values.List = make([]EnumValue, numValues)
for i := 0; len(b) > 0; {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.EnumDescriptorProto_Value_field_number:
ed.L2.Values.List[i].unmarshalFull(v, sb, pf, ed, i)
i++
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
md.L0.ParentFile = pf
md.L0.Parent = pd
md.L0.Index = i
var prevField pref.FieldNumber
var numEnums, numMessages, numExtensions int
var posEnums, posMessages, posExtensions int
b0 := b
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.DescriptorProto_Name_field_number:
md.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.DescriptorProto_EnumType_field_number:
if prevField != genid.DescriptorProto_EnumType_field_number {
if numEnums > 0 {
panic("non-contiguous repeated field")
}
posEnums = len(b0) - len(b) - n - m
}
numEnums++
case genid.DescriptorProto_NestedType_field_number:
if prevField != genid.DescriptorProto_NestedType_field_number {
if numMessages > 0 {
panic("non-contiguous repeated field")
}
posMessages = len(b0) - len(b) - n - m
}
numMessages++
case genid.DescriptorProto_Extension_field_number:
if prevField != genid.DescriptorProto_Extension_field_number {
if numExtensions > 0 {
panic("non-contiguous repeated field")
}
posExtensions = len(b0) - len(b) - n - m
}
numExtensions++
case genid.DescriptorProto_Options_field_number:
md.unmarshalSeedOptions(v)
}
prevField = num
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
prevField = -1 // ignore known field numbers of unknown wire type
}
}
// Must allocate all declarations before parsing each descriptor type
// to ensure we handled all descriptors in "flattened ordering".
if numEnums > 0 {
md.L1.Enums.List = pf.allocEnums(numEnums)
}
if numMessages > 0 {
md.L1.Messages.List = pf.allocMessages(numMessages)
}
if numExtensions > 0 {
md.L1.Extensions.List = pf.allocExtensions(numExtensions)
}
if numEnums > 0 {
b := b0[posEnums:]
for i := range md.L1.Enums.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
md.L1.Enums.List[i].unmarshalSeed(v, sb, pf, md, i)
b = b[n+m:]
}
}
if numMessages > 0 {
b := b0[posMessages:]
for i := range md.L1.Messages.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
md.L1.Messages.List[i].unmarshalSeed(v, sb, pf, md, i)
b = b[n+m:]
}
}
if numExtensions > 0 {
b := b0[posExtensions:]
for i := range md.L1.Extensions.List {
_, n := protowire.ConsumeVarint(b)
v, m := protowire.ConsumeBytes(b[n:])
md.L1.Extensions.List[i].unmarshalSeed(v, sb, pf, md, i)
b = b[n+m:]
}
}
}
func (md *Message) unmarshalSeedOptions(b []byte) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.MessageOptions_MapEntry_field_number:
md.L1.IsMapEntry = protowire.DecodeBool(v)
case genid.MessageOptions_MessageSetWireFormat_field_number:
md.L1.IsMessageSet = protowire.DecodeBool(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
xd.L0.ParentFile = pf
xd.L0.Parent = pd
xd.L0.Index = i
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FieldDescriptorProto_Number_field_number:
xd.L1.Number = pref.FieldNumber(v)
case genid.FieldDescriptorProto_Label_field_number:
xd.L1.Cardinality = pref.Cardinality(v)
case genid.FieldDescriptorProto_Type_field_number:
xd.L1.Kind = pref.Kind(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.FieldDescriptorProto_Name_field_number:
xd.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.FieldDescriptorProto_Extendee_field_number:
xd.L1.Extendee = PlaceholderMessage(makeFullName(sb, v))
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (sd *Service) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
sd.L0.ParentFile = pf
sd.L0.Parent = pd
sd.L0.Index = i
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.ServiceDescriptorProto_Name_field_number:
sd.L0.FullName = appendFullName(sb, pd.FullName(), v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
var nameBuilderPool = sync.Pool{
New: func() interface{} { return new(strs.Builder) },
}
func getBuilder() *strs.Builder {
return nameBuilderPool.Get().(*strs.Builder)
}
func putBuilder(b *strs.Builder) {
nameBuilderPool.Put(b)
}
// makeFullName converts b to a protoreflect.FullName,
// where b must start with a leading dot.
func makeFullName(sb *strs.Builder, b []byte) pref.FullName {
if len(b) == 0 || b[0] != '.' {
panic("name reference must be fully qualified")
}
return pref.FullName(sb.MakeString(b[1:]))
}
func appendFullName(sb *strs.Builder, prefix pref.FullName, suffix []byte) pref.FullName {
return sb.AppendFullName(prefix, pref.Name(strs.UnsafeString(suffix)))
}

View File

@ -0,0 +1,704 @@
// 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 filedesc
import (
"reflect"
"sync"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/descopts"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
func (fd *File) lazyRawInit() {
fd.unmarshalFull(fd.builder.RawDescriptor)
fd.resolveMessages()
fd.resolveExtensions()
fd.resolveServices()
}
func (file *File) resolveMessages() {
var depIdx int32
for i := range file.allMessages {
md := &file.allMessages[i]
// Resolve message field dependencies.
for j := range md.L2.Fields.List {
fd := &md.L2.Fields.List[j]
// Weak fields are resolved upon actual use.
if fd.L1.IsWeak {
continue
}
// Resolve message field dependency.
switch fd.L1.Kind {
case pref.EnumKind:
fd.L1.Enum = file.resolveEnumDependency(fd.L1.Enum, listFieldDeps, depIdx)
depIdx++
case pref.MessageKind, pref.GroupKind:
fd.L1.Message = file.resolveMessageDependency(fd.L1.Message, listFieldDeps, depIdx)
depIdx++
}
// Default is resolved here since it depends on Enum being resolved.
if v := fd.L1.Default.val; v.IsValid() {
fd.L1.Default = unmarshalDefault(v.Bytes(), fd.L1.Kind, file, fd.L1.Enum)
}
}
}
}
func (file *File) resolveExtensions() {
var depIdx int32
for i := range file.allExtensions {
xd := &file.allExtensions[i]
// Resolve extension field dependency.
switch xd.L1.Kind {
case pref.EnumKind:
xd.L2.Enum = file.resolveEnumDependency(xd.L2.Enum, listExtDeps, depIdx)
depIdx++
case pref.MessageKind, pref.GroupKind:
xd.L2.Message = file.resolveMessageDependency(xd.L2.Message, listExtDeps, depIdx)
depIdx++
}
// Default is resolved here since it depends on Enum being resolved.
if v := xd.L2.Default.val; v.IsValid() {
xd.L2.Default = unmarshalDefault(v.Bytes(), xd.L1.Kind, file, xd.L2.Enum)
}
}
}
func (file *File) resolveServices() {
var depIdx int32
for i := range file.allServices {
sd := &file.allServices[i]
// Resolve method dependencies.
for j := range sd.L2.Methods.List {
md := &sd.L2.Methods.List[j]
md.L1.Input = file.resolveMessageDependency(md.L1.Input, listMethInDeps, depIdx)
md.L1.Output = file.resolveMessageDependency(md.L1.Output, listMethOutDeps, depIdx)
depIdx++
}
}
}
func (file *File) resolveEnumDependency(ed pref.EnumDescriptor, i, j int32) pref.EnumDescriptor {
r := file.builder.FileRegistry
if r, ok := r.(resolverByIndex); ok {
if ed2 := r.FindEnumByIndex(i, j, file.allEnums, file.allMessages); ed2 != nil {
return ed2
}
}
for i := range file.allEnums {
if ed2 := &file.allEnums[i]; ed2.L0.FullName == ed.FullName() {
return ed2
}
}
if d, _ := r.FindDescriptorByName(ed.FullName()); d != nil {
return d.(pref.EnumDescriptor)
}
return ed
}
func (file *File) resolveMessageDependency(md pref.MessageDescriptor, i, j int32) pref.MessageDescriptor {
r := file.builder.FileRegistry
if r, ok := r.(resolverByIndex); ok {
if md2 := r.FindMessageByIndex(i, j, file.allEnums, file.allMessages); md2 != nil {
return md2
}
}
for i := range file.allMessages {
if md2 := &file.allMessages[i]; md2.L0.FullName == md.FullName() {
return md2
}
}
if d, _ := r.FindDescriptorByName(md.FullName()); d != nil {
return d.(pref.MessageDescriptor)
}
return md
}
func (fd *File) unmarshalFull(b []byte) {
sb := getBuilder()
defer putBuilder(sb)
var enumIdx, messageIdx, extensionIdx, serviceIdx int
var rawOptions []byte
fd.L2 = new(FileL2)
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FileDescriptorProto_PublicDependency_field_number:
fd.L2.Imports[v].IsPublic = true
case genid.FileDescriptorProto_WeakDependency_field_number:
fd.L2.Imports[v].IsWeak = true
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.FileDescriptorProto_Dependency_field_number:
path := sb.MakeString(v)
imp, _ := fd.builder.FileRegistry.FindFileByPath(path)
if imp == nil {
imp = PlaceholderFile(path)
}
fd.L2.Imports = append(fd.L2.Imports, pref.FileImport{FileDescriptor: imp})
case genid.FileDescriptorProto_EnumType_field_number:
fd.L1.Enums.List[enumIdx].unmarshalFull(v, sb)
enumIdx++
case genid.FileDescriptorProto_MessageType_field_number:
fd.L1.Messages.List[messageIdx].unmarshalFull(v, sb)
messageIdx++
case genid.FileDescriptorProto_Extension_field_number:
fd.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb)
extensionIdx++
case genid.FileDescriptorProto_Service_field_number:
fd.L1.Services.List[serviceIdx].unmarshalFull(v, sb)
serviceIdx++
case genid.FileDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
fd.L2.Options = fd.builder.optionsUnmarshaler(&descopts.File, rawOptions)
}
func (ed *Enum) unmarshalFull(b []byte, sb *strs.Builder) {
var rawValues [][]byte
var rawOptions []byte
if !ed.L1.eagerValues {
ed.L2 = new(EnumL2)
}
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.EnumDescriptorProto_Value_field_number:
rawValues = append(rawValues, v)
case genid.EnumDescriptorProto_ReservedName_field_number:
ed.L2.ReservedNames.List = append(ed.L2.ReservedNames.List, pref.Name(sb.MakeString(v)))
case genid.EnumDescriptorProto_ReservedRange_field_number:
ed.L2.ReservedRanges.List = append(ed.L2.ReservedRanges.List, unmarshalEnumReservedRange(v))
case genid.EnumDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if !ed.L1.eagerValues && len(rawValues) > 0 {
ed.L2.Values.List = make([]EnumValue, len(rawValues))
for i, b := range rawValues {
ed.L2.Values.List[i].unmarshalFull(b, sb, ed.L0.ParentFile, ed, i)
}
}
ed.L2.Options = ed.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Enum, rawOptions)
}
func unmarshalEnumReservedRange(b []byte) (r [2]pref.EnumNumber) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.EnumDescriptorProto_EnumReservedRange_Start_field_number:
r[0] = pref.EnumNumber(v)
case genid.EnumDescriptorProto_EnumReservedRange_End_field_number:
r[1] = pref.EnumNumber(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r
}
func (vd *EnumValue) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
vd.L0.ParentFile = pf
vd.L0.Parent = pd
vd.L0.Index = i
var rawOptions []byte
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.EnumValueDescriptorProto_Number_field_number:
vd.L1.Number = pref.EnumNumber(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.EnumValueDescriptorProto_Name_field_number:
// NOTE: Enum values are in the same scope as the enum parent.
vd.L0.FullName = appendFullName(sb, pd.Parent().FullName(), v)
case genid.EnumValueDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
vd.L1.Options = pf.builder.optionsUnmarshaler(&descopts.EnumValue, rawOptions)
}
func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) {
var rawFields, rawOneofs [][]byte
var enumIdx, messageIdx, extensionIdx int
var rawOptions []byte
md.L2 = new(MessageL2)
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.DescriptorProto_Field_field_number:
rawFields = append(rawFields, v)
case genid.DescriptorProto_OneofDecl_field_number:
rawOneofs = append(rawOneofs, v)
case genid.DescriptorProto_ReservedName_field_number:
md.L2.ReservedNames.List = append(md.L2.ReservedNames.List, pref.Name(sb.MakeString(v)))
case genid.DescriptorProto_ReservedRange_field_number:
md.L2.ReservedRanges.List = append(md.L2.ReservedRanges.List, unmarshalMessageReservedRange(v))
case genid.DescriptorProto_ExtensionRange_field_number:
r, rawOptions := unmarshalMessageExtensionRange(v)
opts := md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.ExtensionRange, rawOptions)
md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, r)
md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, opts)
case genid.DescriptorProto_EnumType_field_number:
md.L1.Enums.List[enumIdx].unmarshalFull(v, sb)
enumIdx++
case genid.DescriptorProto_NestedType_field_number:
md.L1.Messages.List[messageIdx].unmarshalFull(v, sb)
messageIdx++
case genid.DescriptorProto_Extension_field_number:
md.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb)
extensionIdx++
case genid.DescriptorProto_Options_field_number:
md.unmarshalOptions(v)
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if len(rawFields) > 0 || len(rawOneofs) > 0 {
md.L2.Fields.List = make([]Field, len(rawFields))
md.L2.Oneofs.List = make([]Oneof, len(rawOneofs))
for i, b := range rawFields {
fd := &md.L2.Fields.List[i]
fd.unmarshalFull(b, sb, md.L0.ParentFile, md, i)
if fd.L1.Cardinality == pref.Required {
md.L2.RequiredNumbers.List = append(md.L2.RequiredNumbers.List, fd.L1.Number)
}
}
for i, b := range rawOneofs {
od := &md.L2.Oneofs.List[i]
od.unmarshalFull(b, sb, md.L0.ParentFile, md, i)
}
}
md.L2.Options = md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Message, rawOptions)
}
func (md *Message) unmarshalOptions(b []byte) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.MessageOptions_MapEntry_field_number:
md.L1.IsMapEntry = protowire.DecodeBool(v)
case genid.MessageOptions_MessageSetWireFormat_field_number:
md.L1.IsMessageSet = protowire.DecodeBool(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func unmarshalMessageReservedRange(b []byte) (r [2]pref.FieldNumber) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.DescriptorProto_ReservedRange_Start_field_number:
r[0] = pref.FieldNumber(v)
case genid.DescriptorProto_ReservedRange_End_field_number:
r[1] = pref.FieldNumber(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r
}
func unmarshalMessageExtensionRange(b []byte) (r [2]pref.FieldNumber, rawOptions []byte) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.DescriptorProto_ExtensionRange_Start_field_number:
r[0] = pref.FieldNumber(v)
case genid.DescriptorProto_ExtensionRange_End_field_number:
r[1] = pref.FieldNumber(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.DescriptorProto_ExtensionRange_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
return r, rawOptions
}
func (fd *Field) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
fd.L0.ParentFile = pf
fd.L0.Parent = pd
fd.L0.Index = i
var rawTypeName []byte
var rawOptions []byte
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FieldDescriptorProto_Number_field_number:
fd.L1.Number = pref.FieldNumber(v)
case genid.FieldDescriptorProto_Label_field_number:
fd.L1.Cardinality = pref.Cardinality(v)
case genid.FieldDescriptorProto_Type_field_number:
fd.L1.Kind = pref.Kind(v)
case genid.FieldDescriptorProto_OneofIndex_field_number:
// In Message.unmarshalFull, we allocate slices for both
// the field and oneof descriptors before unmarshaling either
// of them. This ensures pointers to slice elements are stable.
od := &pd.(*Message).L2.Oneofs.List[v]
od.L1.Fields.List = append(od.L1.Fields.List, fd)
if fd.L1.ContainingOneof != nil {
panic("oneof type already set")
}
fd.L1.ContainingOneof = od
case genid.FieldDescriptorProto_Proto3Optional_field_number:
fd.L1.IsProto3Optional = protowire.DecodeBool(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
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))
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:
rawTypeName = v
case genid.FieldDescriptorProto_Options_field_number:
fd.unmarshalOptions(v)
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if rawTypeName != nil {
name := makeFullName(sb, rawTypeName)
switch fd.L1.Kind {
case pref.EnumKind:
fd.L1.Enum = PlaceholderEnum(name)
case pref.MessageKind, pref.GroupKind:
fd.L1.Message = PlaceholderMessage(name)
}
}
fd.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Field, rawOptions)
}
func (fd *Field) unmarshalOptions(b []byte) {
const FieldOptions_EnforceUTF8 = 13
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FieldOptions_Packed_field_number:
fd.L1.HasPacked = true
fd.L1.IsPacked = protowire.DecodeBool(v)
case genid.FieldOptions_Weak_field_number:
fd.L1.IsWeak = protowire.DecodeBool(v)
case FieldOptions_EnforceUTF8:
fd.L1.HasEnforceUTF8 = true
fd.L1.EnforceUTF8 = protowire.DecodeBool(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (od *Oneof) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
od.L0.ParentFile = pf
od.L0.Parent = pd
od.L0.Index = i
var rawOptions []byte
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.OneofDescriptorProto_Name_field_number:
od.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.OneofDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
od.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Oneof, rawOptions)
}
func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) {
var rawTypeName []byte
var rawOptions []byte
xd.L2 = new(ExtensionL2)
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FieldDescriptorProto_Proto3Optional_field_number:
xd.L2.IsProto3Optional = protowire.DecodeBool(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.FieldDescriptorProto_JsonName_field_number:
xd.L2.JSONName.Init(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:
rawTypeName = v
case genid.FieldDescriptorProto_Options_field_number:
xd.unmarshalOptions(v)
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if rawTypeName != nil {
name := makeFullName(sb, rawTypeName)
switch xd.L1.Kind {
case pref.EnumKind:
xd.L2.Enum = PlaceholderEnum(name)
case pref.MessageKind, pref.GroupKind:
xd.L2.Message = PlaceholderMessage(name)
}
}
xd.L2.Options = xd.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Field, rawOptions)
}
func (xd *Extension) unmarshalOptions(b []byte) {
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.FieldOptions_Packed_field_number:
xd.L2.IsPacked = protowire.DecodeBool(v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
}
func (sd *Service) unmarshalFull(b []byte, sb *strs.Builder) {
var rawMethods [][]byte
var rawOptions []byte
sd.L2 = new(ServiceL2)
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.ServiceDescriptorProto_Method_field_number:
rawMethods = append(rawMethods, v)
case genid.ServiceDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
if len(rawMethods) > 0 {
sd.L2.Methods.List = make([]Method, len(rawMethods))
for i, b := range rawMethods {
sd.L2.Methods.List[i].unmarshalFull(b, sb, sd.L0.ParentFile, sd, i)
}
}
sd.L2.Options = sd.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Service, rawOptions)
}
func (md *Method) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
md.L0.ParentFile = pf
md.L0.Parent = pd
md.L0.Index = i
var rawOptions []byte
for len(b) > 0 {
num, typ, n := protowire.ConsumeTag(b)
b = b[n:]
switch typ {
case protowire.VarintType:
v, m := protowire.ConsumeVarint(b)
b = b[m:]
switch num {
case genid.MethodDescriptorProto_ClientStreaming_field_number:
md.L1.IsStreamingClient = protowire.DecodeBool(v)
case genid.MethodDescriptorProto_ServerStreaming_field_number:
md.L1.IsStreamingServer = protowire.DecodeBool(v)
}
case protowire.BytesType:
v, m := protowire.ConsumeBytes(b)
b = b[m:]
switch num {
case genid.MethodDescriptorProto_Name_field_number:
md.L0.FullName = appendFullName(sb, pd.FullName(), v)
case genid.MethodDescriptorProto_InputType_field_number:
md.L1.Input = PlaceholderMessage(makeFullName(sb, v))
case genid.MethodDescriptorProto_OutputType_field_number:
md.L1.Output = PlaceholderMessage(makeFullName(sb, v))
case genid.MethodDescriptorProto_Options_field_number:
rawOptions = appendOptions(rawOptions, v)
}
default:
m := protowire.ConsumeFieldValue(num, typ, b)
b = b[m:]
}
}
md.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Method, rawOptions)
}
// appendOptions appends src to dst, where the returned slice is never nil.
// This is necessary to distinguish between empty and unpopulated options.
func appendOptions(dst, src []byte) []byte {
if dst == nil {
dst = []byte{}
}
return append(dst, src...)
}
// optionsUnmarshaler constructs a lazy unmarshal function for an options message.
//
// The type of message to unmarshal to is passed as a pointer since the
// vars in descopts may not yet be populated at the time this function is called.
func (db *Builder) optionsUnmarshaler(p *pref.ProtoMessage, b []byte) func() pref.ProtoMessage {
if b == nil {
return nil
}
var opts pref.ProtoMessage
var once sync.Once
return func() pref.ProtoMessage {
once.Do(func() {
if *p == nil {
panic("Descriptor.Options called without importing the descriptor package")
}
opts = reflect.New(reflect.TypeOf(*p).Elem()).Interface().(pref.ProtoMessage)
if err := (proto.UnmarshalOptions{
AllowPartial: true,
Resolver: db.TypeResolver,
}).Unmarshal(b, opts); err != nil {
panic(err)
}
})
return opts
}
}

View File

@ -0,0 +1,282 @@
// 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 filedesc
import (
"fmt"
"sort"
"sync"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/descfmt"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/reflect/protoreflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type FileImports []pref.FileImport
func (p *FileImports) Len() int { return len(*p) }
func (p *FileImports) Get(i int) pref.FileImport { return (*p)[i] }
func (p *FileImports) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *FileImports) ProtoInternal(pragma.DoNotImplement) {}
type Names struct {
List []pref.Name
once sync.Once
has map[pref.Name]int // protected by once
}
func (p *Names) Len() int { return len(p.List) }
func (p *Names) Get(i int) pref.Name { return p.List[i] }
func (p *Names) Has(s pref.Name) bool { return p.lazyInit().has[s] > 0 }
func (p *Names) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *Names) ProtoInternal(pragma.DoNotImplement) {}
func (p *Names) lazyInit() *Names {
p.once.Do(func() {
if len(p.List) > 0 {
p.has = make(map[pref.Name]int, len(p.List))
for _, s := range p.List {
p.has[s] = p.has[s] + 1
}
}
})
return p
}
// CheckValid reports any errors with the set of names with an error message
// that completes the sentence: "ranges is invalid because it has ..."
func (p *Names) CheckValid() error {
for s, n := range p.lazyInit().has {
switch {
case n > 1:
return errors.New("duplicate name: %q", s)
case false && !s.IsValid():
// NOTE: The C++ implementation does not validate the identifier.
// See https://github.com/protocolbuffers/protobuf/issues/6335.
return errors.New("invalid name: %q", s)
}
}
return nil
}
type EnumRanges struct {
List [][2]pref.EnumNumber // start inclusive; end inclusive
once sync.Once
sorted [][2]pref.EnumNumber // protected by once
}
func (p *EnumRanges) Len() int { return len(p.List) }
func (p *EnumRanges) Get(i int) [2]pref.EnumNumber { return p.List[i] }
func (p *EnumRanges) Has(n pref.EnumNumber) bool {
for ls := p.lazyInit().sorted; len(ls) > 0; {
i := len(ls) / 2
switch r := enumRange(ls[i]); {
case n < r.Start():
ls = ls[:i] // search lower
case n > r.End():
ls = ls[i+1:] // search upper
default:
return true
}
}
return false
}
func (p *EnumRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *EnumRanges) ProtoInternal(pragma.DoNotImplement) {}
func (p *EnumRanges) lazyInit() *EnumRanges {
p.once.Do(func() {
p.sorted = append(p.sorted, p.List...)
sort.Slice(p.sorted, func(i, j int) bool {
return p.sorted[i][0] < p.sorted[j][0]
})
})
return p
}
// CheckValid reports any errors with the set of names with an error message
// that completes the sentence: "ranges is invalid because it has ..."
func (p *EnumRanges) CheckValid() error {
var rp enumRange
for i, r := range p.lazyInit().sorted {
r := enumRange(r)
switch {
case !(r.Start() <= r.End()):
return errors.New("invalid range: %v", r)
case !(rp.End() < r.Start()) && i > 0:
return errors.New("overlapping ranges: %v with %v", rp, r)
}
rp = r
}
return nil
}
type enumRange [2]protoreflect.EnumNumber
func (r enumRange) Start() protoreflect.EnumNumber { return r[0] } // inclusive
func (r enumRange) End() protoreflect.EnumNumber { return r[1] } // inclusive
func (r enumRange) String() string {
if r.Start() == r.End() {
return fmt.Sprintf("%d", r.Start())
}
return fmt.Sprintf("%d to %d", r.Start(), r.End())
}
type FieldRanges struct {
List [][2]pref.FieldNumber // start inclusive; end exclusive
once sync.Once
sorted [][2]pref.FieldNumber // protected by once
}
func (p *FieldRanges) Len() int { return len(p.List) }
func (p *FieldRanges) Get(i int) [2]pref.FieldNumber { return p.List[i] }
func (p *FieldRanges) Has(n pref.FieldNumber) bool {
for ls := p.lazyInit().sorted; len(ls) > 0; {
i := len(ls) / 2
switch r := fieldRange(ls[i]); {
case n < r.Start():
ls = ls[:i] // search lower
case n > r.End():
ls = ls[i+1:] // search upper
default:
return true
}
}
return false
}
func (p *FieldRanges) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *FieldRanges) ProtoInternal(pragma.DoNotImplement) {}
func (p *FieldRanges) lazyInit() *FieldRanges {
p.once.Do(func() {
p.sorted = append(p.sorted, p.List...)
sort.Slice(p.sorted, func(i, j int) bool {
return p.sorted[i][0] < p.sorted[j][0]
})
})
return p
}
// CheckValid reports any errors with the set of ranges with an error message
// that completes the sentence: "ranges is invalid because it has ..."
func (p *FieldRanges) CheckValid(isMessageSet bool) error {
var rp fieldRange
for i, r := range p.lazyInit().sorted {
r := fieldRange(r)
switch {
case !isValidFieldNumber(r.Start(), isMessageSet):
return errors.New("invalid field number: %d", r.Start())
case !isValidFieldNumber(r.End(), isMessageSet):
return errors.New("invalid field number: %d", r.End())
case !(r.Start() <= r.End()):
return errors.New("invalid range: %v", r)
case !(rp.End() < r.Start()) && i > 0:
return errors.New("overlapping ranges: %v with %v", rp, r)
}
rp = r
}
return nil
}
// isValidFieldNumber reports whether the field number is valid.
// Unlike the FieldNumber.IsValid method, it allows ranges that cover the
// reserved number range.
func isValidFieldNumber(n protoreflect.FieldNumber, isMessageSet bool) bool {
return protowire.MinValidNumber <= n && (n <= protowire.MaxValidNumber || isMessageSet)
}
// CheckOverlap reports an error if p and q overlap.
func (p *FieldRanges) CheckOverlap(q *FieldRanges) error {
rps := p.lazyInit().sorted
rqs := q.lazyInit().sorted
for pi, qi := 0, 0; pi < len(rps) && qi < len(rqs); {
rp := fieldRange(rps[pi])
rq := fieldRange(rqs[qi])
if !(rp.End() < rq.Start() || rq.End() < rp.Start()) {
return errors.New("overlapping ranges: %v with %v", rp, rq)
}
if rp.Start() < rq.Start() {
pi++
} else {
qi++
}
}
return nil
}
type fieldRange [2]protoreflect.FieldNumber
func (r fieldRange) Start() protoreflect.FieldNumber { return r[0] } // inclusive
func (r fieldRange) End() protoreflect.FieldNumber { return r[1] - 1 } // inclusive
func (r fieldRange) String() string {
if r.Start() == r.End() {
return fmt.Sprintf("%d", r.Start())
}
return fmt.Sprintf("%d to %d", r.Start(), r.End())
}
type FieldNumbers struct {
List []pref.FieldNumber
once sync.Once
has map[pref.FieldNumber]struct{} // protected by once
}
func (p *FieldNumbers) Len() int { return len(p.List) }
func (p *FieldNumbers) Get(i int) pref.FieldNumber { return p.List[i] }
func (p *FieldNumbers) Has(n pref.FieldNumber) bool {
p.once.Do(func() {
if len(p.List) > 0 {
p.has = make(map[pref.FieldNumber]struct{}, len(p.List))
for _, n := range p.List {
p.has[n] = struct{}{}
}
}
})
_, ok := p.has[n]
return ok
}
func (p *FieldNumbers) Format(s fmt.State, r rune) { descfmt.FormatList(s, r, p) }
func (p *FieldNumbers) ProtoInternal(pragma.DoNotImplement) {}
type OneofFields struct {
List []pref.FieldDescriptor
once sync.Once
byName map[pref.Name]pref.FieldDescriptor // protected by once
byJSON map[string]pref.FieldDescriptor // protected by once
byNum map[pref.FieldNumber]pref.FieldDescriptor // protected by once
}
func (p *OneofFields) Len() int { return len(p.List) }
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) 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) {}
func (p *OneofFields) lazyInit() *OneofFields {
p.once.Do(func() {
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.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.byNum[f.Number()] = f
}
}
})
return p
}
type SourceLocations struct {
List []pref.SourceLocation
}
func (p *SourceLocations) Len() int { return len(p.List) }
func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.List[i] }
func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}

View File

@ -0,0 +1,345 @@
// 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.
// Code generated by generate-types. DO NOT EDIT.
package filedesc
import (
"fmt"
"sync"
"google.golang.org/protobuf/internal/descfmt"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/reflect/protoreflect"
)
type Enums struct {
List []Enum
once sync.Once
byName map[protoreflect.Name]*Enum // protected by once
}
func (p *Enums) Len() int {
return len(p.List)
}
func (p *Enums) Get(i int) protoreflect.EnumDescriptor {
return &p.List[i]
}
func (p *Enums) ByName(s protoreflect.Name) protoreflect.EnumDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Enums) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Enums) ProtoInternal(pragma.DoNotImplement) {}
func (p *Enums) lazyInit() *Enums {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Enum, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}
type EnumValues struct {
List []EnumValue
once sync.Once
byName map[protoreflect.Name]*EnumValue // protected by once
byNum map[protoreflect.EnumNumber]*EnumValue // protected by once
}
func (p *EnumValues) Len() int {
return len(p.List)
}
func (p *EnumValues) Get(i int) protoreflect.EnumValueDescriptor {
return &p.List[i]
}
func (p *EnumValues) ByName(s protoreflect.Name) protoreflect.EnumValueDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *EnumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
if d := p.lazyInit().byNum[n]; d != nil {
return d
}
return nil
}
func (p *EnumValues) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *EnumValues) ProtoInternal(pragma.DoNotImplement) {}
func (p *EnumValues) lazyInit() *EnumValues {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*EnumValue, len(p.List))
p.byNum = make(map[protoreflect.EnumNumber]*EnumValue, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
if _, ok := p.byNum[d.Number()]; !ok {
p.byNum[d.Number()] = d
}
}
}
})
return p
}
type Messages struct {
List []Message
once sync.Once
byName map[protoreflect.Name]*Message // protected by once
}
func (p *Messages) Len() int {
return len(p.List)
}
func (p *Messages) Get(i int) protoreflect.MessageDescriptor {
return &p.List[i]
}
func (p *Messages) ByName(s protoreflect.Name) protoreflect.MessageDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Messages) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Messages) ProtoInternal(pragma.DoNotImplement) {}
func (p *Messages) lazyInit() *Messages {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Message, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}
type Fields struct {
List []Field
once sync.Once
byName map[protoreflect.Name]*Field // protected by once
byJSON map[string]*Field // protected by once
byNum map[protoreflect.FieldNumber]*Field // protected by once
}
func (p *Fields) Len() int {
return len(p.List)
}
func (p *Fields) Get(i int) protoreflect.FieldDescriptor {
return &p.List[i]
}
func (p *Fields) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Fields) ByJSONName(s string) protoreflect.FieldDescriptor {
if d := p.lazyInit().byJSON[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
}
return nil
}
func (p *Fields) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Fields) ProtoInternal(pragma.DoNotImplement) {}
func (p *Fields) lazyInit() *Fields {
p.once.Do(func() {
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.byNum = make(map[protoreflect.FieldNumber]*Field, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
if _, ok := p.byJSON[d.JSONName()]; !ok {
p.byJSON[d.JSONName()] = d
}
if _, ok := p.byNum[d.Number()]; !ok {
p.byNum[d.Number()] = d
}
}
}
})
return p
}
type Oneofs struct {
List []Oneof
once sync.Once
byName map[protoreflect.Name]*Oneof // protected by once
}
func (p *Oneofs) Len() int {
return len(p.List)
}
func (p *Oneofs) Get(i int) protoreflect.OneofDescriptor {
return &p.List[i]
}
func (p *Oneofs) ByName(s protoreflect.Name) protoreflect.OneofDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Oneofs) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Oneofs) ProtoInternal(pragma.DoNotImplement) {}
func (p *Oneofs) lazyInit() *Oneofs {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Oneof, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}
type Extensions struct {
List []Extension
once sync.Once
byName map[protoreflect.Name]*Extension // protected by once
}
func (p *Extensions) Len() int {
return len(p.List)
}
func (p *Extensions) Get(i int) protoreflect.ExtensionDescriptor {
return &p.List[i]
}
func (p *Extensions) ByName(s protoreflect.Name) protoreflect.ExtensionDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Extensions) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Extensions) ProtoInternal(pragma.DoNotImplement) {}
func (p *Extensions) lazyInit() *Extensions {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Extension, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}
type Services struct {
List []Service
once sync.Once
byName map[protoreflect.Name]*Service // protected by once
}
func (p *Services) Len() int {
return len(p.List)
}
func (p *Services) Get(i int) protoreflect.ServiceDescriptor {
return &p.List[i]
}
func (p *Services) ByName(s protoreflect.Name) protoreflect.ServiceDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Services) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Services) ProtoInternal(pragma.DoNotImplement) {}
func (p *Services) lazyInit() *Services {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Service, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}
type Methods struct {
List []Method
once sync.Once
byName map[protoreflect.Name]*Method // protected by once
}
func (p *Methods) Len() int {
return len(p.List)
}
func (p *Methods) Get(i int) protoreflect.MethodDescriptor {
return &p.List[i]
}
func (p *Methods) ByName(s protoreflect.Name) protoreflect.MethodDescriptor {
if d := p.lazyInit().byName[s]; d != nil {
return d
}
return nil
}
func (p *Methods) Format(s fmt.State, r rune) {
descfmt.FormatList(s, r, p)
}
func (p *Methods) ProtoInternal(pragma.DoNotImplement) {}
func (p *Methods) lazyInit() *Methods {
p.once.Do(func() {
if len(p.List) > 0 {
p.byName = make(map[protoreflect.Name]*Method, len(p.List))
for i := range p.List {
d := &p.List[i]
if _, ok := p.byName[d.Name()]; !ok {
p.byName[d.Name()] = d
}
}
}
})
return p
}

View File

@ -0,0 +1,107 @@
// 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 filedesc
import (
"google.golang.org/protobuf/internal/descopts"
"google.golang.org/protobuf/internal/pragma"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
var (
emptyNames = new(Names)
emptyEnumRanges = new(EnumRanges)
emptyFieldRanges = new(FieldRanges)
emptyFieldNumbers = new(FieldNumbers)
emptySourceLocations = new(SourceLocations)
emptyFiles = new(FileImports)
emptyMessages = new(Messages)
emptyFields = new(Fields)
emptyOneofs = new(Oneofs)
emptyEnums = new(Enums)
emptyEnumValues = new(EnumValues)
emptyExtensions = new(Extensions)
emptyServices = new(Services)
)
// PlaceholderFile is a placeholder, representing only the file path.
type PlaceholderFile string
func (f PlaceholderFile) ParentFile() pref.FileDescriptor { return f }
func (f PlaceholderFile) Parent() pref.Descriptor { return nil }
func (f PlaceholderFile) Index() int { return 0 }
func (f PlaceholderFile) Syntax() pref.Syntax { return 0 }
func (f PlaceholderFile) Name() pref.Name { return "" }
func (f PlaceholderFile) FullName() pref.FullName { return "" }
func (f PlaceholderFile) IsPlaceholder() bool { return true }
func (f PlaceholderFile) Options() pref.ProtoMessage { return descopts.File }
func (f PlaceholderFile) Path() string { return string(f) }
func (f PlaceholderFile) Package() pref.FullName { return "" }
func (f PlaceholderFile) Imports() pref.FileImports { return emptyFiles }
func (f PlaceholderFile) Messages() pref.MessageDescriptors { return emptyMessages }
func (f PlaceholderFile) Enums() pref.EnumDescriptors { return emptyEnums }
func (f PlaceholderFile) Extensions() pref.ExtensionDescriptors { return emptyExtensions }
func (f PlaceholderFile) Services() pref.ServiceDescriptors { return emptyServices }
func (f PlaceholderFile) SourceLocations() pref.SourceLocations { return emptySourceLocations }
func (f PlaceholderFile) ProtoType(pref.FileDescriptor) { return }
func (f PlaceholderFile) ProtoInternal(pragma.DoNotImplement) { return }
// PlaceholderEnum is a placeholder, representing only the full name.
type PlaceholderEnum pref.FullName
func (e PlaceholderEnum) ParentFile() pref.FileDescriptor { return nil }
func (e PlaceholderEnum) Parent() pref.Descriptor { return nil }
func (e PlaceholderEnum) Index() int { return 0 }
func (e PlaceholderEnum) Syntax() pref.Syntax { return 0 }
func (e PlaceholderEnum) Name() pref.Name { return pref.FullName(e).Name() }
func (e PlaceholderEnum) FullName() pref.FullName { return pref.FullName(e) }
func (e PlaceholderEnum) IsPlaceholder() bool { return true }
func (e PlaceholderEnum) Options() pref.ProtoMessage { return descopts.Enum }
func (e PlaceholderEnum) Values() pref.EnumValueDescriptors { return emptyEnumValues }
func (e PlaceholderEnum) ReservedNames() pref.Names { return emptyNames }
func (e PlaceholderEnum) ReservedRanges() pref.EnumRanges { return emptyEnumRanges }
func (e PlaceholderEnum) ProtoType(pref.EnumDescriptor) { return }
func (e PlaceholderEnum) ProtoInternal(pragma.DoNotImplement) { return }
// PlaceholderEnumValue is a placeholder, representing only the full name.
type PlaceholderEnumValue pref.FullName
func (e PlaceholderEnumValue) ParentFile() pref.FileDescriptor { return nil }
func (e PlaceholderEnumValue) Parent() pref.Descriptor { return nil }
func (e PlaceholderEnumValue) Index() int { return 0 }
func (e PlaceholderEnumValue) Syntax() pref.Syntax { return 0 }
func (e PlaceholderEnumValue) Name() pref.Name { return pref.FullName(e).Name() }
func (e PlaceholderEnumValue) FullName() pref.FullName { return pref.FullName(e) }
func (e PlaceholderEnumValue) IsPlaceholder() bool { return true }
func (e PlaceholderEnumValue) Options() pref.ProtoMessage { return descopts.EnumValue }
func (e PlaceholderEnumValue) Number() pref.EnumNumber { return 0 }
func (e PlaceholderEnumValue) ProtoType(pref.EnumValueDescriptor) { return }
func (e PlaceholderEnumValue) ProtoInternal(pragma.DoNotImplement) { return }
// PlaceholderMessage is a placeholder, representing only the full name.
type PlaceholderMessage pref.FullName
func (m PlaceholderMessage) ParentFile() pref.FileDescriptor { return nil }
func (m PlaceholderMessage) Parent() pref.Descriptor { return nil }
func (m PlaceholderMessage) Index() int { return 0 }
func (m PlaceholderMessage) Syntax() pref.Syntax { return 0 }
func (m PlaceholderMessage) Name() pref.Name { return pref.FullName(m).Name() }
func (m PlaceholderMessage) FullName() pref.FullName { return pref.FullName(m) }
func (m PlaceholderMessage) IsPlaceholder() bool { return true }
func (m PlaceholderMessage) Options() pref.ProtoMessage { return descopts.Message }
func (m PlaceholderMessage) IsMapEntry() bool { return false }
func (m PlaceholderMessage) Fields() pref.FieldDescriptors { return emptyFields }
func (m PlaceholderMessage) Oneofs() pref.OneofDescriptors { return emptyOneofs }
func (m PlaceholderMessage) ReservedNames() pref.Names { return emptyNames }
func (m PlaceholderMessage) ReservedRanges() pref.FieldRanges { return emptyFieldRanges }
func (m PlaceholderMessage) RequiredNumbers() pref.FieldNumbers { return emptyFieldNumbers }
func (m PlaceholderMessage) ExtensionRanges() pref.FieldRanges { return emptyFieldRanges }
func (m PlaceholderMessage) ExtensionRangeOptions(int) pref.ProtoMessage { panic("index out of range") }
func (m PlaceholderMessage) Messages() pref.MessageDescriptors { return emptyMessages }
func (m PlaceholderMessage) Enums() pref.EnumDescriptors { return emptyEnums }
func (m PlaceholderMessage) Extensions() pref.ExtensionDescriptors { return emptyExtensions }
func (m PlaceholderMessage) ProtoType(pref.MessageDescriptor) { return }
func (m PlaceholderMessage) ProtoInternal(pragma.DoNotImplement) { return }

View File

@ -0,0 +1,297 @@
// 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 filetype provides functionality for wrapping descriptors
// with Go type information.
package filetype
import (
"reflect"
"google.golang.org/protobuf/internal/descopts"
fdesc "google.golang.org/protobuf/internal/filedesc"
pimpl "google.golang.org/protobuf/internal/impl"
pref "google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
)
// Builder constructs type descriptors from a raw file descriptor
// and associated Go types for each enum and message declaration.
//
//
// Flattened Ordering
//
// The protobuf type system represents declarations as a tree. Certain nodes in
// the tree require us to either associate it with a concrete Go type or to
// resolve a dependency, which is information that must be provided separately
// since it cannot be derived from the file descriptor alone.
//
// However, representing a tree as Go literals is difficult to simply do in a
// space and time efficient way. Thus, we store them as a flattened list of
// objects where the serialization order from the tree-based form is important.
//
// The "flattened ordering" is defined as a tree traversal of all enum, message,
// extension, and service declarations using the following algorithm:
//
// def VisitFileDecls(fd):
// for e in fd.Enums: yield e
// for m in fd.Messages: yield m
// for x in fd.Extensions: yield x
// for s in fd.Services: yield s
// for m in fd.Messages: yield from VisitMessageDecls(m)
//
// def VisitMessageDecls(md):
// for e in md.Enums: yield e
// for m in md.Messages: yield m
// for x in md.Extensions: yield x
// for m in md.Messages: yield from VisitMessageDecls(m)
//
// The traversal starts at the root file descriptor and yields each direct
// declaration within each node before traversing into sub-declarations
// that children themselves may have.
type Builder struct {
// File is the underlying file descriptor builder.
File fdesc.Builder
// GoTypes is a unique set of the Go types for all declarations and
// dependencies. Each type is represented as a zero value of the Go type.
//
// Declarations are Go types generated for enums and messages directly
// declared (not publicly imported) in the proto source file.
// Messages for map entries are accounted for, but represented by nil.
// Enum declarations in "flattened ordering" come first, followed by
// message declarations in "flattened ordering".
//
// Dependencies are Go types for enums or messages referenced by
// message fields (excluding weak fields), for parent extended messages of
// extension fields, for enums or messages referenced by extension fields,
// and for input and output messages referenced by service methods.
// Dependencies must come after declarations, but the ordering of
// dependencies themselves is unspecified.
GoTypes []interface{}
// DependencyIndexes is an ordered list of indexes into GoTypes for the
// dependencies of messages, extensions, or services.
//
// There are 5 sub-lists in "flattened ordering" concatenated back-to-back:
// 0. Message field dependencies: list of the enum or message type
// referred to by every message field.
// 1. Extension field targets: list of the extended parent message of
// every extension.
// 2. Extension field dependencies: list of the enum or message type
// referred to by every extension field.
// 3. Service method inputs: list of the input message type
// referred to by every service method.
// 4. Service method outputs: list of the output message type
// referred to by every service method.
//
// The offset into DependencyIndexes for the start of each sub-list
// is appended to the end in reverse order.
DependencyIndexes []int32
// EnumInfos is a list of enum infos in "flattened ordering".
EnumInfos []pimpl.EnumInfo
// MessageInfos is a list of message infos in "flattened ordering".
// If provided, the GoType and PBType for each element is populated.
//
// Requirement: len(MessageInfos) == len(Build.Messages)
MessageInfos []pimpl.MessageInfo
// ExtensionInfos is a list of extension infos in "flattened ordering".
// Each element is initialized and registered with the protoregistry package.
//
// Requirement: len(LegacyExtensions) == len(Build.Extensions)
ExtensionInfos []pimpl.ExtensionInfo
// TypeRegistry is the registry to register each type descriptor.
// If nil, it uses protoregistry.GlobalTypes.
TypeRegistry interface {
RegisterMessage(pref.MessageType) error
RegisterEnum(pref.EnumType) error
RegisterExtension(pref.ExtensionType) error
}
}
// Out is the output of the builder.
type Out struct {
File pref.FileDescriptor
}
func (tb Builder) Build() (out Out) {
// Replace the resolver with one that resolves dependencies by index,
// which is faster and more reliable than relying on the global registry.
if tb.File.FileRegistry == nil {
tb.File.FileRegistry = preg.GlobalFiles
}
tb.File.FileRegistry = &resolverByIndex{
goTypes: tb.GoTypes,
depIdxs: tb.DependencyIndexes,
fileRegistry: tb.File.FileRegistry,
}
// Initialize registry if unpopulated.
if tb.TypeRegistry == nil {
tb.TypeRegistry = preg.GlobalTypes
}
fbOut := tb.File.Build()
out.File = fbOut.File
// Process enums.
enumGoTypes := tb.GoTypes[:len(fbOut.Enums)]
if len(tb.EnumInfos) != len(fbOut.Enums) {
panic("mismatching enum lengths")
}
if len(fbOut.Enums) > 0 {
for i := range fbOut.Enums {
tb.EnumInfos[i] = pimpl.EnumInfo{
GoReflectType: reflect.TypeOf(enumGoTypes[i]),
Desc: &fbOut.Enums[i],
}
// Register enum types.
if err := tb.TypeRegistry.RegisterEnum(&tb.EnumInfos[i]); err != nil {
panic(err)
}
}
}
// Process messages.
messageGoTypes := tb.GoTypes[len(fbOut.Enums):][:len(fbOut.Messages)]
if len(tb.MessageInfos) != len(fbOut.Messages) {
panic("mismatching message lengths")
}
if len(fbOut.Messages) > 0 {
for i := range fbOut.Messages {
if messageGoTypes[i] == nil {
continue // skip map entry
}
tb.MessageInfos[i].GoReflectType = reflect.TypeOf(messageGoTypes[i])
tb.MessageInfos[i].Desc = &fbOut.Messages[i]
// Register message types.
if err := tb.TypeRegistry.RegisterMessage(&tb.MessageInfos[i]); err != nil {
panic(err)
}
}
// As a special-case for descriptor.proto,
// locally register concrete message type for the options.
if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" {
for i := range fbOut.Messages {
switch fbOut.Messages[i].Name() {
case "FileOptions":
descopts.File = messageGoTypes[i].(pref.ProtoMessage)
case "EnumOptions":
descopts.Enum = messageGoTypes[i].(pref.ProtoMessage)
case "EnumValueOptions":
descopts.EnumValue = messageGoTypes[i].(pref.ProtoMessage)
case "MessageOptions":
descopts.Message = messageGoTypes[i].(pref.ProtoMessage)
case "FieldOptions":
descopts.Field = messageGoTypes[i].(pref.ProtoMessage)
case "OneofOptions":
descopts.Oneof = messageGoTypes[i].(pref.ProtoMessage)
case "ExtensionRangeOptions":
descopts.ExtensionRange = messageGoTypes[i].(pref.ProtoMessage)
case "ServiceOptions":
descopts.Service = messageGoTypes[i].(pref.ProtoMessage)
case "MethodOptions":
descopts.Method = messageGoTypes[i].(pref.ProtoMessage)
}
}
}
}
// Process extensions.
if len(tb.ExtensionInfos) != len(fbOut.Extensions) {
panic("mismatching extension lengths")
}
var depIdx int32
for i := range fbOut.Extensions {
// For enum and message kinds, determine the referent Go type so
// that we can construct their constructors.
const listExtDeps = 2
var goType reflect.Type
switch fbOut.Extensions[i].L1.Kind {
case pref.EnumKind:
j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
goType = reflect.TypeOf(tb.GoTypes[j])
depIdx++
case pref.MessageKind, pref.GroupKind:
j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
goType = reflect.TypeOf(tb.GoTypes[j])
depIdx++
default:
goType = goTypeForPBKind[fbOut.Extensions[i].L1.Kind]
}
if fbOut.Extensions[i].IsList() {
goType = reflect.SliceOf(goType)
}
pimpl.InitExtensionInfo(&tb.ExtensionInfos[i], &fbOut.Extensions[i], goType)
// Register extension types.
if err := tb.TypeRegistry.RegisterExtension(&tb.ExtensionInfos[i]); err != nil {
panic(err)
}
}
return out
}
var goTypeForPBKind = map[pref.Kind]reflect.Type{
pref.BoolKind: reflect.TypeOf(bool(false)),
pref.Int32Kind: reflect.TypeOf(int32(0)),
pref.Sint32Kind: reflect.TypeOf(int32(0)),
pref.Sfixed32Kind: reflect.TypeOf(int32(0)),
pref.Int64Kind: reflect.TypeOf(int64(0)),
pref.Sint64Kind: reflect.TypeOf(int64(0)),
pref.Sfixed64Kind: reflect.TypeOf(int64(0)),
pref.Uint32Kind: reflect.TypeOf(uint32(0)),
pref.Fixed32Kind: reflect.TypeOf(uint32(0)),
pref.Uint64Kind: reflect.TypeOf(uint64(0)),
pref.Fixed64Kind: reflect.TypeOf(uint64(0)),
pref.FloatKind: reflect.TypeOf(float32(0)),
pref.DoubleKind: reflect.TypeOf(float64(0)),
pref.StringKind: reflect.TypeOf(string("")),
pref.BytesKind: reflect.TypeOf([]byte(nil)),
}
type depIdxs []int32
// Get retrieves the jth element of the ith sub-list.
func (x depIdxs) Get(i, j int32) int32 {
return x[x[int32(len(x))-i-1]+j]
}
type (
resolverByIndex struct {
goTypes []interface{}
depIdxs depIdxs
fileRegistry
}
fileRegistry interface {
FindFileByPath(string) (pref.FileDescriptor, error)
FindDescriptorByName(pref.FullName) (pref.Descriptor, error)
RegisterFile(pref.FileDescriptor) error
}
)
func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.EnumDescriptor {
if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) {
return &es[depIdx]
} else {
return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx])
}
}
func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.MessageDescriptor {
if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) {
return &ms[depIdx-len(es)]
} else {
return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx])
}
}

View File

@ -0,0 +1,24 @@
// 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 flags provides a set of flags controlled by build tags.
package flags
// ProtoLegacy specifies whether to enable support for legacy functionality
// such as MessageSets, weak fields, and various other obscure behavior
// that is necessary to maintain backwards compatibility with proto1 or
// the pre-release variants of proto2 and proto3.
//
// This is disabled by default unless built with the "protolegacy" tag.
//
// WARNING: The compatibility agreement covers nothing provided by this flag.
// As such, functionality may suddenly be removed or changed at our discretion.
const ProtoLegacy = protoLegacy
// LazyUnmarshalExtensions specifies whether to lazily unmarshal extensions.
//
// Lazy extension unmarshaling validates the contents of message-valued
// extension fields at unmarshal time, but defers creating the message
// structure until the extension is first accessed.
const LazyUnmarshalExtensions = ProtoLegacy

View File

@ -0,0 +1,9 @@
// 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.
// +build !protolegacy
package flags
const protoLegacy = false

View File

@ -0,0 +1,9 @@
// 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.
// +build protolegacy
package flags
const protoLegacy = true

View File

@ -0,0 +1,34 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_any_proto = "google/protobuf/any.proto"
// Names for google.protobuf.Any.
const (
Any_message_name protoreflect.Name = "Any"
Any_message_fullname protoreflect.FullName = "google.protobuf.Any"
)
// Field names for google.protobuf.Any.
const (
Any_TypeUrl_field_name protoreflect.Name = "type_url"
Any_Value_field_name protoreflect.Name = "value"
Any_TypeUrl_field_fullname protoreflect.FullName = "google.protobuf.Any.type_url"
Any_Value_field_fullname protoreflect.FullName = "google.protobuf.Any.value"
)
// Field numbers for google.protobuf.Any.
const (
Any_TypeUrl_field_number protoreflect.FieldNumber = 1
Any_Value_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,106 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_api_proto = "google/protobuf/api.proto"
// Names for google.protobuf.Api.
const (
Api_message_name protoreflect.Name = "Api"
Api_message_fullname protoreflect.FullName = "google.protobuf.Api"
)
// Field names for google.protobuf.Api.
const (
Api_Name_field_name protoreflect.Name = "name"
Api_Methods_field_name protoreflect.Name = "methods"
Api_Options_field_name protoreflect.Name = "options"
Api_Version_field_name protoreflect.Name = "version"
Api_SourceContext_field_name protoreflect.Name = "source_context"
Api_Mixins_field_name protoreflect.Name = "mixins"
Api_Syntax_field_name protoreflect.Name = "syntax"
Api_Name_field_fullname protoreflect.FullName = "google.protobuf.Api.name"
Api_Methods_field_fullname protoreflect.FullName = "google.protobuf.Api.methods"
Api_Options_field_fullname protoreflect.FullName = "google.protobuf.Api.options"
Api_Version_field_fullname protoreflect.FullName = "google.protobuf.Api.version"
Api_SourceContext_field_fullname protoreflect.FullName = "google.protobuf.Api.source_context"
Api_Mixins_field_fullname protoreflect.FullName = "google.protobuf.Api.mixins"
Api_Syntax_field_fullname protoreflect.FullName = "google.protobuf.Api.syntax"
)
// Field numbers for google.protobuf.Api.
const (
Api_Name_field_number protoreflect.FieldNumber = 1
Api_Methods_field_number protoreflect.FieldNumber = 2
Api_Options_field_number protoreflect.FieldNumber = 3
Api_Version_field_number protoreflect.FieldNumber = 4
Api_SourceContext_field_number protoreflect.FieldNumber = 5
Api_Mixins_field_number protoreflect.FieldNumber = 6
Api_Syntax_field_number protoreflect.FieldNumber = 7
)
// Names for google.protobuf.Method.
const (
Method_message_name protoreflect.Name = "Method"
Method_message_fullname protoreflect.FullName = "google.protobuf.Method"
)
// Field names for google.protobuf.Method.
const (
Method_Name_field_name protoreflect.Name = "name"
Method_RequestTypeUrl_field_name protoreflect.Name = "request_type_url"
Method_RequestStreaming_field_name protoreflect.Name = "request_streaming"
Method_ResponseTypeUrl_field_name protoreflect.Name = "response_type_url"
Method_ResponseStreaming_field_name protoreflect.Name = "response_streaming"
Method_Options_field_name protoreflect.Name = "options"
Method_Syntax_field_name protoreflect.Name = "syntax"
Method_Name_field_fullname protoreflect.FullName = "google.protobuf.Method.name"
Method_RequestTypeUrl_field_fullname protoreflect.FullName = "google.protobuf.Method.request_type_url"
Method_RequestStreaming_field_fullname protoreflect.FullName = "google.protobuf.Method.request_streaming"
Method_ResponseTypeUrl_field_fullname protoreflect.FullName = "google.protobuf.Method.response_type_url"
Method_ResponseStreaming_field_fullname protoreflect.FullName = "google.protobuf.Method.response_streaming"
Method_Options_field_fullname protoreflect.FullName = "google.protobuf.Method.options"
Method_Syntax_field_fullname protoreflect.FullName = "google.protobuf.Method.syntax"
)
// Field numbers for google.protobuf.Method.
const (
Method_Name_field_number protoreflect.FieldNumber = 1
Method_RequestTypeUrl_field_number protoreflect.FieldNumber = 2
Method_RequestStreaming_field_number protoreflect.FieldNumber = 3
Method_ResponseTypeUrl_field_number protoreflect.FieldNumber = 4
Method_ResponseStreaming_field_number protoreflect.FieldNumber = 5
Method_Options_field_number protoreflect.FieldNumber = 6
Method_Syntax_field_number protoreflect.FieldNumber = 7
)
// Names for google.protobuf.Mixin.
const (
Mixin_message_name protoreflect.Name = "Mixin"
Mixin_message_fullname protoreflect.FullName = "google.protobuf.Mixin"
)
// Field names for google.protobuf.Mixin.
const (
Mixin_Name_field_name protoreflect.Name = "name"
Mixin_Root_field_name protoreflect.Name = "root"
Mixin_Name_field_fullname protoreflect.FullName = "google.protobuf.Mixin.name"
Mixin_Root_field_fullname protoreflect.FullName = "google.protobuf.Mixin.root"
)
// Field numbers for google.protobuf.Mixin.
const (
Mixin_Name_field_number protoreflect.FieldNumber = 1
Mixin_Root_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,829 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_descriptor_proto = "google/protobuf/descriptor.proto"
// Names for google.protobuf.FileDescriptorSet.
const (
FileDescriptorSet_message_name protoreflect.Name = "FileDescriptorSet"
FileDescriptorSet_message_fullname protoreflect.FullName = "google.protobuf.FileDescriptorSet"
)
// Field names for google.protobuf.FileDescriptorSet.
const (
FileDescriptorSet_File_field_name protoreflect.Name = "file"
FileDescriptorSet_File_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorSet.file"
)
// Field numbers for google.protobuf.FileDescriptorSet.
const (
FileDescriptorSet_File_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.FileDescriptorProto.
const (
FileDescriptorProto_message_name protoreflect.Name = "FileDescriptorProto"
FileDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto"
)
// Field names for google.protobuf.FileDescriptorProto.
const (
FileDescriptorProto_Name_field_name protoreflect.Name = "name"
FileDescriptorProto_Package_field_name protoreflect.Name = "package"
FileDescriptorProto_Dependency_field_name protoreflect.Name = "dependency"
FileDescriptorProto_PublicDependency_field_name protoreflect.Name = "public_dependency"
FileDescriptorProto_WeakDependency_field_name protoreflect.Name = "weak_dependency"
FileDescriptorProto_MessageType_field_name protoreflect.Name = "message_type"
FileDescriptorProto_EnumType_field_name protoreflect.Name = "enum_type"
FileDescriptorProto_Service_field_name protoreflect.Name = "service"
FileDescriptorProto_Extension_field_name protoreflect.Name = "extension"
FileDescriptorProto_Options_field_name protoreflect.Name = "options"
FileDescriptorProto_SourceCodeInfo_field_name protoreflect.Name = "source_code_info"
FileDescriptorProto_Syntax_field_name protoreflect.Name = "syntax"
FileDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.name"
FileDescriptorProto_Package_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.package"
FileDescriptorProto_Dependency_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.dependency"
FileDescriptorProto_PublicDependency_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.public_dependency"
FileDescriptorProto_WeakDependency_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.weak_dependency"
FileDescriptorProto_MessageType_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.message_type"
FileDescriptorProto_EnumType_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.enum_type"
FileDescriptorProto_Service_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.service"
FileDescriptorProto_Extension_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.extension"
FileDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.options"
FileDescriptorProto_SourceCodeInfo_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.source_code_info"
FileDescriptorProto_Syntax_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.syntax"
)
// Field numbers for google.protobuf.FileDescriptorProto.
const (
FileDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
FileDescriptorProto_Package_field_number protoreflect.FieldNumber = 2
FileDescriptorProto_Dependency_field_number protoreflect.FieldNumber = 3
FileDescriptorProto_PublicDependency_field_number protoreflect.FieldNumber = 10
FileDescriptorProto_WeakDependency_field_number protoreflect.FieldNumber = 11
FileDescriptorProto_MessageType_field_number protoreflect.FieldNumber = 4
FileDescriptorProto_EnumType_field_number protoreflect.FieldNumber = 5
FileDescriptorProto_Service_field_number protoreflect.FieldNumber = 6
FileDescriptorProto_Extension_field_number protoreflect.FieldNumber = 7
FileDescriptorProto_Options_field_number protoreflect.FieldNumber = 8
FileDescriptorProto_SourceCodeInfo_field_number protoreflect.FieldNumber = 9
FileDescriptorProto_Syntax_field_number protoreflect.FieldNumber = 12
)
// Names for google.protobuf.DescriptorProto.
const (
DescriptorProto_message_name protoreflect.Name = "DescriptorProto"
DescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.DescriptorProto"
)
// Field names for google.protobuf.DescriptorProto.
const (
DescriptorProto_Name_field_name protoreflect.Name = "name"
DescriptorProto_Field_field_name protoreflect.Name = "field"
DescriptorProto_Extension_field_name protoreflect.Name = "extension"
DescriptorProto_NestedType_field_name protoreflect.Name = "nested_type"
DescriptorProto_EnumType_field_name protoreflect.Name = "enum_type"
DescriptorProto_ExtensionRange_field_name protoreflect.Name = "extension_range"
DescriptorProto_OneofDecl_field_name protoreflect.Name = "oneof_decl"
DescriptorProto_Options_field_name protoreflect.Name = "options"
DescriptorProto_ReservedRange_field_name protoreflect.Name = "reserved_range"
DescriptorProto_ReservedName_field_name protoreflect.Name = "reserved_name"
DescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.name"
DescriptorProto_Field_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.field"
DescriptorProto_Extension_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.extension"
DescriptorProto_NestedType_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.nested_type"
DescriptorProto_EnumType_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.enum_type"
DescriptorProto_ExtensionRange_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.extension_range"
DescriptorProto_OneofDecl_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.oneof_decl"
DescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.options"
DescriptorProto_ReservedRange_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.reserved_range"
DescriptorProto_ReservedName_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.reserved_name"
)
// Field numbers for google.protobuf.DescriptorProto.
const (
DescriptorProto_Name_field_number protoreflect.FieldNumber = 1
DescriptorProto_Field_field_number protoreflect.FieldNumber = 2
DescriptorProto_Extension_field_number protoreflect.FieldNumber = 6
DescriptorProto_NestedType_field_number protoreflect.FieldNumber = 3
DescriptorProto_EnumType_field_number protoreflect.FieldNumber = 4
DescriptorProto_ExtensionRange_field_number protoreflect.FieldNumber = 5
DescriptorProto_OneofDecl_field_number protoreflect.FieldNumber = 8
DescriptorProto_Options_field_number protoreflect.FieldNumber = 7
DescriptorProto_ReservedRange_field_number protoreflect.FieldNumber = 9
DescriptorProto_ReservedName_field_number protoreflect.FieldNumber = 10
)
// Names for google.protobuf.DescriptorProto.ExtensionRange.
const (
DescriptorProto_ExtensionRange_message_name protoreflect.Name = "ExtensionRange"
DescriptorProto_ExtensionRange_message_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ExtensionRange"
)
// Field names for google.protobuf.DescriptorProto.ExtensionRange.
const (
DescriptorProto_ExtensionRange_Start_field_name protoreflect.Name = "start"
DescriptorProto_ExtensionRange_End_field_name protoreflect.Name = "end"
DescriptorProto_ExtensionRange_Options_field_name protoreflect.Name = "options"
DescriptorProto_ExtensionRange_Start_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ExtensionRange.start"
DescriptorProto_ExtensionRange_End_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ExtensionRange.end"
DescriptorProto_ExtensionRange_Options_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ExtensionRange.options"
)
// Field numbers for google.protobuf.DescriptorProto.ExtensionRange.
const (
DescriptorProto_ExtensionRange_Start_field_number protoreflect.FieldNumber = 1
DescriptorProto_ExtensionRange_End_field_number protoreflect.FieldNumber = 2
DescriptorProto_ExtensionRange_Options_field_number protoreflect.FieldNumber = 3
)
// Names for google.protobuf.DescriptorProto.ReservedRange.
const (
DescriptorProto_ReservedRange_message_name protoreflect.Name = "ReservedRange"
DescriptorProto_ReservedRange_message_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ReservedRange"
)
// Field names for google.protobuf.DescriptorProto.ReservedRange.
const (
DescriptorProto_ReservedRange_Start_field_name protoreflect.Name = "start"
DescriptorProto_ReservedRange_End_field_name protoreflect.Name = "end"
DescriptorProto_ReservedRange_Start_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ReservedRange.start"
DescriptorProto_ReservedRange_End_field_fullname protoreflect.FullName = "google.protobuf.DescriptorProto.ReservedRange.end"
)
// Field numbers for google.protobuf.DescriptorProto.ReservedRange.
const (
DescriptorProto_ReservedRange_Start_field_number protoreflect.FieldNumber = 1
DescriptorProto_ReservedRange_End_field_number protoreflect.FieldNumber = 2
)
// Names for google.protobuf.ExtensionRangeOptions.
const (
ExtensionRangeOptions_message_name protoreflect.Name = "ExtensionRangeOptions"
ExtensionRangeOptions_message_fullname protoreflect.FullName = "google.protobuf.ExtensionRangeOptions"
)
// Field names for google.protobuf.ExtensionRangeOptions.
const (
ExtensionRangeOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
ExtensionRangeOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.ExtensionRangeOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.ExtensionRangeOptions.
const (
ExtensionRangeOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.FieldDescriptorProto.
const (
FieldDescriptorProto_message_name protoreflect.Name = "FieldDescriptorProto"
FieldDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto"
)
// Field names for google.protobuf.FieldDescriptorProto.
const (
FieldDescriptorProto_Name_field_name protoreflect.Name = "name"
FieldDescriptorProto_Number_field_name protoreflect.Name = "number"
FieldDescriptorProto_Label_field_name protoreflect.Name = "label"
FieldDescriptorProto_Type_field_name protoreflect.Name = "type"
FieldDescriptorProto_TypeName_field_name protoreflect.Name = "type_name"
FieldDescriptorProto_Extendee_field_name protoreflect.Name = "extendee"
FieldDescriptorProto_DefaultValue_field_name protoreflect.Name = "default_value"
FieldDescriptorProto_OneofIndex_field_name protoreflect.Name = "oneof_index"
FieldDescriptorProto_JsonName_field_name protoreflect.Name = "json_name"
FieldDescriptorProto_Options_field_name protoreflect.Name = "options"
FieldDescriptorProto_Proto3Optional_field_name protoreflect.Name = "proto3_optional"
FieldDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.name"
FieldDescriptorProto_Number_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.number"
FieldDescriptorProto_Label_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.label"
FieldDescriptorProto_Type_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.type"
FieldDescriptorProto_TypeName_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.type_name"
FieldDescriptorProto_Extendee_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.extendee"
FieldDescriptorProto_DefaultValue_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.default_value"
FieldDescriptorProto_OneofIndex_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.oneof_index"
FieldDescriptorProto_JsonName_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.json_name"
FieldDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.options"
FieldDescriptorProto_Proto3Optional_field_fullname protoreflect.FullName = "google.protobuf.FieldDescriptorProto.proto3_optional"
)
// Field numbers for google.protobuf.FieldDescriptorProto.
const (
FieldDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
FieldDescriptorProto_Number_field_number protoreflect.FieldNumber = 3
FieldDescriptorProto_Label_field_number protoreflect.FieldNumber = 4
FieldDescriptorProto_Type_field_number protoreflect.FieldNumber = 5
FieldDescriptorProto_TypeName_field_number protoreflect.FieldNumber = 6
FieldDescriptorProto_Extendee_field_number protoreflect.FieldNumber = 2
FieldDescriptorProto_DefaultValue_field_number protoreflect.FieldNumber = 7
FieldDescriptorProto_OneofIndex_field_number protoreflect.FieldNumber = 9
FieldDescriptorProto_JsonName_field_number protoreflect.FieldNumber = 10
FieldDescriptorProto_Options_field_number protoreflect.FieldNumber = 8
FieldDescriptorProto_Proto3Optional_field_number protoreflect.FieldNumber = 17
)
// Full and short names for google.protobuf.FieldDescriptorProto.Type.
const (
FieldDescriptorProto_Type_enum_fullname = "google.protobuf.FieldDescriptorProto.Type"
FieldDescriptorProto_Type_enum_name = "Type"
)
// Full and short names for google.protobuf.FieldDescriptorProto.Label.
const (
FieldDescriptorProto_Label_enum_fullname = "google.protobuf.FieldDescriptorProto.Label"
FieldDescriptorProto_Label_enum_name = "Label"
)
// Names for google.protobuf.OneofDescriptorProto.
const (
OneofDescriptorProto_message_name protoreflect.Name = "OneofDescriptorProto"
OneofDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.OneofDescriptorProto"
)
// Field names for google.protobuf.OneofDescriptorProto.
const (
OneofDescriptorProto_Name_field_name protoreflect.Name = "name"
OneofDescriptorProto_Options_field_name protoreflect.Name = "options"
OneofDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.OneofDescriptorProto.name"
OneofDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.OneofDescriptorProto.options"
)
// Field numbers for google.protobuf.OneofDescriptorProto.
const (
OneofDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
OneofDescriptorProto_Options_field_number protoreflect.FieldNumber = 2
)
// Names for google.protobuf.EnumDescriptorProto.
const (
EnumDescriptorProto_message_name protoreflect.Name = "EnumDescriptorProto"
EnumDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto"
)
// Field names for google.protobuf.EnumDescriptorProto.
const (
EnumDescriptorProto_Name_field_name protoreflect.Name = "name"
EnumDescriptorProto_Value_field_name protoreflect.Name = "value"
EnumDescriptorProto_Options_field_name protoreflect.Name = "options"
EnumDescriptorProto_ReservedRange_field_name protoreflect.Name = "reserved_range"
EnumDescriptorProto_ReservedName_field_name protoreflect.Name = "reserved_name"
EnumDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.name"
EnumDescriptorProto_Value_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.value"
EnumDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.options"
EnumDescriptorProto_ReservedRange_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.reserved_range"
EnumDescriptorProto_ReservedName_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.reserved_name"
)
// Field numbers for google.protobuf.EnumDescriptorProto.
const (
EnumDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
EnumDescriptorProto_Value_field_number protoreflect.FieldNumber = 2
EnumDescriptorProto_Options_field_number protoreflect.FieldNumber = 3
EnumDescriptorProto_ReservedRange_field_number protoreflect.FieldNumber = 4
EnumDescriptorProto_ReservedName_field_number protoreflect.FieldNumber = 5
)
// Names for google.protobuf.EnumDescriptorProto.EnumReservedRange.
const (
EnumDescriptorProto_EnumReservedRange_message_name protoreflect.Name = "EnumReservedRange"
EnumDescriptorProto_EnumReservedRange_message_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.EnumReservedRange"
)
// Field names for google.protobuf.EnumDescriptorProto.EnumReservedRange.
const (
EnumDescriptorProto_EnumReservedRange_Start_field_name protoreflect.Name = "start"
EnumDescriptorProto_EnumReservedRange_End_field_name protoreflect.Name = "end"
EnumDescriptorProto_EnumReservedRange_Start_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.EnumReservedRange.start"
EnumDescriptorProto_EnumReservedRange_End_field_fullname protoreflect.FullName = "google.protobuf.EnumDescriptorProto.EnumReservedRange.end"
)
// Field numbers for google.protobuf.EnumDescriptorProto.EnumReservedRange.
const (
EnumDescriptorProto_EnumReservedRange_Start_field_number protoreflect.FieldNumber = 1
EnumDescriptorProto_EnumReservedRange_End_field_number protoreflect.FieldNumber = 2
)
// Names for google.protobuf.EnumValueDescriptorProto.
const (
EnumValueDescriptorProto_message_name protoreflect.Name = "EnumValueDescriptorProto"
EnumValueDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.EnumValueDescriptorProto"
)
// Field names for google.protobuf.EnumValueDescriptorProto.
const (
EnumValueDescriptorProto_Name_field_name protoreflect.Name = "name"
EnumValueDescriptorProto_Number_field_name protoreflect.Name = "number"
EnumValueDescriptorProto_Options_field_name protoreflect.Name = "options"
EnumValueDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.EnumValueDescriptorProto.name"
EnumValueDescriptorProto_Number_field_fullname protoreflect.FullName = "google.protobuf.EnumValueDescriptorProto.number"
EnumValueDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.EnumValueDescriptorProto.options"
)
// Field numbers for google.protobuf.EnumValueDescriptorProto.
const (
EnumValueDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
EnumValueDescriptorProto_Number_field_number protoreflect.FieldNumber = 2
EnumValueDescriptorProto_Options_field_number protoreflect.FieldNumber = 3
)
// Names for google.protobuf.ServiceDescriptorProto.
const (
ServiceDescriptorProto_message_name protoreflect.Name = "ServiceDescriptorProto"
ServiceDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.ServiceDescriptorProto"
)
// Field names for google.protobuf.ServiceDescriptorProto.
const (
ServiceDescriptorProto_Name_field_name protoreflect.Name = "name"
ServiceDescriptorProto_Method_field_name protoreflect.Name = "method"
ServiceDescriptorProto_Options_field_name protoreflect.Name = "options"
ServiceDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.ServiceDescriptorProto.name"
ServiceDescriptorProto_Method_field_fullname protoreflect.FullName = "google.protobuf.ServiceDescriptorProto.method"
ServiceDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.ServiceDescriptorProto.options"
)
// Field numbers for google.protobuf.ServiceDescriptorProto.
const (
ServiceDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
ServiceDescriptorProto_Method_field_number protoreflect.FieldNumber = 2
ServiceDescriptorProto_Options_field_number protoreflect.FieldNumber = 3
)
// Names for google.protobuf.MethodDescriptorProto.
const (
MethodDescriptorProto_message_name protoreflect.Name = "MethodDescriptorProto"
MethodDescriptorProto_message_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto"
)
// Field names for google.protobuf.MethodDescriptorProto.
const (
MethodDescriptorProto_Name_field_name protoreflect.Name = "name"
MethodDescriptorProto_InputType_field_name protoreflect.Name = "input_type"
MethodDescriptorProto_OutputType_field_name protoreflect.Name = "output_type"
MethodDescriptorProto_Options_field_name protoreflect.Name = "options"
MethodDescriptorProto_ClientStreaming_field_name protoreflect.Name = "client_streaming"
MethodDescriptorProto_ServerStreaming_field_name protoreflect.Name = "server_streaming"
MethodDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.name"
MethodDescriptorProto_InputType_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.input_type"
MethodDescriptorProto_OutputType_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.output_type"
MethodDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.options"
MethodDescriptorProto_ClientStreaming_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.client_streaming"
MethodDescriptorProto_ServerStreaming_field_fullname protoreflect.FullName = "google.protobuf.MethodDescriptorProto.server_streaming"
)
// Field numbers for google.protobuf.MethodDescriptorProto.
const (
MethodDescriptorProto_Name_field_number protoreflect.FieldNumber = 1
MethodDescriptorProto_InputType_field_number protoreflect.FieldNumber = 2
MethodDescriptorProto_OutputType_field_number protoreflect.FieldNumber = 3
MethodDescriptorProto_Options_field_number protoreflect.FieldNumber = 4
MethodDescriptorProto_ClientStreaming_field_number protoreflect.FieldNumber = 5
MethodDescriptorProto_ServerStreaming_field_number protoreflect.FieldNumber = 6
)
// Names for google.protobuf.FileOptions.
const (
FileOptions_message_name protoreflect.Name = "FileOptions"
FileOptions_message_fullname protoreflect.FullName = "google.protobuf.FileOptions"
)
// Field names for google.protobuf.FileOptions.
const (
FileOptions_JavaPackage_field_name protoreflect.Name = "java_package"
FileOptions_JavaOuterClassname_field_name protoreflect.Name = "java_outer_classname"
FileOptions_JavaMultipleFiles_field_name protoreflect.Name = "java_multiple_files"
FileOptions_JavaGenerateEqualsAndHash_field_name protoreflect.Name = "java_generate_equals_and_hash"
FileOptions_JavaStringCheckUtf8_field_name protoreflect.Name = "java_string_check_utf8"
FileOptions_OptimizeFor_field_name protoreflect.Name = "optimize_for"
FileOptions_GoPackage_field_name protoreflect.Name = "go_package"
FileOptions_CcGenericServices_field_name protoreflect.Name = "cc_generic_services"
FileOptions_JavaGenericServices_field_name protoreflect.Name = "java_generic_services"
FileOptions_PyGenericServices_field_name protoreflect.Name = "py_generic_services"
FileOptions_PhpGenericServices_field_name protoreflect.Name = "php_generic_services"
FileOptions_Deprecated_field_name protoreflect.Name = "deprecated"
FileOptions_CcEnableArenas_field_name protoreflect.Name = "cc_enable_arenas"
FileOptions_ObjcClassPrefix_field_name protoreflect.Name = "objc_class_prefix"
FileOptions_CsharpNamespace_field_name protoreflect.Name = "csharp_namespace"
FileOptions_SwiftPrefix_field_name protoreflect.Name = "swift_prefix"
FileOptions_PhpClassPrefix_field_name protoreflect.Name = "php_class_prefix"
FileOptions_PhpNamespace_field_name protoreflect.Name = "php_namespace"
FileOptions_PhpMetadataNamespace_field_name protoreflect.Name = "php_metadata_namespace"
FileOptions_RubyPackage_field_name protoreflect.Name = "ruby_package"
FileOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
FileOptions_JavaPackage_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_package"
FileOptions_JavaOuterClassname_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_outer_classname"
FileOptions_JavaMultipleFiles_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_multiple_files"
FileOptions_JavaGenerateEqualsAndHash_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_generate_equals_and_hash"
FileOptions_JavaStringCheckUtf8_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_string_check_utf8"
FileOptions_OptimizeFor_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.optimize_for"
FileOptions_GoPackage_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.go_package"
FileOptions_CcGenericServices_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.cc_generic_services"
FileOptions_JavaGenericServices_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.java_generic_services"
FileOptions_PyGenericServices_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.py_generic_services"
FileOptions_PhpGenericServices_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.php_generic_services"
FileOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.deprecated"
FileOptions_CcEnableArenas_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.cc_enable_arenas"
FileOptions_ObjcClassPrefix_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.objc_class_prefix"
FileOptions_CsharpNamespace_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.csharp_namespace"
FileOptions_SwiftPrefix_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.swift_prefix"
FileOptions_PhpClassPrefix_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.php_class_prefix"
FileOptions_PhpNamespace_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.php_namespace"
FileOptions_PhpMetadataNamespace_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.php_metadata_namespace"
FileOptions_RubyPackage_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.ruby_package"
FileOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.FileOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.FileOptions.
const (
FileOptions_JavaPackage_field_number protoreflect.FieldNumber = 1
FileOptions_JavaOuterClassname_field_number protoreflect.FieldNumber = 8
FileOptions_JavaMultipleFiles_field_number protoreflect.FieldNumber = 10
FileOptions_JavaGenerateEqualsAndHash_field_number protoreflect.FieldNumber = 20
FileOptions_JavaStringCheckUtf8_field_number protoreflect.FieldNumber = 27
FileOptions_OptimizeFor_field_number protoreflect.FieldNumber = 9
FileOptions_GoPackage_field_number protoreflect.FieldNumber = 11
FileOptions_CcGenericServices_field_number protoreflect.FieldNumber = 16
FileOptions_JavaGenericServices_field_number protoreflect.FieldNumber = 17
FileOptions_PyGenericServices_field_number protoreflect.FieldNumber = 18
FileOptions_PhpGenericServices_field_number protoreflect.FieldNumber = 42
FileOptions_Deprecated_field_number protoreflect.FieldNumber = 23
FileOptions_CcEnableArenas_field_number protoreflect.FieldNumber = 31
FileOptions_ObjcClassPrefix_field_number protoreflect.FieldNumber = 36
FileOptions_CsharpNamespace_field_number protoreflect.FieldNumber = 37
FileOptions_SwiftPrefix_field_number protoreflect.FieldNumber = 39
FileOptions_PhpClassPrefix_field_number protoreflect.FieldNumber = 40
FileOptions_PhpNamespace_field_number protoreflect.FieldNumber = 41
FileOptions_PhpMetadataNamespace_field_number protoreflect.FieldNumber = 44
FileOptions_RubyPackage_field_number protoreflect.FieldNumber = 45
FileOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Full and short names for google.protobuf.FileOptions.OptimizeMode.
const (
FileOptions_OptimizeMode_enum_fullname = "google.protobuf.FileOptions.OptimizeMode"
FileOptions_OptimizeMode_enum_name = "OptimizeMode"
)
// Names for google.protobuf.MessageOptions.
const (
MessageOptions_message_name protoreflect.Name = "MessageOptions"
MessageOptions_message_fullname protoreflect.FullName = "google.protobuf.MessageOptions"
)
// Field names for google.protobuf.MessageOptions.
const (
MessageOptions_MessageSetWireFormat_field_name protoreflect.Name = "message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_name protoreflect.Name = "no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_name protoreflect.Name = "deprecated"
MessageOptions_MapEntry_field_name protoreflect.Name = "map_entry"
MessageOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
MessageOptions_MessageSetWireFormat_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.deprecated"
MessageOptions_MapEntry_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.map_entry"
MessageOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.MessageOptions.
const (
MessageOptions_MessageSetWireFormat_field_number protoreflect.FieldNumber = 1
MessageOptions_NoStandardDescriptorAccessor_field_number protoreflect.FieldNumber = 2
MessageOptions_Deprecated_field_number protoreflect.FieldNumber = 3
MessageOptions_MapEntry_field_number protoreflect.FieldNumber = 7
MessageOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.FieldOptions.
const (
FieldOptions_message_name protoreflect.Name = "FieldOptions"
FieldOptions_message_fullname protoreflect.FullName = "google.protobuf.FieldOptions"
)
// Field names for google.protobuf.FieldOptions.
const (
FieldOptions_Ctype_field_name protoreflect.Name = "ctype"
FieldOptions_Packed_field_name protoreflect.Name = "packed"
FieldOptions_Jstype_field_name protoreflect.Name = "jstype"
FieldOptions_Lazy_field_name protoreflect.Name = "lazy"
FieldOptions_Deprecated_field_name protoreflect.Name = "deprecated"
FieldOptions_Weak_field_name protoreflect.Name = "weak"
FieldOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
FieldOptions_Ctype_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.ctype"
FieldOptions_Packed_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.packed"
FieldOptions_Jstype_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.jstype"
FieldOptions_Lazy_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.lazy"
FieldOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.deprecated"
FieldOptions_Weak_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.weak"
FieldOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.FieldOptions.
const (
FieldOptions_Ctype_field_number protoreflect.FieldNumber = 1
FieldOptions_Packed_field_number protoreflect.FieldNumber = 2
FieldOptions_Jstype_field_number protoreflect.FieldNumber = 6
FieldOptions_Lazy_field_number protoreflect.FieldNumber = 5
FieldOptions_Deprecated_field_number protoreflect.FieldNumber = 3
FieldOptions_Weak_field_number protoreflect.FieldNumber = 10
FieldOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Full and short names for google.protobuf.FieldOptions.CType.
const (
FieldOptions_CType_enum_fullname = "google.protobuf.FieldOptions.CType"
FieldOptions_CType_enum_name = "CType"
)
// Full and short names for google.protobuf.FieldOptions.JSType.
const (
FieldOptions_JSType_enum_fullname = "google.protobuf.FieldOptions.JSType"
FieldOptions_JSType_enum_name = "JSType"
)
// Names for google.protobuf.OneofOptions.
const (
OneofOptions_message_name protoreflect.Name = "OneofOptions"
OneofOptions_message_fullname protoreflect.FullName = "google.protobuf.OneofOptions"
)
// Field names for google.protobuf.OneofOptions.
const (
OneofOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
OneofOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.OneofOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.OneofOptions.
const (
OneofOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.EnumOptions.
const (
EnumOptions_message_name protoreflect.Name = "EnumOptions"
EnumOptions_message_fullname protoreflect.FullName = "google.protobuf.EnumOptions"
)
// Field names for google.protobuf.EnumOptions.
const (
EnumOptions_AllowAlias_field_name protoreflect.Name = "allow_alias"
EnumOptions_Deprecated_field_name protoreflect.Name = "deprecated"
EnumOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
EnumOptions_AllowAlias_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.allow_alias"
EnumOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.deprecated"
EnumOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.EnumOptions.
const (
EnumOptions_AllowAlias_field_number protoreflect.FieldNumber = 2
EnumOptions_Deprecated_field_number protoreflect.FieldNumber = 3
EnumOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.EnumValueOptions.
const (
EnumValueOptions_message_name protoreflect.Name = "EnumValueOptions"
EnumValueOptions_message_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions"
)
// Field names for google.protobuf.EnumValueOptions.
const (
EnumValueOptions_Deprecated_field_name protoreflect.Name = "deprecated"
EnumValueOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
EnumValueOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.deprecated"
EnumValueOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.EnumValueOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.EnumValueOptions.
const (
EnumValueOptions_Deprecated_field_number protoreflect.FieldNumber = 1
EnumValueOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.ServiceOptions.
const (
ServiceOptions_message_name protoreflect.Name = "ServiceOptions"
ServiceOptions_message_fullname protoreflect.FullName = "google.protobuf.ServiceOptions"
)
// Field names for google.protobuf.ServiceOptions.
const (
ServiceOptions_Deprecated_field_name protoreflect.Name = "deprecated"
ServiceOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
ServiceOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.ServiceOptions.deprecated"
ServiceOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.ServiceOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.ServiceOptions.
const (
ServiceOptions_Deprecated_field_number protoreflect.FieldNumber = 33
ServiceOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.MethodOptions.
const (
MethodOptions_message_name protoreflect.Name = "MethodOptions"
MethodOptions_message_fullname protoreflect.FullName = "google.protobuf.MethodOptions"
)
// Field names for google.protobuf.MethodOptions.
const (
MethodOptions_Deprecated_field_name protoreflect.Name = "deprecated"
MethodOptions_IdempotencyLevel_field_name protoreflect.Name = "idempotency_level"
MethodOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
MethodOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.MethodOptions.deprecated"
MethodOptions_IdempotencyLevel_field_fullname protoreflect.FullName = "google.protobuf.MethodOptions.idempotency_level"
MethodOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.MethodOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.MethodOptions.
const (
MethodOptions_Deprecated_field_number protoreflect.FieldNumber = 33
MethodOptions_IdempotencyLevel_field_number protoreflect.FieldNumber = 34
MethodOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Full and short names for google.protobuf.MethodOptions.IdempotencyLevel.
const (
MethodOptions_IdempotencyLevel_enum_fullname = "google.protobuf.MethodOptions.IdempotencyLevel"
MethodOptions_IdempotencyLevel_enum_name = "IdempotencyLevel"
)
// Names for google.protobuf.UninterpretedOption.
const (
UninterpretedOption_message_name protoreflect.Name = "UninterpretedOption"
UninterpretedOption_message_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption"
)
// Field names for google.protobuf.UninterpretedOption.
const (
UninterpretedOption_Name_field_name protoreflect.Name = "name"
UninterpretedOption_IdentifierValue_field_name protoreflect.Name = "identifier_value"
UninterpretedOption_PositiveIntValue_field_name protoreflect.Name = "positive_int_value"
UninterpretedOption_NegativeIntValue_field_name protoreflect.Name = "negative_int_value"
UninterpretedOption_DoubleValue_field_name protoreflect.Name = "double_value"
UninterpretedOption_StringValue_field_name protoreflect.Name = "string_value"
UninterpretedOption_AggregateValue_field_name protoreflect.Name = "aggregate_value"
UninterpretedOption_Name_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.name"
UninterpretedOption_IdentifierValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.identifier_value"
UninterpretedOption_PositiveIntValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.positive_int_value"
UninterpretedOption_NegativeIntValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.negative_int_value"
UninterpretedOption_DoubleValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.double_value"
UninterpretedOption_StringValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.string_value"
UninterpretedOption_AggregateValue_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.aggregate_value"
)
// Field numbers for google.protobuf.UninterpretedOption.
const (
UninterpretedOption_Name_field_number protoreflect.FieldNumber = 2
UninterpretedOption_IdentifierValue_field_number protoreflect.FieldNumber = 3
UninterpretedOption_PositiveIntValue_field_number protoreflect.FieldNumber = 4
UninterpretedOption_NegativeIntValue_field_number protoreflect.FieldNumber = 5
UninterpretedOption_DoubleValue_field_number protoreflect.FieldNumber = 6
UninterpretedOption_StringValue_field_number protoreflect.FieldNumber = 7
UninterpretedOption_AggregateValue_field_number protoreflect.FieldNumber = 8
)
// Names for google.protobuf.UninterpretedOption.NamePart.
const (
UninterpretedOption_NamePart_message_name protoreflect.Name = "NamePart"
UninterpretedOption_NamePart_message_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.NamePart"
)
// Field names for google.protobuf.UninterpretedOption.NamePart.
const (
UninterpretedOption_NamePart_NamePart_field_name protoreflect.Name = "name_part"
UninterpretedOption_NamePart_IsExtension_field_name protoreflect.Name = "is_extension"
UninterpretedOption_NamePart_NamePart_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.NamePart.name_part"
UninterpretedOption_NamePart_IsExtension_field_fullname protoreflect.FullName = "google.protobuf.UninterpretedOption.NamePart.is_extension"
)
// Field numbers for google.protobuf.UninterpretedOption.NamePart.
const (
UninterpretedOption_NamePart_NamePart_field_number protoreflect.FieldNumber = 1
UninterpretedOption_NamePart_IsExtension_field_number protoreflect.FieldNumber = 2
)
// Names for google.protobuf.SourceCodeInfo.
const (
SourceCodeInfo_message_name protoreflect.Name = "SourceCodeInfo"
SourceCodeInfo_message_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo"
)
// Field names for google.protobuf.SourceCodeInfo.
const (
SourceCodeInfo_Location_field_name protoreflect.Name = "location"
SourceCodeInfo_Location_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.location"
)
// Field numbers for google.protobuf.SourceCodeInfo.
const (
SourceCodeInfo_Location_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.SourceCodeInfo.Location.
const (
SourceCodeInfo_Location_message_name protoreflect.Name = "Location"
SourceCodeInfo_Location_message_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location"
)
// Field names for google.protobuf.SourceCodeInfo.Location.
const (
SourceCodeInfo_Location_Path_field_name protoreflect.Name = "path"
SourceCodeInfo_Location_Span_field_name protoreflect.Name = "span"
SourceCodeInfo_Location_LeadingComments_field_name protoreflect.Name = "leading_comments"
SourceCodeInfo_Location_TrailingComments_field_name protoreflect.Name = "trailing_comments"
SourceCodeInfo_Location_LeadingDetachedComments_field_name protoreflect.Name = "leading_detached_comments"
SourceCodeInfo_Location_Path_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location.path"
SourceCodeInfo_Location_Span_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location.span"
SourceCodeInfo_Location_LeadingComments_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location.leading_comments"
SourceCodeInfo_Location_TrailingComments_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location.trailing_comments"
SourceCodeInfo_Location_LeadingDetachedComments_field_fullname protoreflect.FullName = "google.protobuf.SourceCodeInfo.Location.leading_detached_comments"
)
// Field numbers for google.protobuf.SourceCodeInfo.Location.
const (
SourceCodeInfo_Location_Path_field_number protoreflect.FieldNumber = 1
SourceCodeInfo_Location_Span_field_number protoreflect.FieldNumber = 2
SourceCodeInfo_Location_LeadingComments_field_number protoreflect.FieldNumber = 3
SourceCodeInfo_Location_TrailingComments_field_number protoreflect.FieldNumber = 4
SourceCodeInfo_Location_LeadingDetachedComments_field_number protoreflect.FieldNumber = 6
)
// Names for google.protobuf.GeneratedCodeInfo.
const (
GeneratedCodeInfo_message_name protoreflect.Name = "GeneratedCodeInfo"
GeneratedCodeInfo_message_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo"
)
// Field names for google.protobuf.GeneratedCodeInfo.
const (
GeneratedCodeInfo_Annotation_field_name protoreflect.Name = "annotation"
GeneratedCodeInfo_Annotation_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.annotation"
)
// Field numbers for google.protobuf.GeneratedCodeInfo.
const (
GeneratedCodeInfo_Annotation_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.GeneratedCodeInfo.Annotation.
const (
GeneratedCodeInfo_Annotation_message_name protoreflect.Name = "Annotation"
GeneratedCodeInfo_Annotation_message_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation"
)
// Field names for google.protobuf.GeneratedCodeInfo.Annotation.
const (
GeneratedCodeInfo_Annotation_Path_field_name protoreflect.Name = "path"
GeneratedCodeInfo_Annotation_SourceFile_field_name protoreflect.Name = "source_file"
GeneratedCodeInfo_Annotation_Begin_field_name protoreflect.Name = "begin"
GeneratedCodeInfo_Annotation_End_field_name protoreflect.Name = "end"
GeneratedCodeInfo_Annotation_Path_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.path"
GeneratedCodeInfo_Annotation_SourceFile_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.source_file"
GeneratedCodeInfo_Annotation_Begin_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.begin"
GeneratedCodeInfo_Annotation_End_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.end"
)
// Field numbers for google.protobuf.GeneratedCodeInfo.Annotation.
const (
GeneratedCodeInfo_Annotation_Path_field_number protoreflect.FieldNumber = 1
GeneratedCodeInfo_Annotation_SourceFile_field_number protoreflect.FieldNumber = 2
GeneratedCodeInfo_Annotation_Begin_field_number protoreflect.FieldNumber = 3
GeneratedCodeInfo_Annotation_End_field_number protoreflect.FieldNumber = 4
)

View File

@ -0,0 +1,11 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package genid contains constants for declarations in descriptor.proto
// and the well-known types.
package genid
import protoreflect "google.golang.org/protobuf/reflect/protoreflect"
const GoogleProtobuf_package protoreflect.FullName = "google.protobuf"

View File

@ -0,0 +1,34 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_duration_proto = "google/protobuf/duration.proto"
// Names for google.protobuf.Duration.
const (
Duration_message_name protoreflect.Name = "Duration"
Duration_message_fullname protoreflect.FullName = "google.protobuf.Duration"
)
// Field names for google.protobuf.Duration.
const (
Duration_Seconds_field_name protoreflect.Name = "seconds"
Duration_Nanos_field_name protoreflect.Name = "nanos"
Duration_Seconds_field_fullname protoreflect.FullName = "google.protobuf.Duration.seconds"
Duration_Nanos_field_fullname protoreflect.FullName = "google.protobuf.Duration.nanos"
)
// Field numbers for google.protobuf.Duration.
const (
Duration_Seconds_field_number protoreflect.FieldNumber = 1
Duration_Nanos_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,19 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_empty_proto = "google/protobuf/empty.proto"
// Names for google.protobuf.Empty.
const (
Empty_message_name protoreflect.Name = "Empty"
Empty_message_fullname protoreflect.FullName = "google.protobuf.Empty"
)

View File

@ -0,0 +1,31 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_field_mask_proto = "google/protobuf/field_mask.proto"
// Names for google.protobuf.FieldMask.
const (
FieldMask_message_name protoreflect.Name = "FieldMask"
FieldMask_message_fullname protoreflect.FullName = "google.protobuf.FieldMask"
)
// Field names for google.protobuf.FieldMask.
const (
FieldMask_Paths_field_name protoreflect.Name = "paths"
FieldMask_Paths_field_fullname protoreflect.FullName = "google.protobuf.FieldMask.paths"
)
// Field numbers for google.protobuf.FieldMask.
const (
FieldMask_Paths_field_number protoreflect.FieldNumber = 1
)

View File

@ -0,0 +1,25 @@
// 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 genid
// Go names of implementation-specific struct fields in generated messages.
const (
State_goname = "state"
SizeCache_goname = "sizeCache"
SizeCacheA_goname = "XXX_sizecache"
WeakFields_goname = "weakFields"
WeakFieldsA_goname = "XXX_weak"
UnknownFields_goname = "unknownFields"
UnknownFieldsA_goname = "XXX_unrecognized"
ExtensionFields_goname = "extensionFields"
ExtensionFieldsA_goname = "XXX_InternalExtensions"
ExtensionFieldsB_goname = "XXX_extensions"
WeakFieldPrefix_goname = "XXX_weak_"
)

View File

@ -0,0 +1,16 @@
// 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 genid
import protoreflect "google.golang.org/protobuf/reflect/protoreflect"
// Generic field names and numbers for synthetic map entry messages.
const (
MapEntry_Key_field_name protoreflect.Name = "key"
MapEntry_Value_field_name protoreflect.Name = "value"
MapEntry_Key_field_number protoreflect.FieldNumber = 1
MapEntry_Value_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,31 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_source_context_proto = "google/protobuf/source_context.proto"
// Names for google.protobuf.SourceContext.
const (
SourceContext_message_name protoreflect.Name = "SourceContext"
SourceContext_message_fullname protoreflect.FullName = "google.protobuf.SourceContext"
)
// Field names for google.protobuf.SourceContext.
const (
SourceContext_FileName_field_name protoreflect.Name = "file_name"
SourceContext_FileName_field_fullname protoreflect.FullName = "google.protobuf.SourceContext.file_name"
)
// Field numbers for google.protobuf.SourceContext.
const (
SourceContext_FileName_field_number protoreflect.FieldNumber = 1
)

View File

@ -0,0 +1,116 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_struct_proto = "google/protobuf/struct.proto"
// Full and short names for google.protobuf.NullValue.
const (
NullValue_enum_fullname = "google.protobuf.NullValue"
NullValue_enum_name = "NullValue"
)
// Names for google.protobuf.Struct.
const (
Struct_message_name protoreflect.Name = "Struct"
Struct_message_fullname protoreflect.FullName = "google.protobuf.Struct"
)
// Field names for google.protobuf.Struct.
const (
Struct_Fields_field_name protoreflect.Name = "fields"
Struct_Fields_field_fullname protoreflect.FullName = "google.protobuf.Struct.fields"
)
// Field numbers for google.protobuf.Struct.
const (
Struct_Fields_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.Struct.FieldsEntry.
const (
Struct_FieldsEntry_message_name protoreflect.Name = "FieldsEntry"
Struct_FieldsEntry_message_fullname protoreflect.FullName = "google.protobuf.Struct.FieldsEntry"
)
// Field names for google.protobuf.Struct.FieldsEntry.
const (
Struct_FieldsEntry_Key_field_name protoreflect.Name = "key"
Struct_FieldsEntry_Value_field_name protoreflect.Name = "value"
Struct_FieldsEntry_Key_field_fullname protoreflect.FullName = "google.protobuf.Struct.FieldsEntry.key"
Struct_FieldsEntry_Value_field_fullname protoreflect.FullName = "google.protobuf.Struct.FieldsEntry.value"
)
// Field numbers for google.protobuf.Struct.FieldsEntry.
const (
Struct_FieldsEntry_Key_field_number protoreflect.FieldNumber = 1
Struct_FieldsEntry_Value_field_number protoreflect.FieldNumber = 2
)
// Names for google.protobuf.Value.
const (
Value_message_name protoreflect.Name = "Value"
Value_message_fullname protoreflect.FullName = "google.protobuf.Value"
)
// Field names for google.protobuf.Value.
const (
Value_NullValue_field_name protoreflect.Name = "null_value"
Value_NumberValue_field_name protoreflect.Name = "number_value"
Value_StringValue_field_name protoreflect.Name = "string_value"
Value_BoolValue_field_name protoreflect.Name = "bool_value"
Value_StructValue_field_name protoreflect.Name = "struct_value"
Value_ListValue_field_name protoreflect.Name = "list_value"
Value_NullValue_field_fullname protoreflect.FullName = "google.protobuf.Value.null_value"
Value_NumberValue_field_fullname protoreflect.FullName = "google.protobuf.Value.number_value"
Value_StringValue_field_fullname protoreflect.FullName = "google.protobuf.Value.string_value"
Value_BoolValue_field_fullname protoreflect.FullName = "google.protobuf.Value.bool_value"
Value_StructValue_field_fullname protoreflect.FullName = "google.protobuf.Value.struct_value"
Value_ListValue_field_fullname protoreflect.FullName = "google.protobuf.Value.list_value"
)
// Field numbers for google.protobuf.Value.
const (
Value_NullValue_field_number protoreflect.FieldNumber = 1
Value_NumberValue_field_number protoreflect.FieldNumber = 2
Value_StringValue_field_number protoreflect.FieldNumber = 3
Value_BoolValue_field_number protoreflect.FieldNumber = 4
Value_StructValue_field_number protoreflect.FieldNumber = 5
Value_ListValue_field_number protoreflect.FieldNumber = 6
)
// Oneof names for google.protobuf.Value.
const (
Value_Kind_oneof_name protoreflect.Name = "kind"
Value_Kind_oneof_fullname protoreflect.FullName = "google.protobuf.Value.kind"
)
// Names for google.protobuf.ListValue.
const (
ListValue_message_name protoreflect.Name = "ListValue"
ListValue_message_fullname protoreflect.FullName = "google.protobuf.ListValue"
)
// Field names for google.protobuf.ListValue.
const (
ListValue_Values_field_name protoreflect.Name = "values"
ListValue_Values_field_fullname protoreflect.FullName = "google.protobuf.ListValue.values"
)
// Field numbers for google.protobuf.ListValue.
const (
ListValue_Values_field_number protoreflect.FieldNumber = 1
)

View File

@ -0,0 +1,34 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_timestamp_proto = "google/protobuf/timestamp.proto"
// Names for google.protobuf.Timestamp.
const (
Timestamp_message_name protoreflect.Name = "Timestamp"
Timestamp_message_fullname protoreflect.FullName = "google.protobuf.Timestamp"
)
// Field names for google.protobuf.Timestamp.
const (
Timestamp_Seconds_field_name protoreflect.Name = "seconds"
Timestamp_Nanos_field_name protoreflect.Name = "nanos"
Timestamp_Seconds_field_fullname protoreflect.FullName = "google.protobuf.Timestamp.seconds"
Timestamp_Nanos_field_fullname protoreflect.FullName = "google.protobuf.Timestamp.nanos"
)
// Field numbers for google.protobuf.Timestamp.
const (
Timestamp_Seconds_field_number protoreflect.FieldNumber = 1
Timestamp_Nanos_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,184 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_type_proto = "google/protobuf/type.proto"
// Full and short names for google.protobuf.Syntax.
const (
Syntax_enum_fullname = "google.protobuf.Syntax"
Syntax_enum_name = "Syntax"
)
// Names for google.protobuf.Type.
const (
Type_message_name protoreflect.Name = "Type"
Type_message_fullname protoreflect.FullName = "google.protobuf.Type"
)
// Field names for google.protobuf.Type.
const (
Type_Name_field_name protoreflect.Name = "name"
Type_Fields_field_name protoreflect.Name = "fields"
Type_Oneofs_field_name protoreflect.Name = "oneofs"
Type_Options_field_name protoreflect.Name = "options"
Type_SourceContext_field_name protoreflect.Name = "source_context"
Type_Syntax_field_name protoreflect.Name = "syntax"
Type_Name_field_fullname protoreflect.FullName = "google.protobuf.Type.name"
Type_Fields_field_fullname protoreflect.FullName = "google.protobuf.Type.fields"
Type_Oneofs_field_fullname protoreflect.FullName = "google.protobuf.Type.oneofs"
Type_Options_field_fullname protoreflect.FullName = "google.protobuf.Type.options"
Type_SourceContext_field_fullname protoreflect.FullName = "google.protobuf.Type.source_context"
Type_Syntax_field_fullname protoreflect.FullName = "google.protobuf.Type.syntax"
)
// Field numbers for google.protobuf.Type.
const (
Type_Name_field_number protoreflect.FieldNumber = 1
Type_Fields_field_number protoreflect.FieldNumber = 2
Type_Oneofs_field_number protoreflect.FieldNumber = 3
Type_Options_field_number protoreflect.FieldNumber = 4
Type_SourceContext_field_number protoreflect.FieldNumber = 5
Type_Syntax_field_number protoreflect.FieldNumber = 6
)
// Names for google.protobuf.Field.
const (
Field_message_name protoreflect.Name = "Field"
Field_message_fullname protoreflect.FullName = "google.protobuf.Field"
)
// Field names for google.protobuf.Field.
const (
Field_Kind_field_name protoreflect.Name = "kind"
Field_Cardinality_field_name protoreflect.Name = "cardinality"
Field_Number_field_name protoreflect.Name = "number"
Field_Name_field_name protoreflect.Name = "name"
Field_TypeUrl_field_name protoreflect.Name = "type_url"
Field_OneofIndex_field_name protoreflect.Name = "oneof_index"
Field_Packed_field_name protoreflect.Name = "packed"
Field_Options_field_name protoreflect.Name = "options"
Field_JsonName_field_name protoreflect.Name = "json_name"
Field_DefaultValue_field_name protoreflect.Name = "default_value"
Field_Kind_field_fullname protoreflect.FullName = "google.protobuf.Field.kind"
Field_Cardinality_field_fullname protoreflect.FullName = "google.protobuf.Field.cardinality"
Field_Number_field_fullname protoreflect.FullName = "google.protobuf.Field.number"
Field_Name_field_fullname protoreflect.FullName = "google.protobuf.Field.name"
Field_TypeUrl_field_fullname protoreflect.FullName = "google.protobuf.Field.type_url"
Field_OneofIndex_field_fullname protoreflect.FullName = "google.protobuf.Field.oneof_index"
Field_Packed_field_fullname protoreflect.FullName = "google.protobuf.Field.packed"
Field_Options_field_fullname protoreflect.FullName = "google.protobuf.Field.options"
Field_JsonName_field_fullname protoreflect.FullName = "google.protobuf.Field.json_name"
Field_DefaultValue_field_fullname protoreflect.FullName = "google.protobuf.Field.default_value"
)
// Field numbers for google.protobuf.Field.
const (
Field_Kind_field_number protoreflect.FieldNumber = 1
Field_Cardinality_field_number protoreflect.FieldNumber = 2
Field_Number_field_number protoreflect.FieldNumber = 3
Field_Name_field_number protoreflect.FieldNumber = 4
Field_TypeUrl_field_number protoreflect.FieldNumber = 6
Field_OneofIndex_field_number protoreflect.FieldNumber = 7
Field_Packed_field_number protoreflect.FieldNumber = 8
Field_Options_field_number protoreflect.FieldNumber = 9
Field_JsonName_field_number protoreflect.FieldNumber = 10
Field_DefaultValue_field_number protoreflect.FieldNumber = 11
)
// Full and short names for google.protobuf.Field.Kind.
const (
Field_Kind_enum_fullname = "google.protobuf.Field.Kind"
Field_Kind_enum_name = "Kind"
)
// Full and short names for google.protobuf.Field.Cardinality.
const (
Field_Cardinality_enum_fullname = "google.protobuf.Field.Cardinality"
Field_Cardinality_enum_name = "Cardinality"
)
// Names for google.protobuf.Enum.
const (
Enum_message_name protoreflect.Name = "Enum"
Enum_message_fullname protoreflect.FullName = "google.protobuf.Enum"
)
// Field names for google.protobuf.Enum.
const (
Enum_Name_field_name protoreflect.Name = "name"
Enum_Enumvalue_field_name protoreflect.Name = "enumvalue"
Enum_Options_field_name protoreflect.Name = "options"
Enum_SourceContext_field_name protoreflect.Name = "source_context"
Enum_Syntax_field_name protoreflect.Name = "syntax"
Enum_Name_field_fullname protoreflect.FullName = "google.protobuf.Enum.name"
Enum_Enumvalue_field_fullname protoreflect.FullName = "google.protobuf.Enum.enumvalue"
Enum_Options_field_fullname protoreflect.FullName = "google.protobuf.Enum.options"
Enum_SourceContext_field_fullname protoreflect.FullName = "google.protobuf.Enum.source_context"
Enum_Syntax_field_fullname protoreflect.FullName = "google.protobuf.Enum.syntax"
)
// Field numbers for google.protobuf.Enum.
const (
Enum_Name_field_number protoreflect.FieldNumber = 1
Enum_Enumvalue_field_number protoreflect.FieldNumber = 2
Enum_Options_field_number protoreflect.FieldNumber = 3
Enum_SourceContext_field_number protoreflect.FieldNumber = 4
Enum_Syntax_field_number protoreflect.FieldNumber = 5
)
// Names for google.protobuf.EnumValue.
const (
EnumValue_message_name protoreflect.Name = "EnumValue"
EnumValue_message_fullname protoreflect.FullName = "google.protobuf.EnumValue"
)
// Field names for google.protobuf.EnumValue.
const (
EnumValue_Name_field_name protoreflect.Name = "name"
EnumValue_Number_field_name protoreflect.Name = "number"
EnumValue_Options_field_name protoreflect.Name = "options"
EnumValue_Name_field_fullname protoreflect.FullName = "google.protobuf.EnumValue.name"
EnumValue_Number_field_fullname protoreflect.FullName = "google.protobuf.EnumValue.number"
EnumValue_Options_field_fullname protoreflect.FullName = "google.protobuf.EnumValue.options"
)
// Field numbers for google.protobuf.EnumValue.
const (
EnumValue_Name_field_number protoreflect.FieldNumber = 1
EnumValue_Number_field_number protoreflect.FieldNumber = 2
EnumValue_Options_field_number protoreflect.FieldNumber = 3
)
// Names for google.protobuf.Option.
const (
Option_message_name protoreflect.Name = "Option"
Option_message_fullname protoreflect.FullName = "google.protobuf.Option"
)
// Field names for google.protobuf.Option.
const (
Option_Name_field_name protoreflect.Name = "name"
Option_Value_field_name protoreflect.Name = "value"
Option_Name_field_fullname protoreflect.FullName = "google.protobuf.Option.name"
Option_Value_field_fullname protoreflect.FullName = "google.protobuf.Option.value"
)
// Field numbers for google.protobuf.Option.
const (
Option_Name_field_number protoreflect.FieldNumber = 1
Option_Value_field_number protoreflect.FieldNumber = 2
)

View File

@ -0,0 +1,13 @@
// 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 genid
import protoreflect "google.golang.org/protobuf/reflect/protoreflect"
// Generic field name and number for messages in wrappers.proto.
const (
WrapperValue_Value_field_name protoreflect.Name = "value"
WrapperValue_Value_field_number protoreflect.FieldNumber = 1
)

View File

@ -0,0 +1,175 @@
// 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 genid
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
)
const File_google_protobuf_wrappers_proto = "google/protobuf/wrappers.proto"
// Names for google.protobuf.DoubleValue.
const (
DoubleValue_message_name protoreflect.Name = "DoubleValue"
DoubleValue_message_fullname protoreflect.FullName = "google.protobuf.DoubleValue"
)
// Field names for google.protobuf.DoubleValue.
const (
DoubleValue_Value_field_name protoreflect.Name = "value"
DoubleValue_Value_field_fullname protoreflect.FullName = "google.protobuf.DoubleValue.value"
)
// Field numbers for google.protobuf.DoubleValue.
const (
DoubleValue_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.FloatValue.
const (
FloatValue_message_name protoreflect.Name = "FloatValue"
FloatValue_message_fullname protoreflect.FullName = "google.protobuf.FloatValue"
)
// Field names for google.protobuf.FloatValue.
const (
FloatValue_Value_field_name protoreflect.Name = "value"
FloatValue_Value_field_fullname protoreflect.FullName = "google.protobuf.FloatValue.value"
)
// Field numbers for google.protobuf.FloatValue.
const (
FloatValue_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.Int64Value.
const (
Int64Value_message_name protoreflect.Name = "Int64Value"
Int64Value_message_fullname protoreflect.FullName = "google.protobuf.Int64Value"
)
// Field names for google.protobuf.Int64Value.
const (
Int64Value_Value_field_name protoreflect.Name = "value"
Int64Value_Value_field_fullname protoreflect.FullName = "google.protobuf.Int64Value.value"
)
// Field numbers for google.protobuf.Int64Value.
const (
Int64Value_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.UInt64Value.
const (
UInt64Value_message_name protoreflect.Name = "UInt64Value"
UInt64Value_message_fullname protoreflect.FullName = "google.protobuf.UInt64Value"
)
// Field names for google.protobuf.UInt64Value.
const (
UInt64Value_Value_field_name protoreflect.Name = "value"
UInt64Value_Value_field_fullname protoreflect.FullName = "google.protobuf.UInt64Value.value"
)
// Field numbers for google.protobuf.UInt64Value.
const (
UInt64Value_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.Int32Value.
const (
Int32Value_message_name protoreflect.Name = "Int32Value"
Int32Value_message_fullname protoreflect.FullName = "google.protobuf.Int32Value"
)
// Field names for google.protobuf.Int32Value.
const (
Int32Value_Value_field_name protoreflect.Name = "value"
Int32Value_Value_field_fullname protoreflect.FullName = "google.protobuf.Int32Value.value"
)
// Field numbers for google.protobuf.Int32Value.
const (
Int32Value_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.UInt32Value.
const (
UInt32Value_message_name protoreflect.Name = "UInt32Value"
UInt32Value_message_fullname protoreflect.FullName = "google.protobuf.UInt32Value"
)
// Field names for google.protobuf.UInt32Value.
const (
UInt32Value_Value_field_name protoreflect.Name = "value"
UInt32Value_Value_field_fullname protoreflect.FullName = "google.protobuf.UInt32Value.value"
)
// Field numbers for google.protobuf.UInt32Value.
const (
UInt32Value_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.BoolValue.
const (
BoolValue_message_name protoreflect.Name = "BoolValue"
BoolValue_message_fullname protoreflect.FullName = "google.protobuf.BoolValue"
)
// Field names for google.protobuf.BoolValue.
const (
BoolValue_Value_field_name protoreflect.Name = "value"
BoolValue_Value_field_fullname protoreflect.FullName = "google.protobuf.BoolValue.value"
)
// Field numbers for google.protobuf.BoolValue.
const (
BoolValue_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.StringValue.
const (
StringValue_message_name protoreflect.Name = "StringValue"
StringValue_message_fullname protoreflect.FullName = "google.protobuf.StringValue"
)
// Field names for google.protobuf.StringValue.
const (
StringValue_Value_field_name protoreflect.Name = "value"
StringValue_Value_field_fullname protoreflect.FullName = "google.protobuf.StringValue.value"
)
// Field numbers for google.protobuf.StringValue.
const (
StringValue_Value_field_number protoreflect.FieldNumber = 1
)
// Names for google.protobuf.BytesValue.
const (
BytesValue_message_name protoreflect.Name = "BytesValue"
BytesValue_message_fullname protoreflect.FullName = "google.protobuf.BytesValue"
)
// Field names for google.protobuf.BytesValue.
const (
BytesValue_Value_field_name protoreflect.Name = "value"
BytesValue_Value_field_fullname protoreflect.FullName = "google.protobuf.BytesValue.value"
)
// Field numbers for google.protobuf.BytesValue.
const (
BytesValue_Value_field_number protoreflect.FieldNumber = 1
)

View File

@ -0,0 +1,177 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"fmt"
"reflect"
"strconv"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
// Export is a zero-length named type that exists only to export a set of
// functions that we do not want to appear in godoc.
type Export struct{}
// NewError formats a string according to the format specifier and arguments and
// returns an error that has a "proto" prefix.
func (Export) NewError(f string, x ...interface{}) error {
return errors.New(f, x...)
}
// enum is any enum type generated by protoc-gen-go
// and must be a named int32 type.
type enum = interface{}
// EnumOf returns the protoreflect.Enum interface over e.
// It returns nil if e is nil.
func (Export) EnumOf(e enum) pref.Enum {
switch e := e.(type) {
case nil:
return nil
case pref.Enum:
return e
default:
return legacyWrapEnum(reflect.ValueOf(e))
}
}
// EnumDescriptorOf returns the protoreflect.EnumDescriptor for e.
// It returns nil if e is nil.
func (Export) EnumDescriptorOf(e enum) pref.EnumDescriptor {
switch e := e.(type) {
case nil:
return nil
case pref.Enum:
return e.Descriptor()
default:
return LegacyLoadEnumDesc(reflect.TypeOf(e))
}
}
// EnumTypeOf returns the protoreflect.EnumType for e.
// It returns nil if e is nil.
func (Export) EnumTypeOf(e enum) pref.EnumType {
switch e := e.(type) {
case nil:
return nil
case pref.Enum:
return e.Type()
default:
return legacyLoadEnumType(reflect.TypeOf(e))
}
}
// EnumStringOf returns the enum value as a string, either as the name if
// the number is resolvable, or the number formatted as a string.
func (Export) EnumStringOf(ed pref.EnumDescriptor, n pref.EnumNumber) string {
ev := ed.Values().ByNumber(n)
if ev != nil {
return string(ev.Name())
}
return strconv.Itoa(int(n))
}
// message is any message type generated by protoc-gen-go
// and must be a pointer to a named struct type.
type message = interface{}
// legacyMessageWrapper wraps a v2 message as a v1 message.
type legacyMessageWrapper struct{ m pref.ProtoMessage }
func (m legacyMessageWrapper) Reset() { proto.Reset(m.m) }
func (m legacyMessageWrapper) String() string { return Export{}.MessageStringOf(m.m) }
func (m legacyMessageWrapper) ProtoMessage() {}
// ProtoMessageV1Of converts either a v1 or v2 message to a v1 message.
// It returns nil if m is nil.
func (Export) ProtoMessageV1Of(m message) piface.MessageV1 {
switch mv := m.(type) {
case nil:
return nil
case piface.MessageV1:
return mv
case unwrapper:
return Export{}.ProtoMessageV1Of(mv.protoUnwrap())
case pref.ProtoMessage:
return legacyMessageWrapper{mv}
default:
panic(fmt.Sprintf("message %T is neither a v1 or v2 Message", m))
}
}
func (Export) protoMessageV2Of(m message) pref.ProtoMessage {
switch mv := m.(type) {
case nil:
return nil
case pref.ProtoMessage:
return mv
case legacyMessageWrapper:
return mv.m
case piface.MessageV1:
return nil
default:
panic(fmt.Sprintf("message %T is neither a v1 or v2 Message", m))
}
}
// ProtoMessageV2Of converts either a v1 or v2 message to a v2 message.
// It returns nil if m is nil.
func (Export) ProtoMessageV2Of(m message) pref.ProtoMessage {
if m == nil {
return nil
}
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv
}
return legacyWrapMessage(reflect.ValueOf(m)).Interface()
}
// MessageOf returns the protoreflect.Message interface over m.
// It returns nil if m is nil.
func (Export) MessageOf(m message) pref.Message {
if m == nil {
return nil
}
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect()
}
return legacyWrapMessage(reflect.ValueOf(m))
}
// MessageDescriptorOf returns the protoreflect.MessageDescriptor for m.
// It returns nil if m is nil.
func (Export) MessageDescriptorOf(m message) pref.MessageDescriptor {
if m == nil {
return nil
}
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect().Descriptor()
}
return LegacyLoadMessageDesc(reflect.TypeOf(m))
}
// MessageTypeOf returns the protoreflect.MessageType for m.
// It returns nil if m is nil.
func (Export) MessageTypeOf(m message) pref.MessageType {
if m == nil {
return nil
}
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect().Type()
}
return legacyLoadMessageInfo(reflect.TypeOf(m), "")
}
// MessageStringOf returns the message value as a string,
// which is the message serialized in the protobuf text format.
func (Export) MessageStringOf(m pref.ProtoMessage) string {
return prototext.MarshalOptions{Multiline: false}.Format(m)
}

View File

@ -0,0 +1,141 @@
// 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 impl
import (
"sync"
"google.golang.org/protobuf/internal/errors"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
func (mi *MessageInfo) checkInitialized(in piface.CheckInitializedInput) (piface.CheckInitializedOutput, error) {
var p pointer
if ms, ok := in.Message.(*messageState); ok {
p = ms.pointer()
} else {
p = in.Message.(*messageReflectWrapper).pointer()
}
return piface.CheckInitializedOutput{}, mi.checkInitializedPointer(p)
}
func (mi *MessageInfo) checkInitializedPointer(p pointer) error {
mi.init()
if !mi.needsInitCheck {
return nil
}
if p.IsNil() {
for _, f := range mi.orderedCoderFields {
if f.isRequired {
return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
}
}
return nil
}
if mi.extensionOffset.IsValid() {
e := p.Apply(mi.extensionOffset).Extensions()
if err := mi.isInitExtensions(e); err != nil {
return err
}
}
for _, f := range mi.orderedCoderFields {
if !f.isRequired && f.funcs.isInit == nil {
continue
}
fptr := p.Apply(f.offset)
if f.isPointer && fptr.Elem().IsNil() {
if f.isRequired {
return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
}
continue
}
if f.funcs.isInit == nil {
continue
}
if err := f.funcs.isInit(fptr, f); err != nil {
return err
}
}
return nil
}
func (mi *MessageInfo) isInitExtensions(ext *map[int32]ExtensionField) error {
if ext == nil {
return nil
}
for _, x := range *ext {
ei := getExtensionFieldInfo(x.Type())
if ei.funcs.isInit == nil {
continue
}
v := x.Value()
if !v.IsValid() {
continue
}
if err := ei.funcs.isInit(v); err != nil {
return err
}
}
return nil
}
var (
needsInitCheckMu sync.Mutex
needsInitCheckMap sync.Map
)
// needsInitCheck reports whether a message needs to be checked for partial initialization.
//
// It returns true if the message transitively includes any required or extension fields.
func needsInitCheck(md pref.MessageDescriptor) bool {
if v, ok := needsInitCheckMap.Load(md); ok {
if has, ok := v.(bool); ok {
return has
}
}
needsInitCheckMu.Lock()
defer needsInitCheckMu.Unlock()
return needsInitCheckLocked(md)
}
func needsInitCheckLocked(md pref.MessageDescriptor) (has bool) {
if v, ok := needsInitCheckMap.Load(md); ok {
// If has is true, we've previously determined that this message
// needs init checks.
//
// If has is false, we've previously determined that it can never
// be uninitialized.
//
// If has is not a bool, we've just encountered a cycle in the
// message graph. In this case, it is safe to return false: If
// the message does have required fields, we'll detect them later
// in the graph traversal.
has, ok := v.(bool)
return ok && has
}
needsInitCheckMap.Store(md, struct{}{}) // avoid cycles while descending into this message
defer func() {
needsInitCheckMap.Store(md, has)
}()
if md.RequiredNumbers().Len() > 0 {
return true
}
if md.ExtensionRanges().Len() > 0 {
return true
}
for i := 0; i < md.Fields().Len(); i++ {
fd := md.Fields().Get(i)
// Map keys are never messages, so just consider the map value.
if fd.IsMap() {
fd = fd.MapValue()
}
fmd := fd.Message()
if fmd != nil && needsInitCheckLocked(fmd) {
return true
}
}
return false
}

View File

@ -0,0 +1,223 @@
// 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 impl
import (
"sync"
"sync/atomic"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type extensionFieldInfo struct {
wiretag uint64
tagsize int
unmarshalNeedsValue bool
funcs valueCoderFuncs
validation validationInfo
}
var legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo
func getExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
if xi, ok := xt.(*ExtensionInfo); ok {
xi.lazyInit()
return xi.info
}
return legacyLoadExtensionFieldInfo(xt)
}
// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt.
func legacyLoadExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
if xi, ok := legacyExtensionFieldInfoCache.Load(xt); ok {
return xi.(*extensionFieldInfo)
}
e := makeExtensionFieldInfo(xt.TypeDescriptor())
if e, ok := legacyMessageTypeCache.LoadOrStore(xt, e); ok {
return e.(*extensionFieldInfo)
}
return e
}
func makeExtensionFieldInfo(xd pref.ExtensionDescriptor) *extensionFieldInfo {
var wiretag uint64
if !xd.IsPacked() {
wiretag = protowire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
} else {
wiretag = protowire.EncodeTag(xd.Number(), protowire.BytesType)
}
e := &extensionFieldInfo{
wiretag: wiretag,
tagsize: protowire.SizeVarint(wiretag),
funcs: encoderFuncsForValue(xd),
}
// Does the unmarshal function need a value passed to it?
// This is true for composite types, where we pass in a message, list, or map to fill in,
// and for enums, where we pass in a prototype value to specify the concrete enum type.
switch xd.Kind() {
case pref.MessageKind, pref.GroupKind, pref.EnumKind:
e.unmarshalNeedsValue = true
default:
if xd.Cardinality() == pref.Repeated {
e.unmarshalNeedsValue = true
}
}
return e
}
type lazyExtensionValue struct {
atomicOnce uint32 // atomically set if value is valid
mu sync.Mutex
xi *extensionFieldInfo
value pref.Value
b []byte
fn func() pref.Value
}
type ExtensionField struct {
typ pref.ExtensionType
// value is either the value of GetValue,
// or a *lazyExtensionValue that then returns the value of GetValue.
value pref.Value
lazy *lazyExtensionValue
}
func (f *ExtensionField) appendLazyBytes(xt pref.ExtensionType, xi *extensionFieldInfo, num protowire.Number, wtyp protowire.Type, b []byte) {
if f.lazy == nil {
f.lazy = &lazyExtensionValue{xi: xi}
}
f.typ = xt
f.lazy.xi = xi
f.lazy.b = protowire.AppendTag(f.lazy.b, num, wtyp)
f.lazy.b = append(f.lazy.b, b...)
}
func (f *ExtensionField) canLazy(xt pref.ExtensionType) bool {
if f.typ == nil {
return true
}
if f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0 {
return true
}
return false
}
func (f *ExtensionField) lazyInit() {
f.lazy.mu.Lock()
defer f.lazy.mu.Unlock()
if atomic.LoadUint32(&f.lazy.atomicOnce) == 1 {
return
}
if f.lazy.xi != nil {
b := f.lazy.b
val := f.typ.New()
for len(b) > 0 {
var tag uint64
if b[0] < 0x80 {
tag = uint64(b[0])
b = b[1:]
} else if len(b) >= 2 && b[1] < 128 {
tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
b = b[2:]
} else {
var n int
tag, n = protowire.ConsumeVarint(b)
if n < 0 {
panic(errors.New("bad tag in lazy extension decoding"))
}
b = b[n:]
}
num := protowire.Number(tag >> 3)
wtyp := protowire.Type(tag & 7)
var out unmarshalOutput
var err error
val, out, err = f.lazy.xi.funcs.unmarshal(b, val, num, wtyp, lazyUnmarshalOptions)
if err != nil {
panic(errors.New("decode failure in lazy extension decoding: %v", err))
}
b = b[out.n:]
}
f.lazy.value = val
} else {
f.lazy.value = f.lazy.fn()
}
f.lazy.xi = nil
f.lazy.fn = nil
f.lazy.b = nil
atomic.StoreUint32(&f.lazy.atomicOnce, 1)
}
// Set sets the type and value of the extension field.
// This must not be called concurrently.
func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
f.typ = t
f.value = v
f.lazy = nil
}
// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
// This must not be called concurrently.
func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
f.typ = t
f.lazy = &lazyExtensionValue{fn: fn}
}
// Value returns the value of the extension field.
// This may be called concurrently.
func (f *ExtensionField) Value() pref.Value {
if f.lazy != nil {
if atomic.LoadUint32(&f.lazy.atomicOnce) == 0 {
f.lazyInit()
}
return f.lazy.value
}
return f.value
}
// Type returns the type of the extension field.
// This may be called concurrently.
func (f ExtensionField) Type() pref.ExtensionType {
return f.typ
}
// IsSet returns whether the extension field is set.
// This may be called concurrently.
func (f ExtensionField) IsSet() bool {
return f.typ != nil
}
// IsLazy reports whether a field is lazily encoded.
// It is exported for testing.
func IsLazy(m pref.Message, fd pref.FieldDescriptor) bool {
var mi *MessageInfo
var p pointer
switch m := m.(type) {
case *messageState:
mi = m.messageInfo()
p = m.pointer()
case *messageReflectWrapper:
mi = m.messageInfo()
p = m.pointer()
default:
return false
}
xd, ok := fd.(pref.ExtensionTypeDescriptor)
if !ok {
return false
}
xt := xd.Type()
ext := mi.extensionMap(p)
if ext == nil {
return false
}
f, ok := (*ext)[int32(fd.Number())]
if !ok {
return false
}
return f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0
}

View File

@ -0,0 +1,828 @@
// 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 impl
import (
"fmt"
"reflect"
"sync"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
piface "google.golang.org/protobuf/runtime/protoiface"
)
type errInvalidUTF8 struct{}
func (errInvalidUTF8) Error() string { return "string field contains invalid UTF-8" }
func (errInvalidUTF8) InvalidUTF8() bool { return true }
// initOneofFieldCoders initializes the fast-path functions for the fields in a oneof.
//
// For size, marshal, and isInit operations, functions are set only on the first field
// in the oneof. The functions are called when the oneof is non-nil, and will dispatch
// to the appropriate field-specific function as necessary.
//
// The unmarshal function is set on each field individually as usual.
func (mi *MessageInfo) initOneofFieldCoders(od pref.OneofDescriptor, si structInfo) {
fs := si.oneofsByName[od.Name()]
ft := fs.Type
oneofFields := make(map[reflect.Type]*coderFieldInfo)
needIsInit := false
fields := od.Fields()
for i, lim := 0, fields.Len(); i < lim; i++ {
fd := od.Fields().Get(i)
num := fd.Number()
// Make a copy of the original coderFieldInfo for use in unmarshaling.
//
// oneofFields[oneofType].funcs.marshal is the field-specific marshal function.
//
// mi.coderFields[num].marshal is set on only the first field in the oneof,
// and dispatches to the field-specific marshaler in oneofFields.
cf := *mi.coderFields[num]
ot := si.oneofWrappersByNumber[num]
cf.ft = ot.Field(0).Type
cf.mi, cf.funcs = fieldCoder(fd, cf.ft)
oneofFields[ot] = &cf
if cf.funcs.isInit != nil {
needIsInit = true
}
mi.coderFields[num].funcs.unmarshal = func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
var vw reflect.Value // pointer to wrapper type
vi := p.AsValueOf(ft).Elem() // oneof field value of interface kind
if !vi.IsNil() && !vi.Elem().IsNil() && vi.Elem().Elem().Type() == ot {
vw = vi.Elem()
} else {
vw = reflect.New(ot)
}
out, err := cf.funcs.unmarshal(b, pointerOfValue(vw).Apply(zeroOffset), wtyp, &cf, opts)
if err != nil {
return out, err
}
vi.Set(vw)
return out, nil
}
}
getInfo := func(p pointer) (pointer, *coderFieldInfo) {
v := p.AsValueOf(ft).Elem()
if v.IsNil() {
return pointer{}, nil
}
v = v.Elem() // interface -> *struct
if v.IsNil() {
return pointer{}, nil
}
return pointerOfValue(v).Apply(zeroOffset), oneofFields[v.Elem().Type()]
}
first := mi.coderFields[od.Fields().Get(0).Number()]
first.funcs.size = func(p pointer, _ *coderFieldInfo, opts marshalOptions) int {
p, info := getInfo(p)
if info == nil || info.funcs.size == nil {
return 0
}
return info.funcs.size(p, info, opts)
}
first.funcs.marshal = func(b []byte, p pointer, _ *coderFieldInfo, opts marshalOptions) ([]byte, error) {
p, info := getInfo(p)
if info == nil || info.funcs.marshal == nil {
return b, nil
}
return info.funcs.marshal(b, p, info, opts)
}
first.funcs.merge = func(dst, src pointer, _ *coderFieldInfo, opts mergeOptions) {
srcp, srcinfo := getInfo(src)
if srcinfo == nil || srcinfo.funcs.merge == nil {
return
}
dstp, dstinfo := getInfo(dst)
if dstinfo != srcinfo {
dst.AsValueOf(ft).Elem().Set(reflect.New(src.AsValueOf(ft).Elem().Elem().Elem().Type()))
dstp = pointerOfValue(dst.AsValueOf(ft).Elem().Elem()).Apply(zeroOffset)
}
srcinfo.funcs.merge(dstp, srcp, srcinfo, opts)
}
if needIsInit {
first.funcs.isInit = func(p pointer, _ *coderFieldInfo) error {
p, info := getInfo(p)
if info == nil || info.funcs.isInit == nil {
return nil
}
return info.funcs.isInit(p, info)
}
}
}
func makeWeakMessageFieldCoder(fd pref.FieldDescriptor) pointerCoderFuncs {
var once sync.Once
var messageType pref.MessageType
lazyInit := func() {
once.Do(func() {
messageName := fd.Message().FullName()
messageType, _ = preg.GlobalTypes.FindMessageByName(messageName)
})
}
return pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
m, ok := p.WeakFields().get(f.num)
if !ok {
return 0
}
lazyInit()
if messageType == nil {
panic(fmt.Sprintf("weak message %v is not linked in", fd.Message().FullName()))
}
return sizeMessage(m, f.tagsize, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
m, ok := p.WeakFields().get(f.num)
if !ok {
return b, nil
}
lazyInit()
if messageType == nil {
panic(fmt.Sprintf("weak message %v is not linked in", fd.Message().FullName()))
}
return appendMessage(b, m, f.wiretag, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
fs := p.WeakFields()
m, ok := fs.get(f.num)
if !ok {
lazyInit()
if messageType == nil {
return unmarshalOutput{}, errUnknown
}
m = messageType.New().Interface()
fs.set(f.num, m)
}
return consumeMessage(b, m, wtyp, opts)
},
isInit: func(p pointer, f *coderFieldInfo) error {
m, ok := p.WeakFields().get(f.num)
if !ok {
return nil
}
return proto.CheckInitialized(m)
},
merge: func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
sm, ok := src.WeakFields().get(f.num)
if !ok {
return
}
dm, ok := dst.WeakFields().get(f.num)
if !ok {
lazyInit()
if messageType == nil {
panic(fmt.Sprintf("weak message %v is not linked in", fd.Message().FullName()))
}
dm = messageType.New().Interface()
dst.WeakFields().set(f.num, dm)
}
opts.Merge(dm, sm)
},
}
}
func makeMessageFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
if mi := getMessageInfo(ft); mi != nil {
funcs := pointerCoderFuncs{
size: sizeMessageInfo,
marshal: appendMessageInfo,
unmarshal: consumeMessageInfo,
merge: mergeMessage,
}
if needsInitCheck(mi.Desc) {
funcs.isInit = isInitMessageInfo
}
return funcs
} else {
return pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
m := asMessage(p.AsValueOf(ft).Elem())
return sizeMessage(m, f.tagsize, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
m := asMessage(p.AsValueOf(ft).Elem())
return appendMessage(b, m, f.wiretag, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
mp := p.AsValueOf(ft).Elem()
if mp.IsNil() {
mp.Set(reflect.New(ft.Elem()))
}
return consumeMessage(b, asMessage(mp), wtyp, opts)
},
isInit: func(p pointer, f *coderFieldInfo) error {
m := asMessage(p.AsValueOf(ft).Elem())
return proto.CheckInitialized(m)
},
merge: mergeMessage,
}
}
}
func sizeMessageInfo(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return protowire.SizeBytes(f.mi.sizePointer(p.Elem(), opts)) + f.tagsize
}
func appendMessageInfo(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
b = protowire.AppendVarint(b, f.wiretag)
b = protowire.AppendVarint(b, uint64(f.mi.sizePointer(p.Elem(), opts)))
return f.mi.marshalAppendPointer(b, p.Elem(), opts)
}
func consumeMessageInfo(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
if p.Elem().IsNil() {
p.SetPointer(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())))
}
o, err := f.mi.unmarshalPointer(v, p.Elem(), 0, opts)
if err != nil {
return out, err
}
out.n = n
out.initialized = o.initialized
return out, nil
}
func isInitMessageInfo(p pointer, f *coderFieldInfo) error {
return f.mi.checkInitializedPointer(p.Elem())
}
func sizeMessage(m proto.Message, tagsize int, _ marshalOptions) int {
return protowire.SizeBytes(proto.Size(m)) + tagsize
}
func appendMessage(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
b = protowire.AppendVarint(b, wiretag)
b = protowire.AppendVarint(b, uint64(proto.Size(m)))
return opts.Options().MarshalAppend(b, m)
}
func consumeMessage(b []byte, m proto.Message, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: v,
Message: m.ProtoReflect(),
})
if err != nil {
return out, err
}
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return out, nil
}
func sizeMessageValue(v pref.Value, tagsize int, opts marshalOptions) int {
m := v.Message().Interface()
return sizeMessage(m, tagsize, opts)
}
func appendMessageValue(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
m := v.Message().Interface()
return appendMessage(b, m, wiretag, opts)
}
func consumeMessageValue(b []byte, v pref.Value, _ protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (pref.Value, unmarshalOutput, error) {
m := v.Message().Interface()
out, err := consumeMessage(b, m, wtyp, opts)
return v, out, err
}
func isInitMessageValue(v pref.Value) error {
m := v.Message().Interface()
return proto.CheckInitialized(m)
}
var coderMessageValue = valueCoderFuncs{
size: sizeMessageValue,
marshal: appendMessageValue,
unmarshal: consumeMessageValue,
isInit: isInitMessageValue,
merge: mergeMessageValue,
}
func sizeGroupValue(v pref.Value, tagsize int, opts marshalOptions) int {
m := v.Message().Interface()
return sizeGroup(m, tagsize, opts)
}
func appendGroupValue(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
m := v.Message().Interface()
return appendGroup(b, m, wiretag, opts)
}
func consumeGroupValue(b []byte, v pref.Value, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (pref.Value, unmarshalOutput, error) {
m := v.Message().Interface()
out, err := consumeGroup(b, m, num, wtyp, opts)
return v, out, err
}
var coderGroupValue = valueCoderFuncs{
size: sizeGroupValue,
marshal: appendGroupValue,
unmarshal: consumeGroupValue,
isInit: isInitMessageValue,
merge: mergeMessageValue,
}
func makeGroupFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
num := fd.Number()
if mi := getMessageInfo(ft); mi != nil {
funcs := pointerCoderFuncs{
size: sizeGroupType,
marshal: appendGroupType,
unmarshal: consumeGroupType,
merge: mergeMessage,
}
if needsInitCheck(mi.Desc) {
funcs.isInit = isInitMessageInfo
}
return funcs
} else {
return pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
m := asMessage(p.AsValueOf(ft).Elem())
return sizeGroup(m, f.tagsize, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
m := asMessage(p.AsValueOf(ft).Elem())
return appendGroup(b, m, f.wiretag, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
mp := p.AsValueOf(ft).Elem()
if mp.IsNil() {
mp.Set(reflect.New(ft.Elem()))
}
return consumeGroup(b, asMessage(mp), num, wtyp, opts)
},
isInit: func(p pointer, f *coderFieldInfo) error {
m := asMessage(p.AsValueOf(ft).Elem())
return proto.CheckInitialized(m)
},
merge: mergeMessage,
}
}
}
func sizeGroupType(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return 2*f.tagsize + f.mi.sizePointer(p.Elem(), opts)
}
func appendGroupType(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
b = protowire.AppendVarint(b, f.wiretag) // start group
b, err := f.mi.marshalAppendPointer(b, p.Elem(), opts)
b = protowire.AppendVarint(b, f.wiretag+1) // end group
return b, err
}
func consumeGroupType(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.StartGroupType {
return out, errUnknown
}
if p.Elem().IsNil() {
p.SetPointer(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())))
}
return f.mi.unmarshalPointer(b, p.Elem(), f.num, opts)
}
func sizeGroup(m proto.Message, tagsize int, _ marshalOptions) int {
return 2*tagsize + proto.Size(m)
}
func appendGroup(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
b = protowire.AppendVarint(b, wiretag) // start group
b, err := opts.Options().MarshalAppend(b, m)
b = protowire.AppendVarint(b, wiretag+1) // end group
return b, err
}
func consumeGroup(b []byte, m proto.Message, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.StartGroupType {
return out, errUnknown
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return out, protowire.ParseError(n)
}
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: b,
Message: m.ProtoReflect(),
})
if err != nil {
return out, err
}
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return out, nil
}
func makeMessageSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
if mi := getMessageInfo(ft); mi != nil {
funcs := pointerCoderFuncs{
size: sizeMessageSliceInfo,
marshal: appendMessageSliceInfo,
unmarshal: consumeMessageSliceInfo,
merge: mergeMessageSlice,
}
if needsInitCheck(mi.Desc) {
funcs.isInit = isInitMessageSliceInfo
}
return funcs
}
return pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return sizeMessageSlice(p, ft, f.tagsize, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
return appendMessageSlice(b, p, f.wiretag, ft, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
return consumeMessageSlice(b, p, ft, wtyp, opts)
},
isInit: func(p pointer, f *coderFieldInfo) error {
return isInitMessageSlice(p, ft)
},
merge: mergeMessageSlice,
}
}
func sizeMessageSliceInfo(p pointer, f *coderFieldInfo, opts marshalOptions) int {
s := p.PointerSlice()
n := 0
for _, v := range s {
n += protowire.SizeBytes(f.mi.sizePointer(v, opts)) + f.tagsize
}
return n
}
func appendMessageSliceInfo(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
s := p.PointerSlice()
var err error
for _, v := range s {
b = protowire.AppendVarint(b, f.wiretag)
siz := f.mi.sizePointer(v, opts)
b = protowire.AppendVarint(b, uint64(siz))
b, err = f.mi.marshalAppendPointer(b, v, opts)
if err != nil {
return b, err
}
}
return b, nil
}
func consumeMessageSliceInfo(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
m := reflect.New(f.mi.GoReflectType.Elem()).Interface()
mp := pointerOfIface(m)
o, err := f.mi.unmarshalPointer(v, mp, 0, opts)
if err != nil {
return out, err
}
p.AppendPointerSlice(mp)
out.n = n
out.initialized = o.initialized
return out, nil
}
func isInitMessageSliceInfo(p pointer, f *coderFieldInfo) error {
s := p.PointerSlice()
for _, v := range s {
if err := f.mi.checkInitializedPointer(v); err != nil {
return err
}
}
return nil
}
func sizeMessageSlice(p pointer, goType reflect.Type, tagsize int, _ marshalOptions) int {
s := p.PointerSlice()
n := 0
for _, v := range s {
m := asMessage(v.AsValueOf(goType.Elem()))
n += protowire.SizeBytes(proto.Size(m)) + tagsize
}
return n
}
func appendMessageSlice(b []byte, p pointer, wiretag uint64, goType reflect.Type, opts marshalOptions) ([]byte, error) {
s := p.PointerSlice()
var err error
for _, v := range s {
m := asMessage(v.AsValueOf(goType.Elem()))
b = protowire.AppendVarint(b, wiretag)
siz := proto.Size(m)
b = protowire.AppendVarint(b, uint64(siz))
b, err = opts.Options().MarshalAppend(b, m)
if err != nil {
return b, err
}
}
return b, nil
}
func consumeMessageSlice(b []byte, p pointer, goType reflect.Type, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
mp := reflect.New(goType.Elem())
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: v,
Message: asMessage(mp).ProtoReflect(),
})
if err != nil {
return out, err
}
p.AppendPointerSlice(pointerOfValue(mp))
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return out, nil
}
func isInitMessageSlice(p pointer, goType reflect.Type) error {
s := p.PointerSlice()
for _, v := range s {
m := asMessage(v.AsValueOf(goType.Elem()))
if err := proto.CheckInitialized(m); err != nil {
return err
}
}
return nil
}
// Slices of messages
func sizeMessageSliceValue(listv pref.Value, tagsize int, opts marshalOptions) int {
list := listv.List()
n := 0
for i, llen := 0, list.Len(); i < llen; i++ {
m := list.Get(i).Message().Interface()
n += protowire.SizeBytes(proto.Size(m)) + tagsize
}
return n
}
func appendMessageSliceValue(b []byte, listv pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
list := listv.List()
mopts := opts.Options()
for i, llen := 0, list.Len(); i < llen; i++ {
m := list.Get(i).Message().Interface()
b = protowire.AppendVarint(b, wiretag)
siz := proto.Size(m)
b = protowire.AppendVarint(b, uint64(siz))
var err error
b, err = mopts.MarshalAppend(b, m)
if err != nil {
return b, err
}
}
return b, nil
}
func consumeMessageSliceValue(b []byte, listv pref.Value, _ protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (_ pref.Value, out unmarshalOutput, err error) {
list := listv.List()
if wtyp != protowire.BytesType {
return pref.Value{}, out, errUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return pref.Value{}, out, protowire.ParseError(n)
}
m := list.NewElement()
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: v,
Message: m.Message(),
})
if err != nil {
return pref.Value{}, out, err
}
list.Append(m)
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return listv, out, nil
}
func isInitMessageSliceValue(listv pref.Value) error {
list := listv.List()
for i, llen := 0, list.Len(); i < llen; i++ {
m := list.Get(i).Message().Interface()
if err := proto.CheckInitialized(m); err != nil {
return err
}
}
return nil
}
var coderMessageSliceValue = valueCoderFuncs{
size: sizeMessageSliceValue,
marshal: appendMessageSliceValue,
unmarshal: consumeMessageSliceValue,
isInit: isInitMessageSliceValue,
merge: mergeMessageListValue,
}
func sizeGroupSliceValue(listv pref.Value, tagsize int, opts marshalOptions) int {
list := listv.List()
n := 0
for i, llen := 0, list.Len(); i < llen; i++ {
m := list.Get(i).Message().Interface()
n += 2*tagsize + proto.Size(m)
}
return n
}
func appendGroupSliceValue(b []byte, listv pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
list := listv.List()
mopts := opts.Options()
for i, llen := 0, list.Len(); i < llen; i++ {
m := list.Get(i).Message().Interface()
b = protowire.AppendVarint(b, wiretag) // start group
var err error
b, err = mopts.MarshalAppend(b, m)
if err != nil {
return b, err
}
b = protowire.AppendVarint(b, wiretag+1) // end group
}
return b, nil
}
func consumeGroupSliceValue(b []byte, listv pref.Value, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (_ pref.Value, out unmarshalOutput, err error) {
list := listv.List()
if wtyp != protowire.StartGroupType {
return pref.Value{}, out, errUnknown
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return pref.Value{}, out, protowire.ParseError(n)
}
m := list.NewElement()
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: b,
Message: m.Message(),
})
if err != nil {
return pref.Value{}, out, err
}
list.Append(m)
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return listv, out, nil
}
var coderGroupSliceValue = valueCoderFuncs{
size: sizeGroupSliceValue,
marshal: appendGroupSliceValue,
unmarshal: consumeGroupSliceValue,
isInit: isInitMessageSliceValue,
merge: mergeMessageListValue,
}
func makeGroupSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
num := fd.Number()
if mi := getMessageInfo(ft); mi != nil {
funcs := pointerCoderFuncs{
size: sizeGroupSliceInfo,
marshal: appendGroupSliceInfo,
unmarshal: consumeGroupSliceInfo,
merge: mergeMessageSlice,
}
if needsInitCheck(mi.Desc) {
funcs.isInit = isInitMessageSliceInfo
}
return funcs
}
return pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return sizeGroupSlice(p, ft, f.tagsize, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
return appendGroupSlice(b, p, f.wiretag, ft, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
return consumeGroupSlice(b, p, num, wtyp, ft, opts)
},
isInit: func(p pointer, f *coderFieldInfo) error {
return isInitMessageSlice(p, ft)
},
merge: mergeMessageSlice,
}
}
func sizeGroupSlice(p pointer, messageType reflect.Type, tagsize int, _ marshalOptions) int {
s := p.PointerSlice()
n := 0
for _, v := range s {
m := asMessage(v.AsValueOf(messageType.Elem()))
n += 2*tagsize + proto.Size(m)
}
return n
}
func appendGroupSlice(b []byte, p pointer, wiretag uint64, messageType reflect.Type, opts marshalOptions) ([]byte, error) {
s := p.PointerSlice()
var err error
for _, v := range s {
m := asMessage(v.AsValueOf(messageType.Elem()))
b = protowire.AppendVarint(b, wiretag) // start group
b, err = opts.Options().MarshalAppend(b, m)
if err != nil {
return b, err
}
b = protowire.AppendVarint(b, wiretag+1) // end group
}
return b, nil
}
func consumeGroupSlice(b []byte, p pointer, num protowire.Number, wtyp protowire.Type, goType reflect.Type, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.StartGroupType {
return out, errUnknown
}
b, n := protowire.ConsumeGroup(num, b)
if n < 0 {
return out, protowire.ParseError(n)
}
mp := reflect.New(goType.Elem())
o, err := opts.Options().UnmarshalState(piface.UnmarshalInput{
Buf: b,
Message: asMessage(mp).ProtoReflect(),
})
if err != nil {
return out, err
}
p.AppendPointerSlice(pointerOfValue(mp))
out.n = n
out.initialized = o.Flags&piface.UnmarshalInitialized != 0
return out, nil
}
func sizeGroupSliceInfo(p pointer, f *coderFieldInfo, opts marshalOptions) int {
s := p.PointerSlice()
n := 0
for _, v := range s {
n += 2*f.tagsize + f.mi.sizePointer(v, opts)
}
return n
}
func appendGroupSliceInfo(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
s := p.PointerSlice()
var err error
for _, v := range s {
b = protowire.AppendVarint(b, f.wiretag) // start group
b, err = f.mi.marshalAppendPointer(b, v, opts)
if err != nil {
return b, err
}
b = protowire.AppendVarint(b, f.wiretag+1) // end group
}
return b, nil
}
func consumeGroupSliceInfo(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
if wtyp != protowire.StartGroupType {
return unmarshalOutput{}, errUnknown
}
m := reflect.New(f.mi.GoReflectType.Elem()).Interface()
mp := pointerOfIface(m)
out, err := f.mi.unmarshalPointer(b, mp, f.num, opts)
if err != nil {
return out, err
}
p.AppendPointerSlice(mp)
return out, nil
}
func asMessage(v reflect.Value) pref.ProtoMessage {
if m, ok := v.Interface().(pref.ProtoMessage); ok {
return m
}
return legacyWrapMessage(v).Interface()
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,389 @@
// 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 impl
import (
"errors"
"reflect"
"sort"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/genid"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type mapInfo struct {
goType reflect.Type
keyWiretag uint64
valWiretag uint64
keyFuncs valueCoderFuncs
valFuncs valueCoderFuncs
keyZero pref.Value
keyKind pref.Kind
conv *mapConverter
}
func encoderFuncsForMap(fd pref.FieldDescriptor, ft reflect.Type) (valueMessage *MessageInfo, funcs pointerCoderFuncs) {
// TODO: Consider generating specialized map coders.
keyField := fd.MapKey()
valField := fd.MapValue()
keyWiretag := protowire.EncodeTag(1, wireTypes[keyField.Kind()])
valWiretag := protowire.EncodeTag(2, wireTypes[valField.Kind()])
keyFuncs := encoderFuncsForValue(keyField)
valFuncs := encoderFuncsForValue(valField)
conv := newMapConverter(ft, fd)
mapi := &mapInfo{
goType: ft,
keyWiretag: keyWiretag,
valWiretag: valWiretag,
keyFuncs: keyFuncs,
valFuncs: valFuncs,
keyZero: keyField.Default(),
keyKind: keyField.Kind(),
conv: conv,
}
if valField.Kind() == pref.MessageKind {
valueMessage = getMessageInfo(ft.Elem())
}
funcs = pointerCoderFuncs{
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
return sizeMap(p.AsValueOf(ft).Elem(), mapi, f, opts)
},
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
return appendMap(b, p.AsValueOf(ft).Elem(), mapi, f, opts)
},
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
mp := p.AsValueOf(ft)
if mp.Elem().IsNil() {
mp.Elem().Set(reflect.MakeMap(mapi.goType))
}
if f.mi == nil {
return consumeMap(b, mp.Elem(), wtyp, mapi, f, opts)
} else {
return consumeMapOfMessage(b, mp.Elem(), wtyp, mapi, f, opts)
}
},
}
switch valField.Kind() {
case pref.MessageKind:
funcs.merge = mergeMapOfMessage
case pref.BytesKind:
funcs.merge = mergeMapOfBytes
default:
funcs.merge = mergeMap
}
if valFuncs.isInit != nil {
funcs.isInit = func(p pointer, f *coderFieldInfo) error {
return isInitMap(p.AsValueOf(ft).Elem(), mapi, f)
}
}
return valueMessage, funcs
}
const (
mapKeyTagSize = 1 // field 1, tag size 1.
mapValTagSize = 1 // field 2, tag size 2.
)
func sizeMap(mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalOptions) int {
if mapv.Len() == 0 {
return 0
}
n := 0
iter := mapRange(mapv)
for iter.Next() {
key := mapi.conv.keyConv.PBValueOf(iter.Key()).MapKey()
keySize := mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts)
var valSize int
value := mapi.conv.valConv.PBValueOf(iter.Value())
if f.mi == nil {
valSize = mapi.valFuncs.size(value, mapValTagSize, opts)
} else {
p := pointerOfValue(iter.Value())
valSize += mapValTagSize
valSize += protowire.SizeBytes(f.mi.sizePointer(p, opts))
}
n += f.tagsize + protowire.SizeBytes(keySize+valSize)
}
return n
}
func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
var (
key = mapi.keyZero
val = mapi.conv.valConv.New()
)
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return out, protowire.ParseError(n)
}
if num > protowire.MaxValidNumber {
return out, errors.New("invalid field number")
}
b = b[n:]
err := errUnknown
switch num {
case genid.MapEntry_Key_field_number:
var v pref.Value
var o unmarshalOutput
v, o, err = mapi.keyFuncs.unmarshal(b, key, num, wtyp, opts)
if err != nil {
break
}
key = v
n = o.n
case genid.MapEntry_Value_field_number:
var v pref.Value
var o unmarshalOutput
v, o, err = mapi.valFuncs.unmarshal(b, val, num, wtyp, opts)
if err != nil {
break
}
val = v
n = o.n
}
if err == errUnknown {
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
}
} else if err != nil {
return out, err
}
b = b[n:]
}
mapv.SetMapIndex(mapi.conv.keyConv.GoValueOf(key), mapi.conv.valConv.GoValueOf(val))
out.n = n
return out, nil
}
func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.BytesType {
return out, errUnknown
}
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
var (
key = mapi.keyZero
val = reflect.New(f.mi.GoReflectType.Elem())
)
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return out, protowire.ParseError(n)
}
if num > protowire.MaxValidNumber {
return out, errors.New("invalid field number")
}
b = b[n:]
err := errUnknown
switch num {
case 1:
var v pref.Value
var o unmarshalOutput
v, o, err = mapi.keyFuncs.unmarshal(b, key, num, wtyp, opts)
if err != nil {
break
}
key = v
n = o.n
case 2:
if wtyp != protowire.BytesType {
break
}
var v []byte
v, n = protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
var o unmarshalOutput
o, err = f.mi.unmarshalPointer(v, pointerOfValue(val), 0, opts)
if o.initialized {
// Consider this map item initialized so long as we see
// an initialized value.
out.initialized = true
}
}
if err == errUnknown {
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
}
} else if err != nil {
return out, err
}
b = b[n:]
}
mapv.SetMapIndex(mapi.conv.keyConv.GoValueOf(key), val)
out.n = n
return out, nil
}
func appendMapItem(b []byte, keyrv, valrv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
if f.mi == nil {
key := mapi.conv.keyConv.PBValueOf(keyrv).MapKey()
val := mapi.conv.valConv.PBValueOf(valrv)
size := 0
size += mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts)
size += mapi.valFuncs.size(val, mapValTagSize, opts)
b = protowire.AppendVarint(b, uint64(size))
b, err := mapi.keyFuncs.marshal(b, key.Value(), mapi.keyWiretag, opts)
if err != nil {
return nil, err
}
return mapi.valFuncs.marshal(b, val, mapi.valWiretag, opts)
} else {
key := mapi.conv.keyConv.PBValueOf(keyrv).MapKey()
val := pointerOfValue(valrv)
valSize := f.mi.sizePointer(val, opts)
size := 0
size += mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts)
size += mapValTagSize + protowire.SizeBytes(valSize)
b = protowire.AppendVarint(b, uint64(size))
b, err := mapi.keyFuncs.marshal(b, key.Value(), mapi.keyWiretag, opts)
if err != nil {
return nil, err
}
b = protowire.AppendVarint(b, mapi.valWiretag)
b = protowire.AppendVarint(b, uint64(valSize))
return f.mi.marshalAppendPointer(b, val, opts)
}
}
func appendMap(b []byte, mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
if mapv.Len() == 0 {
return b, nil
}
if opts.Deterministic() {
return appendMapDeterministic(b, mapv, mapi, f, opts)
}
iter := mapRange(mapv)
for iter.Next() {
var err error
b = protowire.AppendVarint(b, f.wiretag)
b, err = appendMapItem(b, iter.Key(), iter.Value(), mapi, f, opts)
if err != nil {
return b, err
}
}
return b, nil
}
func appendMapDeterministic(b []byte, mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
keys := mapv.MapKeys()
sort.Slice(keys, func(i, j int) bool {
switch keys[i].Kind() {
case reflect.Bool:
return !keys[i].Bool() && keys[j].Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return keys[i].Int() < keys[j].Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return keys[i].Uint() < keys[j].Uint()
case reflect.Float32, reflect.Float64:
return keys[i].Float() < keys[j].Float()
case reflect.String:
return keys[i].String() < keys[j].String()
default:
panic("invalid kind: " + keys[i].Kind().String())
}
})
for _, key := range keys {
var err error
b = protowire.AppendVarint(b, f.wiretag)
b, err = appendMapItem(b, key, mapv.MapIndex(key), mapi, f, opts)
if err != nil {
return b, err
}
}
return b, nil
}
func isInitMap(mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo) error {
if mi := f.mi; mi != nil {
mi.init()
if !mi.needsInitCheck {
return nil
}
iter := mapRange(mapv)
for iter.Next() {
val := pointerOfValue(iter.Value())
if err := mi.checkInitializedPointer(val); err != nil {
return err
}
}
} else {
iter := mapRange(mapv)
for iter.Next() {
val := mapi.conv.valConv.PBValueOf(iter.Value())
if err := mapi.valFuncs.isInit(val); err != nil {
return err
}
}
}
return nil
}
func mergeMap(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
dstm := dst.AsValueOf(f.ft).Elem()
srcm := src.AsValueOf(f.ft).Elem()
if srcm.Len() == 0 {
return
}
if dstm.IsNil() {
dstm.Set(reflect.MakeMap(f.ft))
}
iter := mapRange(srcm)
for iter.Next() {
dstm.SetMapIndex(iter.Key(), iter.Value())
}
}
func mergeMapOfBytes(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
dstm := dst.AsValueOf(f.ft).Elem()
srcm := src.AsValueOf(f.ft).Elem()
if srcm.Len() == 0 {
return
}
if dstm.IsNil() {
dstm.Set(reflect.MakeMap(f.ft))
}
iter := mapRange(srcm)
for iter.Next() {
dstm.SetMapIndex(iter.Key(), reflect.ValueOf(append(emptyBuf[:], iter.Value().Bytes()...)))
}
}
func mergeMapOfMessage(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
dstm := dst.AsValueOf(f.ft).Elem()
srcm := src.AsValueOf(f.ft).Elem()
if srcm.Len() == 0 {
return
}
if dstm.IsNil() {
dstm.Set(reflect.MakeMap(f.ft))
}
iter := mapRange(srcm)
for iter.Next() {
val := reflect.New(f.ft.Elem().Elem())
if f.mi != nil {
f.mi.mergePointer(pointerOfValue(val), pointerOfValue(iter.Value()), opts)
} else {
opts.Merge(asMessage(val), asMessage(iter.Value()))
}
dstm.SetMapIndex(iter.Key(), val)
}
}

View File

@ -0,0 +1,37 @@
// 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.
// +build !go1.12
package impl
import "reflect"
type mapIter struct {
v reflect.Value
keys []reflect.Value
}
// mapRange provides a less-efficient equivalent to
// the Go 1.12 reflect.Value.MapRange method.
func mapRange(v reflect.Value) *mapIter {
return &mapIter{v: v}
}
func (i *mapIter) Next() bool {
if i.keys == nil {
i.keys = i.v.MapKeys()
} else {
i.keys = i.keys[1:]
}
return len(i.keys) > 0
}
func (i *mapIter) Key() reflect.Value {
return i.keys[0]
}
func (i *mapIter) Value() reflect.Value {
return i.v.MapIndex(i.keys[0])
}

View File

@ -0,0 +1,11 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.12
package impl
import "reflect"
func mapRange(v reflect.Value) *reflect.MapIter { return v.MapRange() }

View File

@ -0,0 +1,159 @@
// 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 impl
import (
"fmt"
"reflect"
"sort"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/fieldsort"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
// coderMessageInfo contains per-message information used by the fast-path functions.
// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
// possible.
type coderMessageInfo struct {
methods piface.Methods
orderedCoderFields []*coderFieldInfo
denseCoderFields []*coderFieldInfo
coderFields map[protowire.Number]*coderFieldInfo
sizecacheOffset offset
unknownOffset offset
extensionOffset offset
needsInitCheck bool
isMessageSet bool
numRequiredFields uint8
}
type coderFieldInfo struct {
funcs pointerCoderFuncs // fast-path per-field functions
mi *MessageInfo // field's message
ft reflect.Type
validation validationInfo // information used by message validation
num pref.FieldNumber // field number
offset offset // struct field offset
wiretag uint64 // field tag (number + wire type)
tagsize int // size of the varint-encoded tag
isPointer bool // true if IsNil may be called on the struct field
isRequired bool // true if field is required
}
func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
mi.sizecacheOffset = si.sizecacheOffset
mi.unknownOffset = si.unknownOffset
mi.extensionOffset = si.extensionOffset
mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
fields := mi.Desc.Fields()
preallocFields := make([]coderFieldInfo, fields.Len())
for i := 0; i < fields.Len(); i++ {
fd := fields.Get(i)
fs := si.fieldsByNumber[fd.Number()]
isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
if isOneof {
fs = si.oneofsByName[fd.ContainingOneof().Name()]
}
ft := fs.Type
var wiretag uint64
if !fd.IsPacked() {
wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
} else {
wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType)
}
var fieldOffset offset
var funcs pointerCoderFuncs
var childMessage *MessageInfo
switch {
case isOneof:
fieldOffset = offsetOf(fs, mi.Exporter)
case fd.IsWeak():
fieldOffset = si.weakOffset
funcs = makeWeakMessageFieldCoder(fd)
default:
fieldOffset = offsetOf(fs, mi.Exporter)
childMessage, funcs = fieldCoder(fd, ft)
}
cf := &preallocFields[i]
*cf = coderFieldInfo{
num: fd.Number(),
offset: fieldOffset,
wiretag: wiretag,
ft: ft,
tagsize: protowire.SizeVarint(wiretag),
funcs: funcs,
mi: childMessage,
validation: newFieldValidationInfo(mi, si, fd, ft),
isPointer: fd.Cardinality() == pref.Repeated || fd.HasPresence(),
isRequired: fd.Cardinality() == pref.Required,
}
mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
mi.coderFields[cf.num] = cf
}
for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
if od := oneofs.Get(i); !od.IsSynthetic() {
mi.initOneofFieldCoders(od, si)
}
}
if messageset.IsMessageSet(mi.Desc) {
if !mi.extensionOffset.IsValid() {
panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
}
if !mi.unknownOffset.IsValid() {
panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName()))
}
mi.isMessageSet = true
}
sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
})
var maxDense pref.FieldNumber
for _, cf := range mi.orderedCoderFields {
if cf.num >= 16 && cf.num >= 2*maxDense {
break
}
maxDense = cf.num
}
mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
for _, cf := range mi.orderedCoderFields {
if int(cf.num) >= len(mi.denseCoderFields) {
break
}
mi.denseCoderFields[cf.num] = cf
}
// To preserve compatibility with historic wire output, marshal oneofs last.
if mi.Desc.Oneofs().Len() > 0 {
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)
})
}
mi.needsInitCheck = needsInitCheck(mi.Desc)
if mi.methods.Marshal == nil && mi.methods.Size == nil {
mi.methods.Flags |= piface.SupportMarshalDeterministic
mi.methods.Marshal = mi.marshal
mi.methods.Size = mi.size
}
if mi.methods.Unmarshal == nil {
mi.methods.Flags |= piface.SupportUnmarshalDiscardUnknown
mi.methods.Unmarshal = mi.unmarshal
}
if mi.methods.CheckInitialized == nil {
mi.methods.CheckInitialized = mi.checkInitialized
}
if mi.methods.Merge == nil {
mi.methods.Merge = mi.merge
}
}

View File

@ -0,0 +1,120 @@
// 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 impl
import (
"sort"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
)
func sizeMessageSet(mi *MessageInfo, p pointer, opts marshalOptions) (size int) {
if !flags.ProtoLegacy {
return 0
}
ext := *p.Apply(mi.extensionOffset).Extensions()
for _, x := range ext {
xi := getExtensionFieldInfo(x.Type())
if xi.funcs.size == nil {
continue
}
num, _ := protowire.DecodeTag(xi.wiretag)
size += messageset.SizeField(num)
size += xi.funcs.size(x.Value(), protowire.SizeTag(messageset.FieldMessage), opts)
}
unknown := *p.Apply(mi.unknownOffset).Bytes()
size += messageset.SizeUnknown(unknown)
return size
}
func marshalMessageSet(mi *MessageInfo, b []byte, p pointer, opts marshalOptions) ([]byte, error) {
if !flags.ProtoLegacy {
return b, errors.New("no support for message_set_wire_format")
}
ext := *p.Apply(mi.extensionOffset).Extensions()
switch len(ext) {
case 0:
case 1:
// Fast-path for one extension: Don't bother sorting the keys.
for _, x := range ext {
var err error
b, err = marshalMessageSetField(mi, b, x, opts)
if err != nil {
return b, err
}
}
default:
// Sort the keys to provide a deterministic encoding.
// Not sure this is required, but the old code does it.
keys := make([]int, 0, len(ext))
for k := range ext {
keys = append(keys, int(k))
}
sort.Ints(keys)
for _, k := range keys {
var err error
b, err = marshalMessageSetField(mi, b, ext[int32(k)], opts)
if err != nil {
return b, err
}
}
}
unknown := *p.Apply(mi.unknownOffset).Bytes()
b, err := messageset.AppendUnknown(b, unknown)
if err != nil {
return b, err
}
return b, nil
}
func marshalMessageSetField(mi *MessageInfo, b []byte, x ExtensionField, opts marshalOptions) ([]byte, error) {
xi := getExtensionFieldInfo(x.Type())
num, _ := protowire.DecodeTag(xi.wiretag)
b = messageset.AppendFieldStart(b, num)
b, err := xi.funcs.marshal(b, x.Value(), protowire.EncodeTag(messageset.FieldMessage, protowire.BytesType), opts)
if err != nil {
return b, err
}
b = messageset.AppendFieldEnd(b)
return b, nil
}
func unmarshalMessageSet(mi *MessageInfo, b []byte, p pointer, opts unmarshalOptions) (out unmarshalOutput, err error) {
if !flags.ProtoLegacy {
return out, errors.New("no support for message_set_wire_format")
}
ep := p.Apply(mi.extensionOffset).Extensions()
if *ep == nil {
*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...)
return nil
}
if !o.initialized {
initialized = false
}
return err
})
out.n = len(b)
out.initialized = initialized
return out, err
}

View File

@ -0,0 +1,209 @@
// 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.
// +build purego appengine
package impl
import (
"reflect"
"google.golang.org/protobuf/encoding/protowire"
)
func sizeEnum(p pointer, f *coderFieldInfo, _ marshalOptions) (size int) {
v := p.v.Elem().Int()
return f.tagsize + protowire.SizeVarint(uint64(v))
}
func appendEnum(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
v := p.v.Elem().Int()
b = protowire.AppendVarint(b, f.wiretag)
b = protowire.AppendVarint(b, uint64(v))
return b, nil
}
func consumeEnum(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, _ unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.VarintType {
return out, errUnknown
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
}
p.v.Elem().SetInt(int64(v))
out.n = n
return out, nil
}
func mergeEnum(dst, src pointer, _ *coderFieldInfo, _ mergeOptions) {
dst.v.Elem().Set(src.v.Elem())
}
var coderEnum = pointerCoderFuncs{
size: sizeEnum,
marshal: appendEnum,
unmarshal: consumeEnum,
merge: mergeEnum,
}
func sizeEnumNoZero(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) {
if p.v.Elem().Int() == 0 {
return 0
}
return sizeEnum(p, f, opts)
}
func appendEnumNoZero(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
if p.v.Elem().Int() == 0 {
return b, nil
}
return appendEnum(b, p, f, opts)
}
func mergeEnumNoZero(dst, src pointer, _ *coderFieldInfo, _ mergeOptions) {
if src.v.Elem().Int() != 0 {
dst.v.Elem().Set(src.v.Elem())
}
}
var coderEnumNoZero = pointerCoderFuncs{
size: sizeEnumNoZero,
marshal: appendEnumNoZero,
unmarshal: consumeEnum,
merge: mergeEnumNoZero,
}
func sizeEnumPtr(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) {
return sizeEnum(pointer{p.v.Elem()}, f, opts)
}
func appendEnumPtr(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
return appendEnum(b, pointer{p.v.Elem()}, f, opts)
}
func consumeEnumPtr(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
if wtyp != protowire.VarintType {
return out, errUnknown
}
if p.v.Elem().IsNil() {
p.v.Elem().Set(reflect.New(p.v.Elem().Type().Elem()))
}
return consumeEnum(b, pointer{p.v.Elem()}, wtyp, f, opts)
}
func mergeEnumPtr(dst, src pointer, _ *coderFieldInfo, _ mergeOptions) {
if !src.v.Elem().IsNil() {
v := reflect.New(dst.v.Type().Elem().Elem())
v.Elem().Set(src.v.Elem().Elem())
dst.v.Elem().Set(v)
}
}
var coderEnumPtr = pointerCoderFuncs{
size: sizeEnumPtr,
marshal: appendEnumPtr,
unmarshal: consumeEnumPtr,
merge: mergeEnumPtr,
}
func sizeEnumSlice(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) {
s := p.v.Elem()
for i, llen := 0, s.Len(); i < llen; i++ {
size += protowire.SizeVarint(uint64(s.Index(i).Int())) + f.tagsize
}
return size
}
func appendEnumSlice(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
s := p.v.Elem()
for i, llen := 0, s.Len(); i < llen; i++ {
b = protowire.AppendVarint(b, f.wiretag)
b = protowire.AppendVarint(b, uint64(s.Index(i).Int()))
}
return b, nil
}
func consumeEnumSlice(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
s := p.v.Elem()
if wtyp == protowire.BytesType {
b, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, protowire.ParseError(n)
}
for len(b) > 0 {
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
}
rv := reflect.New(s.Type().Elem()).Elem()
rv.SetInt(int64(v))
s.Set(reflect.Append(s, rv))
b = b[n:]
}
out.n = n
return out, nil
}
if wtyp != protowire.VarintType {
return out, errUnknown
}
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
}
rv := reflect.New(s.Type().Elem()).Elem()
rv.SetInt(int64(v))
s.Set(reflect.Append(s, rv))
out.n = n
return out, nil
}
func mergeEnumSlice(dst, src pointer, _ *coderFieldInfo, _ mergeOptions) {
dst.v.Elem().Set(reflect.AppendSlice(dst.v.Elem(), src.v.Elem()))
}
var coderEnumSlice = pointerCoderFuncs{
size: sizeEnumSlice,
marshal: appendEnumSlice,
unmarshal: consumeEnumSlice,
merge: mergeEnumSlice,
}
func sizeEnumPackedSlice(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) {
s := p.v.Elem()
llen := s.Len()
if llen == 0 {
return 0
}
n := 0
for i := 0; i < llen; i++ {
n += protowire.SizeVarint(uint64(s.Index(i).Int()))
}
return f.tagsize + protowire.SizeBytes(n)
}
func appendEnumPackedSlice(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
s := p.v.Elem()
llen := s.Len()
if llen == 0 {
return b, nil
}
b = protowire.AppendVarint(b, f.wiretag)
n := 0
for i := 0; i < llen; i++ {
n += protowire.SizeVarint(uint64(s.Index(i).Int()))
}
b = protowire.AppendVarint(b, uint64(n))
for i := 0; i < llen; i++ {
b = protowire.AppendVarint(b, uint64(s.Index(i).Int()))
}
return b, nil
}
var coderEnumPackedSlice = pointerCoderFuncs{
size: sizeEnumPackedSlice,
marshal: appendEnumPackedSlice,
unmarshal: consumeEnumSlice,
merge: mergeEnumSlice,
}

View File

@ -0,0 +1,557 @@
// 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 impl
import (
"fmt"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/strs"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// pointerCoderFuncs is a set of pointer encoding functions.
type pointerCoderFuncs struct {
mi *MessageInfo
size func(p pointer, f *coderFieldInfo, opts marshalOptions) int
marshal func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error)
unmarshal func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error)
isInit func(p pointer, f *coderFieldInfo) error
merge func(dst, src pointer, f *coderFieldInfo, opts mergeOptions)
}
// valueCoderFuncs is a set of protoreflect.Value encoding functions.
type valueCoderFuncs struct {
size func(v pref.Value, tagsize int, opts marshalOptions) int
marshal func(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error)
unmarshal func(b []byte, v pref.Value, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (pref.Value, unmarshalOutput, error)
isInit func(v pref.Value) error
merge func(dst, src pref.Value, opts mergeOptions) pref.Value
}
// fieldCoder returns pointer functions for a field, used for operating on
// struct fields.
func fieldCoder(fd pref.FieldDescriptor, ft reflect.Type) (*MessageInfo, pointerCoderFuncs) {
switch {
case fd.IsMap():
return encoderFuncsForMap(fd, ft)
case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
// Repeated fields (not packed).
if ft.Kind() != reflect.Slice {
break
}
ft := ft.Elem()
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
return nil, coderBoolSlice
}
case pref.EnumKind:
if ft.Kind() == reflect.Int32 {
return nil, coderEnumSlice
}
case pref.Int32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderInt32Slice
}
case pref.Sint32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSint32Slice
}
case pref.Uint32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderUint32Slice
}
case pref.Int64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderInt64Slice
}
case pref.Sint64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSint64Slice
}
case pref.Uint64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderUint64Slice
}
case pref.Sfixed32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSfixed32Slice
}
case pref.Fixed32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderFixed32Slice
}
case pref.FloatKind:
if ft.Kind() == reflect.Float32 {
return nil, coderFloatSlice
}
case pref.Sfixed64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSfixed64Slice
}
case pref.Fixed64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderFixed64Slice
}
case pref.DoubleKind:
if ft.Kind() == reflect.Float64 {
return nil, coderDoubleSlice
}
case pref.StringKind:
if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) {
return nil, coderStringSliceValidateUTF8
}
if ft.Kind() == reflect.String {
return nil, coderStringSlice
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) {
return nil, coderBytesSliceValidateUTF8
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytesSlice
}
case pref.BytesKind:
if ft.Kind() == reflect.String {
return nil, coderStringSlice
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytesSlice
}
case pref.MessageKind:
return getMessageInfo(ft), makeMessageSliceFieldCoder(fd, ft)
case pref.GroupKind:
return getMessageInfo(ft), makeGroupSliceFieldCoder(fd, ft)
}
case fd.Cardinality() == pref.Repeated && fd.IsPacked():
// Packed repeated fields.
//
// Only repeated fields of primitive numeric types
// (Varint, Fixed32, or Fixed64 wire type) can be packed.
if ft.Kind() != reflect.Slice {
break
}
ft := ft.Elem()
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
return nil, coderBoolPackedSlice
}
case pref.EnumKind:
if ft.Kind() == reflect.Int32 {
return nil, coderEnumPackedSlice
}
case pref.Int32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderInt32PackedSlice
}
case pref.Sint32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSint32PackedSlice
}
case pref.Uint32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderUint32PackedSlice
}
case pref.Int64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderInt64PackedSlice
}
case pref.Sint64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSint64PackedSlice
}
case pref.Uint64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderUint64PackedSlice
}
case pref.Sfixed32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSfixed32PackedSlice
}
case pref.Fixed32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderFixed32PackedSlice
}
case pref.FloatKind:
if ft.Kind() == reflect.Float32 {
return nil, coderFloatPackedSlice
}
case pref.Sfixed64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSfixed64PackedSlice
}
case pref.Fixed64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderFixed64PackedSlice
}
case pref.DoubleKind:
if ft.Kind() == reflect.Float64 {
return nil, coderDoublePackedSlice
}
}
case fd.Kind() == pref.MessageKind:
return getMessageInfo(ft), makeMessageFieldCoder(fd, ft)
case fd.Kind() == pref.GroupKind:
return getMessageInfo(ft), makeGroupFieldCoder(fd, ft)
case fd.Syntax() == pref.Proto3 && fd.ContainingOneof() == nil:
// Populated oneof fields always encode even if set to the zero value,
// which normally are not encoded in proto3.
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
return nil, coderBoolNoZero
}
case pref.EnumKind:
if ft.Kind() == reflect.Int32 {
return nil, coderEnumNoZero
}
case pref.Int32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderInt32NoZero
}
case pref.Sint32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSint32NoZero
}
case pref.Uint32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderUint32NoZero
}
case pref.Int64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderInt64NoZero
}
case pref.Sint64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSint64NoZero
}
case pref.Uint64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderUint64NoZero
}
case pref.Sfixed32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSfixed32NoZero
}
case pref.Fixed32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderFixed32NoZero
}
case pref.FloatKind:
if ft.Kind() == reflect.Float32 {
return nil, coderFloatNoZero
}
case pref.Sfixed64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSfixed64NoZero
}
case pref.Fixed64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderFixed64NoZero
}
case pref.DoubleKind:
if ft.Kind() == reflect.Float64 {
return nil, coderDoubleNoZero
}
case pref.StringKind:
if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) {
return nil, coderStringNoZeroValidateUTF8
}
if ft.Kind() == reflect.String {
return nil, coderStringNoZero
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) {
return nil, coderBytesNoZeroValidateUTF8
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytesNoZero
}
case pref.BytesKind:
if ft.Kind() == reflect.String {
return nil, coderStringNoZero
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytesNoZero
}
}
case ft.Kind() == reflect.Ptr:
ft := ft.Elem()
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
return nil, coderBoolPtr
}
case pref.EnumKind:
if ft.Kind() == reflect.Int32 {
return nil, coderEnumPtr
}
case pref.Int32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderInt32Ptr
}
case pref.Sint32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSint32Ptr
}
case pref.Uint32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderUint32Ptr
}
case pref.Int64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderInt64Ptr
}
case pref.Sint64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSint64Ptr
}
case pref.Uint64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderUint64Ptr
}
case pref.Sfixed32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSfixed32Ptr
}
case pref.Fixed32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderFixed32Ptr
}
case pref.FloatKind:
if ft.Kind() == reflect.Float32 {
return nil, coderFloatPtr
}
case pref.Sfixed64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSfixed64Ptr
}
case pref.Fixed64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderFixed64Ptr
}
case pref.DoubleKind:
if ft.Kind() == reflect.Float64 {
return nil, coderDoublePtr
}
case pref.StringKind:
if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) {
return nil, coderStringPtrValidateUTF8
}
if ft.Kind() == reflect.String {
return nil, coderStringPtr
}
case pref.BytesKind:
if ft.Kind() == reflect.String {
return nil, coderStringPtr
}
}
default:
switch fd.Kind() {
case pref.BoolKind:
if ft.Kind() == reflect.Bool {
return nil, coderBool
}
case pref.EnumKind:
if ft.Kind() == reflect.Int32 {
return nil, coderEnum
}
case pref.Int32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderInt32
}
case pref.Sint32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSint32
}
case pref.Uint32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderUint32
}
case pref.Int64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderInt64
}
case pref.Sint64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSint64
}
case pref.Uint64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderUint64
}
case pref.Sfixed32Kind:
if ft.Kind() == reflect.Int32 {
return nil, coderSfixed32
}
case pref.Fixed32Kind:
if ft.Kind() == reflect.Uint32 {
return nil, coderFixed32
}
case pref.FloatKind:
if ft.Kind() == reflect.Float32 {
return nil, coderFloat
}
case pref.Sfixed64Kind:
if ft.Kind() == reflect.Int64 {
return nil, coderSfixed64
}
case pref.Fixed64Kind:
if ft.Kind() == reflect.Uint64 {
return nil, coderFixed64
}
case pref.DoubleKind:
if ft.Kind() == reflect.Float64 {
return nil, coderDouble
}
case pref.StringKind:
if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) {
return nil, coderStringValidateUTF8
}
if ft.Kind() == reflect.String {
return nil, coderString
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) {
return nil, coderBytesValidateUTF8
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytes
}
case pref.BytesKind:
if ft.Kind() == reflect.String {
return nil, coderString
}
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
return nil, coderBytes
}
}
}
panic(fmt.Sprintf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))
}
// encoderFuncsForValue returns value functions for a field, used for
// extension values and map encoding.
func encoderFuncsForValue(fd pref.FieldDescriptor) valueCoderFuncs {
switch {
case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
switch fd.Kind() {
case pref.BoolKind:
return coderBoolSliceValue
case pref.EnumKind:
return coderEnumSliceValue
case pref.Int32Kind:
return coderInt32SliceValue
case pref.Sint32Kind:
return coderSint32SliceValue
case pref.Uint32Kind:
return coderUint32SliceValue
case pref.Int64Kind:
return coderInt64SliceValue
case pref.Sint64Kind:
return coderSint64SliceValue
case pref.Uint64Kind:
return coderUint64SliceValue
case pref.Sfixed32Kind:
return coderSfixed32SliceValue
case pref.Fixed32Kind:
return coderFixed32SliceValue
case pref.FloatKind:
return coderFloatSliceValue
case pref.Sfixed64Kind:
return coderSfixed64SliceValue
case pref.Fixed64Kind:
return coderFixed64SliceValue
case pref.DoubleKind:
return coderDoubleSliceValue
case pref.StringKind:
// We don't have a UTF-8 validating coder for repeated string fields.
// Value coders are used for extensions and maps.
// Extensions are never proto3, and maps never contain lists.
return coderStringSliceValue
case pref.BytesKind:
return coderBytesSliceValue
case pref.MessageKind:
return coderMessageSliceValue
case pref.GroupKind:
return coderGroupSliceValue
}
case fd.Cardinality() == pref.Repeated && fd.IsPacked():
switch fd.Kind() {
case pref.BoolKind:
return coderBoolPackedSliceValue
case pref.EnumKind:
return coderEnumPackedSliceValue
case pref.Int32Kind:
return coderInt32PackedSliceValue
case pref.Sint32Kind:
return coderSint32PackedSliceValue
case pref.Uint32Kind:
return coderUint32PackedSliceValue
case pref.Int64Kind:
return coderInt64PackedSliceValue
case pref.Sint64Kind:
return coderSint64PackedSliceValue
case pref.Uint64Kind:
return coderUint64PackedSliceValue
case pref.Sfixed32Kind:
return coderSfixed32PackedSliceValue
case pref.Fixed32Kind:
return coderFixed32PackedSliceValue
case pref.FloatKind:
return coderFloatPackedSliceValue
case pref.Sfixed64Kind:
return coderSfixed64PackedSliceValue
case pref.Fixed64Kind:
return coderFixed64PackedSliceValue
case pref.DoubleKind:
return coderDoublePackedSliceValue
}
default:
switch fd.Kind() {
default:
case pref.BoolKind:
return coderBoolValue
case pref.EnumKind:
return coderEnumValue
case pref.Int32Kind:
return coderInt32Value
case pref.Sint32Kind:
return coderSint32Value
case pref.Uint32Kind:
return coderUint32Value
case pref.Int64Kind:
return coderInt64Value
case pref.Sint64Kind:
return coderSint64Value
case pref.Uint64Kind:
return coderUint64Value
case pref.Sfixed32Kind:
return coderSfixed32Value
case pref.Fixed32Kind:
return coderFixed32Value
case pref.FloatKind:
return coderFloatValue
case pref.Sfixed64Kind:
return coderSfixed64Value
case pref.Fixed64Kind:
return coderFixed64Value
case pref.DoubleKind:
return coderDoubleValue
case pref.StringKind:
if strs.EnforceUTF8(fd) {
return coderStringValueValidateUTF8
}
return coderStringValue
case pref.BytesKind:
return coderBytesValue
case pref.MessageKind:
return coderMessageValue
case pref.GroupKind:
return coderGroupValue
}
}
panic(fmt.Sprintf("invalid field: no encoder for %v %v %v", fd.FullName(), fd.Cardinality(), fd.Kind()))
}

View File

@ -0,0 +1,17 @@
// 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.
// +build !purego,!appengine
package impl
// When using unsafe pointers, we can just treat enum values as int32s.
var (
coderEnumNoZero = coderInt32NoZero
coderEnum = coderInt32
coderEnumPtr = coderInt32Ptr
coderEnumSlice = coderInt32Slice
coderEnumPackedSlice = coderInt32PackedSlice
)

View File

@ -0,0 +1,467 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"fmt"
"reflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// unwrapper unwraps the value to the underlying value.
// This is implemented by List and Map.
type unwrapper interface {
protoUnwrap() interface{}
}
// A Converter coverts to/from Go reflect.Value types and protobuf protoreflect.Value types.
type Converter interface {
// PBValueOf converts a reflect.Value to a protoreflect.Value.
PBValueOf(reflect.Value) pref.Value
// GoValueOf converts a protoreflect.Value to a reflect.Value.
GoValueOf(pref.Value) reflect.Value
// IsValidPB returns whether a protoreflect.Value is compatible with this type.
IsValidPB(pref.Value) bool
// IsValidGo returns whether a reflect.Value is compatible with this type.
IsValidGo(reflect.Value) bool
// New returns a new field value.
// For scalars, it returns the default value of the field.
// For composite types, it returns a new mutable value.
New() pref.Value
// Zero returns a new field value.
// For scalars, it returns the default value of the field.
// For composite types, it returns an immutable, empty value.
Zero() pref.Value
}
// NewConverter matches a Go type with a protobuf field and returns a Converter
// that converts between the two. Enums must be a named int32 kind that
// implements protoreflect.Enum, and messages must be pointer to a named
// struct type that implements protoreflect.ProtoMessage.
//
// This matcher deliberately supports a wider range of Go types than what
// protoc-gen-go historically generated to be able to automatically wrap some
// v1 messages generated by other forks of protoc-gen-go.
func NewConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
switch {
case fd.IsList():
return newListConverter(t, fd)
case fd.IsMap():
return newMapConverter(t, fd)
default:
return newSingularConverter(t, fd)
}
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
}
var (
boolType = reflect.TypeOf(bool(false))
int32Type = reflect.TypeOf(int32(0))
int64Type = reflect.TypeOf(int64(0))
uint32Type = reflect.TypeOf(uint32(0))
uint64Type = reflect.TypeOf(uint64(0))
float32Type = reflect.TypeOf(float32(0))
float64Type = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf(string(""))
bytesType = reflect.TypeOf([]byte(nil))
byteType = reflect.TypeOf(byte(0))
)
var (
boolZero = pref.ValueOfBool(false)
int32Zero = pref.ValueOfInt32(0)
int64Zero = pref.ValueOfInt64(0)
uint32Zero = pref.ValueOfUint32(0)
uint64Zero = pref.ValueOfUint64(0)
float32Zero = pref.ValueOfFloat32(0)
float64Zero = pref.ValueOfFloat64(0)
stringZero = pref.ValueOfString("")
bytesZero = pref.ValueOfBytes(nil)
)
func newSingularConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
defVal := func(fd pref.FieldDescriptor, zero pref.Value) pref.Value {
if fd.Cardinality() == pref.Repeated {
// Default isn't defined for repeated fields.
return zero
}
return fd.Default()
}
switch fd.Kind() {
case pref.BoolKind:
if t.Kind() == reflect.Bool {
return &boolConverter{t, defVal(fd, boolZero)}
}
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
if t.Kind() == reflect.Int32 {
return &int32Converter{t, defVal(fd, int32Zero)}
}
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
if t.Kind() == reflect.Int64 {
return &int64Converter{t, defVal(fd, int64Zero)}
}
case pref.Uint32Kind, pref.Fixed32Kind:
if t.Kind() == reflect.Uint32 {
return &uint32Converter{t, defVal(fd, uint32Zero)}
}
case pref.Uint64Kind, pref.Fixed64Kind:
if t.Kind() == reflect.Uint64 {
return &uint64Converter{t, defVal(fd, uint64Zero)}
}
case pref.FloatKind:
if t.Kind() == reflect.Float32 {
return &float32Converter{t, defVal(fd, float32Zero)}
}
case pref.DoubleKind:
if t.Kind() == reflect.Float64 {
return &float64Converter{t, defVal(fd, float64Zero)}
}
case pref.StringKind:
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
return &stringConverter{t, defVal(fd, stringZero)}
}
case pref.BytesKind:
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
return &bytesConverter{t, defVal(fd, bytesZero)}
}
case pref.EnumKind:
// Handle enums, which must be a named int32 type.
if t.Kind() == reflect.Int32 {
return newEnumConverter(t, fd)
}
case pref.MessageKind, pref.GroupKind:
return newMessageConverter(t)
}
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
}
type boolConverter struct {
goType reflect.Type
def pref.Value
}
func (c *boolConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfBool(v.Bool())
}
func (c *boolConverter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(v.Bool()).Convert(c.goType)
}
func (c *boolConverter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(bool)
return ok
}
func (c *boolConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *boolConverter) New() pref.Value { return c.def }
func (c *boolConverter) Zero() pref.Value { return c.def }
type int32Converter struct {
goType reflect.Type
def pref.Value
}
func (c *int32Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfInt32(int32(v.Int()))
}
func (c *int32Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(int32(v.Int())).Convert(c.goType)
}
func (c *int32Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(int32)
return ok
}
func (c *int32Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *int32Converter) New() pref.Value { return c.def }
func (c *int32Converter) Zero() pref.Value { return c.def }
type int64Converter struct {
goType reflect.Type
def pref.Value
}
func (c *int64Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfInt64(int64(v.Int()))
}
func (c *int64Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(int64(v.Int())).Convert(c.goType)
}
func (c *int64Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(int64)
return ok
}
func (c *int64Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *int64Converter) New() pref.Value { return c.def }
func (c *int64Converter) Zero() pref.Value { return c.def }
type uint32Converter struct {
goType reflect.Type
def pref.Value
}
func (c *uint32Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfUint32(uint32(v.Uint()))
}
func (c *uint32Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(uint32(v.Uint())).Convert(c.goType)
}
func (c *uint32Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(uint32)
return ok
}
func (c *uint32Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *uint32Converter) New() pref.Value { return c.def }
func (c *uint32Converter) Zero() pref.Value { return c.def }
type uint64Converter struct {
goType reflect.Type
def pref.Value
}
func (c *uint64Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfUint64(uint64(v.Uint()))
}
func (c *uint64Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(uint64(v.Uint())).Convert(c.goType)
}
func (c *uint64Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(uint64)
return ok
}
func (c *uint64Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *uint64Converter) New() pref.Value { return c.def }
func (c *uint64Converter) Zero() pref.Value { return c.def }
type float32Converter struct {
goType reflect.Type
def pref.Value
}
func (c *float32Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfFloat32(float32(v.Float()))
}
func (c *float32Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(float32(v.Float())).Convert(c.goType)
}
func (c *float32Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(float32)
return ok
}
func (c *float32Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *float32Converter) New() pref.Value { return c.def }
func (c *float32Converter) Zero() pref.Value { return c.def }
type float64Converter struct {
goType reflect.Type
def pref.Value
}
func (c *float64Converter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfFloat64(float64(v.Float()))
}
func (c *float64Converter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(float64(v.Float())).Convert(c.goType)
}
func (c *float64Converter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(float64)
return ok
}
func (c *float64Converter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *float64Converter) New() pref.Value { return c.def }
func (c *float64Converter) Zero() pref.Value { return c.def }
type stringConverter struct {
goType reflect.Type
def pref.Value
}
func (c *stringConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfString(v.Convert(stringType).String())
}
func (c *stringConverter) GoValueOf(v pref.Value) reflect.Value {
// pref.Value.String never panics, so we go through an interface
// conversion here to check the type.
s := v.Interface().(string)
if c.goType.Kind() == reflect.Slice && s == "" {
return reflect.Zero(c.goType) // ensure empty string is []byte(nil)
}
return reflect.ValueOf(s).Convert(c.goType)
}
func (c *stringConverter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(string)
return ok
}
func (c *stringConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *stringConverter) New() pref.Value { return c.def }
func (c *stringConverter) Zero() pref.Value { return c.def }
type bytesConverter struct {
goType reflect.Type
def pref.Value
}
func (c *bytesConverter) 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.goType.Kind() == reflect.String && v.Len() == 0 {
return pref.ValueOfBytes(nil) // ensure empty string is []byte(nil)
}
return pref.ValueOfBytes(v.Convert(bytesType).Bytes())
}
func (c *bytesConverter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(v.Bytes()).Convert(c.goType)
}
func (c *bytesConverter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().([]byte)
return ok
}
func (c *bytesConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *bytesConverter) New() pref.Value { return c.def }
func (c *bytesConverter) Zero() pref.Value { return c.def }
type enumConverter struct {
goType reflect.Type
def pref.Value
}
func newEnumConverter(goType reflect.Type, fd pref.FieldDescriptor) Converter {
var def pref.Value
if fd.Cardinality() == pref.Repeated {
def = pref.ValueOfEnum(fd.Enum().Values().Get(0).Number())
} else {
def = fd.Default()
}
return &enumConverter{goType, def}
}
func (c *enumConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfEnum(pref.EnumNumber(v.Int()))
}
func (c *enumConverter) GoValueOf(v pref.Value) reflect.Value {
return reflect.ValueOf(v.Enum()).Convert(c.goType)
}
func (c *enumConverter) IsValidPB(v pref.Value) bool {
_, ok := v.Interface().(pref.EnumNumber)
return ok
}
func (c *enumConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *enumConverter) New() pref.Value {
return c.def
}
func (c *enumConverter) Zero() pref.Value {
return c.def
}
type messageConverter struct {
goType reflect.Type
}
func newMessageConverter(goType reflect.Type) Converter {
return &messageConverter{goType}
}
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 m, ok := v.Interface().(pref.ProtoMessage); ok {
return pref.ValueOfMessage(m.ProtoReflect())
}
return pref.ValueOfMessage(legacyWrapMessage(v))
}
func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
m := v.Message()
var rv reflect.Value
if u, ok := m.(unwrapper); ok {
rv = reflect.ValueOf(u.protoUnwrap())
} else {
rv = reflect.ValueOf(m.Interface())
}
if rv.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
}
return rv
}
func (c *messageConverter) IsValidPB(v pref.Value) bool {
m := v.Message()
var rv reflect.Value
if u, ok := m.(unwrapper); ok {
rv = reflect.ValueOf(u.protoUnwrap())
} else {
rv = reflect.ValueOf(m.Interface())
}
return rv.Type() == c.goType
}
func (c *messageConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *messageConverter) New() pref.Value {
return c.PBValueOf(reflect.New(c.goType.Elem()))
}
func (c *messageConverter) Zero() pref.Value {
return c.PBValueOf(reflect.Zero(c.goType))
}

View File

@ -0,0 +1,141 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"fmt"
"reflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
switch {
case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Slice:
return &listPtrConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
case t.Kind() == reflect.Slice:
return &listConverter{t, newSingularConverter(t.Elem(), fd)}
}
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
}
type listConverter struct {
goType reflect.Type // []T
c Converter
}
func (c *listConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
pv := reflect.New(c.goType)
pv.Elem().Set(v)
return pref.ValueOfList(&listReflect{pv, c.c})
}
func (c *listConverter) GoValueOf(v pref.Value) reflect.Value {
rv := v.List().(*listReflect).v
if rv.IsNil() {
return reflect.Zero(c.goType)
}
return rv.Elem()
}
func (c *listConverter) IsValidPB(v pref.Value) bool {
list, ok := v.Interface().(*listReflect)
if !ok {
return false
}
return list.v.Type().Elem() == c.goType
}
func (c *listConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *listConverter) New() pref.Value {
return pref.ValueOfList(&listReflect{reflect.New(c.goType), c.c})
}
func (c *listConverter) Zero() pref.Value {
return pref.ValueOfList(&listReflect{reflect.Zero(reflect.PtrTo(c.goType)), c.c})
}
type listPtrConverter struct {
goType reflect.Type // *[]T
c Converter
}
func (c *listPtrConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfList(&listReflect{v, c.c})
}
func (c *listPtrConverter) GoValueOf(v pref.Value) reflect.Value {
return v.List().(*listReflect).v
}
func (c *listPtrConverter) IsValidPB(v pref.Value) bool {
list, ok := v.Interface().(*listReflect)
if !ok {
return false
}
return list.v.Type() == c.goType
}
func (c *listPtrConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *listPtrConverter) New() pref.Value {
return c.PBValueOf(reflect.New(c.goType.Elem()))
}
func (c *listPtrConverter) Zero() pref.Value {
return c.PBValueOf(reflect.Zero(c.goType))
}
type listReflect struct {
v reflect.Value // *[]T
conv Converter
}
func (ls *listReflect) Len() int {
if ls.v.IsNil() {
return 0
}
return ls.v.Elem().Len()
}
func (ls *listReflect) Get(i int) pref.Value {
return ls.conv.PBValueOf(ls.v.Elem().Index(i))
}
func (ls *listReflect) Set(i int, v pref.Value) {
ls.v.Elem().Index(i).Set(ls.conv.GoValueOf(v))
}
func (ls *listReflect) Append(v pref.Value) {
ls.v.Elem().Set(reflect.Append(ls.v.Elem(), ls.conv.GoValueOf(v)))
}
func (ls *listReflect) AppendMutable() pref.Value {
if _, ok := ls.conv.(*messageConverter); !ok {
panic("invalid AppendMutable on list with non-message type")
}
v := ls.NewElement()
ls.Append(v)
return v
}
func (ls *listReflect) Truncate(i int) {
ls.v.Elem().Set(ls.v.Elem().Slice(0, i))
}
func (ls *listReflect) NewElement() pref.Value {
return ls.conv.New()
}
func (ls *listReflect) IsValid() bool {
return !ls.v.IsNil()
}
func (ls *listReflect) protoUnwrap() interface{} {
return ls.v.Interface()
}

View File

@ -0,0 +1,121 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"fmt"
"reflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type mapConverter struct {
goType reflect.Type // map[K]V
keyConv, valConv Converter
}
func newMapConverter(t reflect.Type, fd pref.FieldDescriptor) *mapConverter {
if t.Kind() != reflect.Map {
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
}
return &mapConverter{
goType: t,
keyConv: newSingularConverter(t.Key(), fd.MapKey()),
valConv: newSingularConverter(t.Elem(), fd.MapValue()),
}
}
func (c *mapConverter) PBValueOf(v reflect.Value) pref.Value {
if v.Type() != c.goType {
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
}
return pref.ValueOfMap(&mapReflect{v, c.keyConv, c.valConv})
}
func (c *mapConverter) GoValueOf(v pref.Value) reflect.Value {
return v.Map().(*mapReflect).v
}
func (c *mapConverter) IsValidPB(v pref.Value) bool {
mapv, ok := v.Interface().(*mapReflect)
if !ok {
return false
}
return mapv.v.Type() == c.goType
}
func (c *mapConverter) IsValidGo(v reflect.Value) bool {
return v.IsValid() && v.Type() == c.goType
}
func (c *mapConverter) New() pref.Value {
return c.PBValueOf(reflect.MakeMap(c.goType))
}
func (c *mapConverter) Zero() pref.Value {
return c.PBValueOf(reflect.Zero(c.goType))
}
type mapReflect struct {
v reflect.Value // map[K]V
keyConv Converter
valConv Converter
}
func (ms *mapReflect) Len() int {
return ms.v.Len()
}
func (ms *mapReflect) Has(k pref.MapKey) bool {
rk := ms.keyConv.GoValueOf(k.Value())
rv := ms.v.MapIndex(rk)
return rv.IsValid()
}
func (ms *mapReflect) Get(k pref.MapKey) pref.Value {
rk := ms.keyConv.GoValueOf(k.Value())
rv := ms.v.MapIndex(rk)
if !rv.IsValid() {
return pref.Value{}
}
return ms.valConv.PBValueOf(rv)
}
func (ms *mapReflect) Set(k pref.MapKey, v pref.Value) {
rk := ms.keyConv.GoValueOf(k.Value())
rv := ms.valConv.GoValueOf(v)
ms.v.SetMapIndex(rk, rv)
}
func (ms *mapReflect) Clear(k pref.MapKey) {
rk := ms.keyConv.GoValueOf(k.Value())
ms.v.SetMapIndex(rk, reflect.Value{})
}
func (ms *mapReflect) Mutable(k pref.MapKey) pref.Value {
if _, ok := ms.valConv.(*messageConverter); !ok {
panic("invalid Mutable on map with non-message value type")
}
v := ms.Get(k)
if !v.IsValid() {
v = ms.NewValue()
ms.Set(k, v)
}
return v
}
func (ms *mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
iter := mapRange(ms.v)
for iter.Next() {
k := ms.keyConv.PBValueOf(iter.Key()).MapKey()
v := ms.valConv.PBValueOf(iter.Value())
if !f(k, v) {
return
}
}
}
func (ms *mapReflect) NewValue() pref.Value {
return ms.valConv.New()
}
func (ms *mapReflect) IsValid() bool {
return !ms.v.IsNil()
}
func (ms *mapReflect) protoUnwrap() interface{} {
return ms.v.Interface()
}

View File

@ -0,0 +1,274 @@
// 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 impl
import (
"math/bits"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
preg "google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoiface"
piface "google.golang.org/protobuf/runtime/protoiface"
)
type unmarshalOptions struct {
flags protoiface.UnmarshalInputFlags
resolver interface {
FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
}
}
func (o unmarshalOptions) Options() proto.UnmarshalOptions {
return proto.UnmarshalOptions{
Merge: true,
AllowPartial: true,
DiscardUnknown: o.DiscardUnknown(),
Resolver: o.resolver,
}
}
func (o unmarshalOptions) DiscardUnknown() bool { return o.flags&piface.UnmarshalDiscardUnknown != 0 }
func (o unmarshalOptions) IsDefault() bool {
return o.flags == 0 && o.resolver == preg.GlobalTypes
}
var lazyUnmarshalOptions = unmarshalOptions{
resolver: preg.GlobalTypes,
}
type unmarshalOutput struct {
n int // number of bytes consumed
initialized bool
}
// unmarshal is protoreflect.Methods.Unmarshal.
func (mi *MessageInfo) unmarshal(in piface.UnmarshalInput) (piface.UnmarshalOutput, error) {
var p pointer
if ms, ok := in.Message.(*messageState); ok {
p = ms.pointer()
} else {
p = in.Message.(*messageReflectWrapper).pointer()
}
out, err := mi.unmarshalPointer(in.Buf, p, 0, unmarshalOptions{
flags: in.Flags,
resolver: in.Resolver,
})
var flags piface.UnmarshalOutputFlags
if out.initialized {
flags |= piface.UnmarshalInitialized
}
return piface.UnmarshalOutput{
Flags: flags,
}, err
}
// errUnknown is returned during unmarshaling to indicate a parse error that
// should result in a field being placed in the unknown fields section (for example,
// when the wire type doesn't match) as opposed to the entire unmarshal operation
// failing (for example, when a field extends past the available input).
//
// This is a sentinel error which should never be visible to the user.
var errUnknown = errors.New("unknown")
func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) {
mi.init()
if flags.ProtoLegacy && mi.isMessageSet {
return unmarshalMessageSet(mi, b, p, opts)
}
initialized := true
var requiredMask uint64
var exts *map[int32]ExtensionField
start := len(b)
for len(b) > 0 {
// Parse the tag (field number and wire type).
var tag uint64
if b[0] < 0x80 {
tag = uint64(b[0])
b = b[1:]
} else if len(b) >= 2 && b[1] < 128 {
tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
b = b[2:]
} else {
var n int
tag, n = protowire.ConsumeVarint(b)
if n < 0 {
return out, protowire.ParseError(n)
}
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")
} else {
num = protowire.Number(n)
}
wtyp := protowire.Type(tag & 7)
if wtyp == protowire.EndGroupType {
if num != groupTag {
return out, errors.New("mismatching end group marker")
}
groupTag = 0
break
}
var f *coderFieldInfo
if int(num) < len(mi.denseCoderFields) {
f = mi.denseCoderFields[num]
} else {
f = mi.coderFields[num]
}
var n int
err := errUnknown
switch {
case f != nil:
if f.funcs.unmarshal == nil {
break
}
var o unmarshalOutput
o, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, f, opts)
n = o.n
if err != nil {
break
}
requiredMask |= f.validation.requiredBit
if f.funcs.isInit != nil && !o.initialized {
initialized = false
}
default:
// Possible extension.
if exts == nil && mi.extensionOffset.IsValid() {
exts = p.Apply(mi.extensionOffset).Extensions()
if *exts == nil {
*exts = make(map[int32]ExtensionField)
}
}
if exts == nil {
break
}
var o unmarshalOutput
o, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
if err != nil {
break
}
n = o.n
if !o.initialized {
initialized = false
}
}
if err != nil {
if err != errUnknown {
return out, err
}
n = protowire.ConsumeFieldValue(num, wtyp, b)
if n < 0 {
return out, protowire.ParseError(n)
}
if !opts.DiscardUnknown() && mi.unknownOffset.IsValid() {
u := p.Apply(mi.unknownOffset).Bytes()
*u = protowire.AppendTag(*u, num, wtyp)
*u = append(*u, b[:n]...)
}
}
b = b[n:]
}
if groupTag != 0 {
return out, errors.New("missing end group marker")
}
if mi.numRequiredFields > 0 && bits.OnesCount64(requiredMask) != int(mi.numRequiredFields) {
initialized = false
}
if initialized {
out.initialized = true
}
out.n = start - len(b)
return out, nil
}
func (mi *MessageInfo) unmarshalExtension(b []byte, num protowire.Number, wtyp protowire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (out unmarshalOutput, err error) {
x := exts[int32(num)]
xt := x.Type()
if xt == nil {
var err error
xt, err = opts.resolver.FindExtensionByNumber(mi.Desc.FullName(), num)
if err != nil {
if err == preg.NotFound {
return out, errUnknown
}
return out, errors.New("%v: unable to resolve extension %v: %v", mi.Desc.FullName(), num, err)
}
}
xi := getExtensionFieldInfo(xt)
if xi.funcs.unmarshal == nil {
return out, errUnknown
}
if flags.LazyUnmarshalExtensions {
if opts.IsDefault() && x.canLazy(xt) {
out, valid := skipExtension(b, xi, num, wtyp, opts)
switch valid {
case ValidationValid:
if out.initialized {
x.appendLazyBytes(xt, xi, num, wtyp, b[:out.n])
exts[int32(num)] = x
return out, nil
}
case ValidationInvalid:
return out, errors.New("invalid wire format")
case ValidationUnknown:
}
}
}
ival := x.Value()
if !ival.IsValid() && xi.unmarshalNeedsValue {
// Create a new message, list, or map value to fill in.
// For enums, create a prototype value to let the unmarshal func know the
// concrete type.
ival = xt.New()
}
v, out, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
if err != nil {
return out, err
}
if xi.funcs.isInit == nil {
out.initialized = true
}
x.Set(xt, v)
exts[int32(num)] = x
return out, nil
}
func skipExtension(b []byte, xi *extensionFieldInfo, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, _ ValidationStatus) {
if xi.validation.mi == nil {
return out, ValidationUnknown
}
xi.validation.mi.init()
switch xi.validation.typ {
case validationTypeMessage:
if wtyp != protowire.BytesType {
return out, ValidationUnknown
}
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return out, ValidationUnknown
}
out, st := xi.validation.mi.validate(v, 0, opts)
out.n = n
return out, st
case validationTypeGroup:
if wtyp != protowire.StartGroupType {
return out, ValidationUnknown
}
out, st := xi.validation.mi.validate(b, num, opts)
return out, st
default:
return out, ValidationUnknown
}
}

View File

@ -0,0 +1,199 @@
// 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 impl
import (
"math"
"sort"
"sync/atomic"
"google.golang.org/protobuf/internal/flags"
proto "google.golang.org/protobuf/proto"
piface "google.golang.org/protobuf/runtime/protoiface"
)
type marshalOptions struct {
flags piface.MarshalInputFlags
}
func (o marshalOptions) Options() proto.MarshalOptions {
return proto.MarshalOptions{
AllowPartial: true,
Deterministic: o.Deterministic(),
UseCachedSize: o.UseCachedSize(),
}
}
func (o marshalOptions) Deterministic() bool { return o.flags&piface.MarshalDeterministic != 0 }
func (o marshalOptions) UseCachedSize() bool { return o.flags&piface.MarshalUseCachedSize != 0 }
// size is protoreflect.Methods.Size.
func (mi *MessageInfo) size(in piface.SizeInput) piface.SizeOutput {
var p pointer
if ms, ok := in.Message.(*messageState); ok {
p = ms.pointer()
} else {
p = in.Message.(*messageReflectWrapper).pointer()
}
size := mi.sizePointer(p, marshalOptions{
flags: in.Flags,
})
return piface.SizeOutput{Size: size}
}
func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) {
mi.init()
if p.IsNil() {
return 0
}
if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size >= 0 {
return int(size)
}
}
return mi.sizePointerSlow(p, opts)
}
func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
if flags.ProtoLegacy && mi.isMessageSet {
size = sizeMessageSet(mi, p, opts)
if mi.sizecacheOffset.IsValid() {
atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
}
return size
}
if mi.extensionOffset.IsValid() {
e := p.Apply(mi.extensionOffset).Extensions()
size += mi.sizeExtensions(e, opts)
}
for _, f := range mi.orderedCoderFields {
if f.funcs.size == nil {
continue
}
fptr := p.Apply(f.offset)
if f.isPointer && fptr.Elem().IsNil() {
continue
}
size += f.funcs.size(fptr, f, opts)
}
if mi.unknownOffset.IsValid() {
u := *p.Apply(mi.unknownOffset).Bytes()
size += len(u)
}
if mi.sizecacheOffset.IsValid() {
if size > math.MaxInt32 {
// The size is too large for the int32 sizecache field.
// We will need to recompute the size when encoding;
// unfortunately expensive, but better than invalid output.
atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), -1)
} else {
atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
}
}
return size
}
// marshal is protoreflect.Methods.Marshal.
func (mi *MessageInfo) marshal(in piface.MarshalInput) (out piface.MarshalOutput, err error) {
var p pointer
if ms, ok := in.Message.(*messageState); ok {
p = ms.pointer()
} else {
p = in.Message.(*messageReflectWrapper).pointer()
}
b, err := mi.marshalAppendPointer(in.Buf, p, marshalOptions{
flags: in.Flags,
})
return piface.MarshalOutput{Buf: b}, err
}
func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
mi.init()
if p.IsNil() {
return b, nil
}
if flags.ProtoLegacy && mi.isMessageSet {
return marshalMessageSet(mi, b, p, opts)
}
var err error
// The old marshaler encodes extensions at beginning.
if mi.extensionOffset.IsValid() {
e := p.Apply(mi.extensionOffset).Extensions()
// TODO: Special handling for MessageSet?
b, err = mi.appendExtensions(b, e, opts)
if err != nil {
return b, err
}
}
for _, f := range mi.orderedCoderFields {
if f.funcs.marshal == nil {
continue
}
fptr := p.Apply(f.offset)
if f.isPointer && fptr.Elem().IsNil() {
continue
}
b, err = f.funcs.marshal(b, fptr, f, opts)
if err != nil {
return b, err
}
}
if mi.unknownOffset.IsValid() && !mi.isMessageSet {
u := *p.Apply(mi.unknownOffset).Bytes()
b = append(b, u...)
}
return b, nil
}
func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) {
if ext == nil {
return 0
}
for _, x := range *ext {
xi := getExtensionFieldInfo(x.Type())
if xi.funcs.size == nil {
continue
}
n += xi.funcs.size(x.Value(), xi.tagsize, opts)
}
return n
}
func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) {
if ext == nil {
return b, nil
}
switch len(*ext) {
case 0:
return b, nil
case 1:
// Fast-path for one extension: Don't bother sorting the keys.
var err error
for _, x := range *ext {
xi := getExtensionFieldInfo(x.Type())
b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
}
return b, err
default:
// Sort the keys to provide a deterministic encoding.
// Not sure this is required, but the old code does it.
keys := make([]int, 0, len(*ext))
for k := range *ext {
keys = append(keys, int(k))
}
sort.Ints(keys)
var err error
for _, k := range keys {
x := (*ext)[int32(k)]
xi := getExtensionFieldInfo(x.Type())
b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
if err != nil {
return b, err
}
}
return b, nil
}
}

View File

@ -0,0 +1,21 @@
// 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 impl
import (
"reflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
type EnumInfo struct {
GoReflectType reflect.Type // int32 kind
Desc pref.EnumDescriptor
}
func (t *EnumInfo) New(n pref.EnumNumber) pref.Enum {
return reflect.ValueOf(n).Convert(t.GoReflectType).Interface().(pref.Enum)
}
func (t *EnumInfo) Descriptor() pref.EnumDescriptor { return t.Desc }

View File

@ -0,0 +1,156 @@
// 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 impl
import (
"reflect"
"sync"
"sync/atomic"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
// ExtensionInfo implements ExtensionType.
//
// This type contains a number of exported fields for legacy compatibility.
// The only non-deprecated use of this type is through the methods of the
// ExtensionType interface.
type ExtensionInfo struct {
// An ExtensionInfo may exist in several stages of initialization.
//
// extensionInfoUninitialized: Some or all of the legacy exported
// fields may be set, but none of the unexported fields have been
// initialized. This is the starting state for an ExtensionInfo
// in legacy generated code.
//
// extensionInfoDescInit: The desc field is set, but other unexported fields
// may not be initialized. Legacy exported fields may or may not be set.
// This is the starting state for an ExtensionInfo in newly generated code.
//
// extensionInfoFullInit: The ExtensionInfo is fully initialized.
// This state is only entered after lazy initialization is complete.
init uint32
mu sync.Mutex
goType reflect.Type
desc extensionTypeDescriptor
conv Converter
info *extensionFieldInfo // for fast-path method implementations
// ExtendedType is a typed nil-pointer to the parent message type that
// is being extended. It is possible for this to be unpopulated in v2
// since the message may no longer implement the MessageV1 interface.
//
// Deprecated: Use the ExtendedType method instead.
ExtendedType piface.MessageV1
// ExtensionType is the zero value of the extension type.
//
// For historical reasons, reflect.TypeOf(ExtensionType) and the
// type returned by InterfaceOf may not be identical.
//
// Deprecated: Use InterfaceOf(xt.Zero()) instead.
ExtensionType interface{}
// Field is the field number of the extension.
//
// Deprecated: Use the Descriptor().Number method instead.
Field int32
// Name is the fully qualified name of extension.
//
// Deprecated: Use the Descriptor().FullName method instead.
Name string
// Tag is the protobuf struct tag used in the v1 API.
//
// Deprecated: Do not use.
Tag string
// Filename is the proto filename in which the extension is defined.
//
// Deprecated: Use Descriptor().ParentFile().Path() instead.
Filename string
}
// Stages of initialization: See the ExtensionInfo.init field.
const (
extensionInfoUninitialized = 0
extensionInfoDescInit = 1
extensionInfoFullInit = 2
)
func InitExtensionInfo(xi *ExtensionInfo, xd pref.ExtensionDescriptor, goType reflect.Type) {
xi.goType = goType
xi.desc = extensionTypeDescriptor{xd, xi}
xi.init = extensionInfoDescInit
}
func (xi *ExtensionInfo) New() pref.Value {
return xi.lazyInit().New()
}
func (xi *ExtensionInfo) Zero() pref.Value {
return xi.lazyInit().Zero()
}
func (xi *ExtensionInfo) ValueOf(v interface{}) pref.Value {
return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
}
func (xi *ExtensionInfo) InterfaceOf(v pref.Value) interface{} {
return xi.lazyInit().GoValueOf(v).Interface()
}
func (xi *ExtensionInfo) IsValidValue(v pref.Value) bool {
return xi.lazyInit().IsValidPB(v)
}
func (xi *ExtensionInfo) IsValidInterface(v interface{}) bool {
return xi.lazyInit().IsValidGo(reflect.ValueOf(v))
}
func (xi *ExtensionInfo) TypeDescriptor() pref.ExtensionTypeDescriptor {
if atomic.LoadUint32(&xi.init) < extensionInfoDescInit {
xi.lazyInitSlow()
}
return &xi.desc
}
func (xi *ExtensionInfo) lazyInit() Converter {
if atomic.LoadUint32(&xi.init) < extensionInfoFullInit {
xi.lazyInitSlow()
}
return xi.conv
}
func (xi *ExtensionInfo) lazyInitSlow() {
xi.mu.Lock()
defer xi.mu.Unlock()
if xi.init == extensionInfoFullInit {
return
}
defer atomic.StoreUint32(&xi.init, extensionInfoFullInit)
if xi.desc.ExtensionDescriptor == nil {
xi.initFromLegacy()
}
if !xi.desc.ExtensionDescriptor.IsPlaceholder() {
if xi.ExtensionType == nil {
xi.initToLegacy()
}
xi.conv = NewConverter(xi.goType, xi.desc.ExtensionDescriptor)
xi.info = makeExtensionFieldInfo(xi.desc.ExtensionDescriptor)
xi.info.validation = newValidationInfo(xi.desc.ExtensionDescriptor, xi.goType)
}
}
type extensionTypeDescriptor struct {
pref.ExtensionDescriptor
xi *ExtensionInfo
}
func (xtd *extensionTypeDescriptor) Type() pref.ExtensionType {
return xtd.xi
}
func (xtd *extensionTypeDescriptor) Descriptor() pref.ExtensionDescriptor {
return xtd.ExtensionDescriptor
}

View File

@ -0,0 +1,219 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package impl
import (
"fmt"
"reflect"
"strings"
"sync"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/reflect/protoreflect"
pref "google.golang.org/protobuf/reflect/protoreflect"
)
// legacyEnumName returns the name of enums used in legacy code.
// It is neither the protobuf full name nor the qualified Go name,
// but rather an odd hybrid of both.
func legacyEnumName(ed pref.EnumDescriptor) string {
var protoPkg string
enumName := string(ed.FullName())
if fd := ed.ParentFile(); fd != nil {
protoPkg = string(fd.Package())
enumName = strings.TrimPrefix(enumName, protoPkg+".")
}
if protoPkg == "" {
return strs.GoCamelCase(enumName)
}
return protoPkg + "." + strs.GoCamelCase(enumName)
}
// legacyWrapEnum wraps v as a protoreflect.Enum,
// where v must be a int32 kind and not implement the v2 API already.
func legacyWrapEnum(v reflect.Value) pref.Enum {
et := legacyLoadEnumType(v.Type())
return et.New(pref.EnumNumber(v.Int()))
}
var legacyEnumTypeCache sync.Map // map[reflect.Type]protoreflect.EnumType
// legacyLoadEnumType dynamically loads a protoreflect.EnumType for t,
// where t must be an int32 kind and not implement the v2 API already.
func legacyLoadEnumType(t reflect.Type) pref.EnumType {
// Fast-path: check if a EnumType is cached for this concrete type.
if et, ok := legacyEnumTypeCache.Load(t); ok {
return et.(pref.EnumType)
}
// Slow-path: derive enum descriptor and initialize EnumType.
var et pref.EnumType
ed := LegacyLoadEnumDesc(t)
et = &legacyEnumType{
desc: ed,
goType: t,
}
if et, ok := legacyEnumTypeCache.LoadOrStore(t, et); ok {
return et.(pref.EnumType)
}
return et
}
type legacyEnumType struct {
desc pref.EnumDescriptor
goType reflect.Type
m sync.Map // map[protoreflect.EnumNumber]proto.Enum
}
func (t *legacyEnumType) New(n pref.EnumNumber) pref.Enum {
if e, ok := t.m.Load(n); ok {
return e.(pref.Enum)
}
e := &legacyEnumWrapper{num: n, pbTyp: t, goTyp: t.goType}
t.m.Store(n, e)
return e
}
func (t *legacyEnumType) Descriptor() pref.EnumDescriptor {
return t.desc
}
type legacyEnumWrapper struct {
num pref.EnumNumber
pbTyp pref.EnumType
goTyp reflect.Type
}
func (e *legacyEnumWrapper) Descriptor() pref.EnumDescriptor {
return e.pbTyp.Descriptor()
}
func (e *legacyEnumWrapper) Type() pref.EnumType {
return e.pbTyp
}
func (e *legacyEnumWrapper) Number() pref.EnumNumber {
return e.num
}
func (e *legacyEnumWrapper) ProtoReflect() pref.Enum {
return e
}
func (e *legacyEnumWrapper) protoUnwrap() interface{} {
v := reflect.New(e.goTyp).Elem()
v.SetInt(int64(e.num))
return v.Interface()
}
var (
_ pref.Enum = (*legacyEnumWrapper)(nil)
_ unwrapper = (*legacyEnumWrapper)(nil)
)
var legacyEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
// LegacyLoadEnumDesc returns an EnumDescriptor derived from the Go type,
// which must be an int32 kind and not implement the v2 API already.
//
// This is exported for testing purposes.
func LegacyLoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
// Fast-path: check if an EnumDescriptor is cached for this concrete type.
if ed, ok := legacyEnumDescCache.Load(t); ok {
return ed.(pref.EnumDescriptor)
}
// Slow-path: initialize EnumDescriptor from the raw descriptor.
ev := reflect.Zero(t).Interface()
if _, ok := ev.(pref.Enum); ok {
panic(fmt.Sprintf("%v already implements proto.Enum", t))
}
edV1, ok := ev.(enumV1)
if !ok {
return aberrantLoadEnumDesc(t)
}
b, idxs := edV1.EnumDescriptor()
var ed pref.EnumDescriptor
if len(idxs) == 1 {
ed = legacyLoadFileDesc(b).Enums().Get(idxs[0])
} else {
md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
for _, i := range idxs[1 : len(idxs)-1] {
md = md.Messages().Get(i)
}
ed = md.Enums().Get(idxs[len(idxs)-1])
}
if ed, ok := legacyEnumDescCache.LoadOrStore(t, ed); ok {
return ed.(protoreflect.EnumDescriptor)
}
return ed
}
var aberrantEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
// aberrantLoadEnumDesc returns an EnumDescriptor derived from the Go type,
// which must not implement protoreflect.Enum or enumV1.
//
// If the type does not implement enumV1, then there is no reliable
// way to derive the original protobuf type information.
// We are unable to use the global enum registry since it is
// unfortunately keyed by the protobuf full name, which we also do not know.
// Thus, this produces some bogus enum descriptor based on the Go type name.
func aberrantLoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
// Fast-path: check if an EnumDescriptor is cached for this concrete type.
if ed, ok := aberrantEnumDescCache.Load(t); ok {
return ed.(pref.EnumDescriptor)
}
// Slow-path: construct a bogus, but unique EnumDescriptor.
ed := &filedesc.Enum{L2: new(filedesc.EnumL2)}
ed.L0.FullName = AberrantDeriveFullName(t) // e.g., github_com.user.repo.MyEnum
ed.L0.ParentFile = filedesc.SurrogateProto3
ed.L2.Values.List = append(ed.L2.Values.List, filedesc.EnumValue{})
// TODO: Use the presence of a UnmarshalJSON method to determine proto2?
vd := &ed.L2.Values.List[0]
vd.L0.FullName = ed.L0.FullName + "_UNKNOWN" // e.g., github_com.user.repo.MyEnum_UNKNOWN
vd.L0.ParentFile = ed.L0.ParentFile
vd.L0.Parent = ed
// TODO: We could use the String method to obtain some enum value names by
// starting at 0 and print the enum until it produces invalid identifiers.
// An exhaustive query is clearly impractical, but can be best-effort.
if ed, ok := aberrantEnumDescCache.LoadOrStore(t, ed); ok {
return ed.(pref.EnumDescriptor)
}
return ed
}
// AberrantDeriveFullName derives a fully qualified protobuf name for the given Go type
// The provided name is not guaranteed to be stable nor universally unique.
// It should be sufficiently unique within a program.
//
// This is exported for testing purposes.
func AberrantDeriveFullName(t reflect.Type) pref.FullName {
sanitize := func(r rune) rune {
switch {
case r == '/':
return '.'
case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z', '0' <= r && r <= '9':
return r
default:
return '_'
}
}
prefix := strings.Map(sanitize, t.PkgPath())
suffix := strings.Map(sanitize, t.Name())
if suffix == "" {
suffix = fmt.Sprintf("UnknownX%X", reflect.ValueOf(t).Pointer())
}
ss := append(strings.Split(prefix, "."), suffix)
for i, s := range ss {
if s == "" || ('0' <= s[0] && s[0] <= '9') {
ss[i] = "x" + s
}
}
return pref.FullName(strings.Join(ss, "."))
}

View File

@ -0,0 +1,92 @@
// 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 impl
import (
"encoding/binary"
"encoding/json"
"hash/crc32"
"math"
"reflect"
"google.golang.org/protobuf/internal/errors"
pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
// These functions exist to support exported APIs in generated protobufs.
// While these are deprecated, they cannot be removed for compatibility reasons.
// LegacyEnumName returns the name of enums used in legacy code.
func (Export) LegacyEnumName(ed pref.EnumDescriptor) string {
return legacyEnumName(ed)
}
// LegacyMessageTypeOf returns the protoreflect.MessageType for m,
// with name used as the message name if necessary.
func (Export) LegacyMessageTypeOf(m piface.MessageV1, name pref.FullName) pref.MessageType {
if mv := (Export{}).protoMessageV2Of(m); mv != nil {
return mv.ProtoReflect().Type()
}
return legacyLoadMessageInfo(reflect.TypeOf(m), name)
}
// UnmarshalJSONEnum unmarshals an enum from a JSON-encoded input.
// The input can either be a string representing the enum value by name,
// or a number representing the enum number itself.
func (Export) UnmarshalJSONEnum(ed pref.EnumDescriptor, b []byte) (pref.EnumNumber, error) {
if b[0] == '"' {
var name pref.Name
if err := json.Unmarshal(b, &name); err != nil {
return 0, errors.New("invalid input for enum %v: %s", ed.FullName(), b)
}
ev := ed.Values().ByName(name)
if ev == nil {
return 0, errors.New("invalid value for enum %v: %s", ed.FullName(), name)
}
return ev.Number(), nil
} else {
var num pref.EnumNumber
if err := json.Unmarshal(b, &num); err != nil {
return 0, errors.New("invalid input for enum %v: %s", ed.FullName(), b)
}
return num, nil
}
}
// CompressGZIP compresses the input as a GZIP-encoded file.
// The current implementation does no compression.
func (Export) CompressGZIP(in []byte) (out []byte) {
// RFC 1952, section 2.3.1.
var gzipHeader = [10]byte{0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}
// RFC 1951, section 3.2.4.
var blockHeader [5]byte
const maxBlockSize = math.MaxUint16
numBlocks := 1 + len(in)/maxBlockSize
// RFC 1952, section 2.3.1.
var gzipFooter [8]byte
binary.LittleEndian.PutUint32(gzipFooter[0:4], crc32.ChecksumIEEE(in))
binary.LittleEndian.PutUint32(gzipFooter[4:8], uint32(len(in)))
// Encode the input without compression using raw DEFLATE blocks.
out = make([]byte, 0, len(gzipHeader)+len(blockHeader)*numBlocks+len(in)+len(gzipFooter))
out = append(out, gzipHeader[:]...)
for blockHeader[0] == 0 {
blockSize := maxBlockSize
if blockSize > len(in) {
blockHeader[0] = 0x01 // final bit per RFC 1951, section 3.2.3.
blockSize = len(in)
}
binary.LittleEndian.PutUint16(blockHeader[1:3], uint16(blockSize)^0x0000)
binary.LittleEndian.PutUint16(blockHeader[3:5], uint16(blockSize)^0xffff)
out = append(out, blockHeader[:]...)
out = append(out, in[:blockSize]...)
in = in[blockSize:]
}
out = append(out, gzipFooter[:]...)
return out
}

Some files were not shown because too many files have changed in this diff Show More