mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 08:21:11 +00:00 
			
		
		
		
	* Add prometheus collector and route * dep ensure -add github.com/prometheus/client_golang/prometheus * dep ensure -update github.com/golang/protobuf * add metrics to reserved usernames * add comment head in metrics package * fix style imports * add metrics settings * add bearer token check * mapping metrics configs * fix lint * update config cheat sheet * update conf sample, typo fix
		
			
				
	
	
		
			843 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			843 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Go support for Protocol Buffers - Google's data interchange format
 | 
						|
//
 | 
						|
// Copyright 2010 The Go Authors.  All rights reserved.
 | 
						|
// https://github.com/golang/protobuf
 | 
						|
//
 | 
						|
// 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.
 | 
						|
 | 
						|
package proto
 | 
						|
 | 
						|
// Functions for writing the text protocol buffer format.
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"bytes"
 | 
						|
	"encoding"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"log"
 | 
						|
	"math"
 | 
						|
	"reflect"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	newline         = []byte("\n")
 | 
						|
	spaces          = []byte("                                        ")
 | 
						|
	endBraceNewline = []byte("}\n")
 | 
						|
	backslashN      = []byte{'\\', 'n'}
 | 
						|
	backslashR      = []byte{'\\', 'r'}
 | 
						|
	backslashT      = []byte{'\\', 't'}
 | 
						|
	backslashDQ     = []byte{'\\', '"'}
 | 
						|
	backslashBS     = []byte{'\\', '\\'}
 | 
						|
	posInf          = []byte("inf")
 | 
						|
	negInf          = []byte("-inf")
 | 
						|
	nan             = []byte("nan")
 | 
						|
)
 | 
						|
 | 
						|
type writer interface {
 | 
						|
	io.Writer
 | 
						|
	WriteByte(byte) error
 | 
						|
}
 | 
						|
 | 
						|
// textWriter is an io.Writer that tracks its indentation level.
 | 
						|
type textWriter struct {
 | 
						|
	ind      int
 | 
						|
	complete bool // if the current position is a complete line
 | 
						|
	compact  bool // whether to write out as a one-liner
 | 
						|
	w        writer
 | 
						|
}
 | 
						|
 | 
						|
func (w *textWriter) WriteString(s string) (n int, err error) {
 | 
						|
	if !strings.Contains(s, "\n") {
 | 
						|
		if !w.compact && w.complete {
 | 
						|
			w.writeIndent()
 | 
						|
		}
 | 
						|
		w.complete = false
 | 
						|
		return io.WriteString(w.w, s)
 | 
						|
	}
 | 
						|
	// WriteString is typically called without newlines, so this
 | 
						|
	// codepath and its copy are rare.  We copy to avoid
 | 
						|
	// duplicating all of Write's logic here.
 | 
						|
	return w.Write([]byte(s))
 | 
						|
}
 | 
						|
 | 
						|
func (w *textWriter) Write(p []byte) (n int, err error) {
 | 
						|
	newlines := bytes.Count(p, newline)
 | 
						|
	if newlines == 0 {
 | 
						|
		if !w.compact && w.complete {
 | 
						|
			w.writeIndent()
 | 
						|
		}
 | 
						|
		n, err = w.w.Write(p)
 | 
						|
		w.complete = false
 | 
						|
		return n, err
 | 
						|
	}
 | 
						|
 | 
						|
	frags := bytes.SplitN(p, newline, newlines+1)
 | 
						|
	if w.compact {
 | 
						|
		for i, frag := range frags {
 | 
						|
			if i > 0 {
 | 
						|
				if err := w.w.WriteByte(' '); err != nil {
 | 
						|
					return n, err
 | 
						|
				}
 | 
						|
				n++
 | 
						|
			}
 | 
						|
			nn, err := w.w.Write(frag)
 | 
						|
			n += nn
 | 
						|
			if err != nil {
 | 
						|
				return n, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return n, nil
 | 
						|
	}
 | 
						|
 | 
						|
	for i, frag := range frags {
 | 
						|
		if w.complete {
 | 
						|
			w.writeIndent()
 | 
						|
		}
 | 
						|
		nn, err := w.w.Write(frag)
 | 
						|
		n += nn
 | 
						|
		if err != nil {
 | 
						|
			return n, err
 | 
						|
		}
 | 
						|
		if i+1 < len(frags) {
 | 
						|
			if err := w.w.WriteByte('\n'); err != nil {
 | 
						|
				return n, err
 | 
						|
			}
 | 
						|
			n++
 | 
						|
		}
 | 
						|
	}
 | 
						|
	w.complete = len(frags[len(frags)-1]) == 0
 | 
						|
	return n, nil
 | 
						|
}
 | 
						|
 | 
						|
func (w *textWriter) WriteByte(c byte) error {
 | 
						|
	if w.compact && c == '\n' {
 | 
						|
		c = ' '
 | 
						|
	}
 | 
						|
	if !w.compact && w.complete {
 | 
						|
		w.writeIndent()
 | 
						|
	}
 | 
						|
	err := w.w.WriteByte(c)
 | 
						|
	w.complete = c == '\n'
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (w *textWriter) indent() { w.ind++ }
 | 
						|
 | 
						|
func (w *textWriter) unindent() {
 | 
						|
	if w.ind == 0 {
 | 
						|
		log.Print("proto: textWriter unindented too far")
 | 
						|
		return
 | 
						|
	}
 | 
						|
	w.ind--
 | 
						|
}
 | 
						|
 | 
						|
func writeName(w *textWriter, props *Properties) error {
 | 
						|
	if _, err := w.WriteString(props.OrigName); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if props.Wire != "group" {
 | 
						|
		return w.WriteByte(':')
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func requiresQuotes(u string) bool {
 | 
						|
	// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
 | 
						|
	for _, ch := range u {
 | 
						|
		switch {
 | 
						|
		case ch == '.' || ch == '/' || ch == '_':
 | 
						|
			continue
 | 
						|
		case '0' <= ch && ch <= '9':
 | 
						|
			continue
 | 
						|
		case 'A' <= ch && ch <= 'Z':
 | 
						|
			continue
 | 
						|
		case 'a' <= ch && ch <= 'z':
 | 
						|
			continue
 | 
						|
		default:
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// isAny reports whether sv is a google.protobuf.Any message
 | 
						|
func isAny(sv reflect.Value) bool {
 | 
						|
	type wkt interface {
 | 
						|
		XXX_WellKnownType() string
 | 
						|
	}
 | 
						|
	t, ok := sv.Addr().Interface().(wkt)
 | 
						|
	return ok && t.XXX_WellKnownType() == "Any"
 | 
						|
}
 | 
						|
 | 
						|
// writeProto3Any writes an expanded google.protobuf.Any message.
 | 
						|
//
 | 
						|
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
 | 
						|
// required messages are not linked in).
 | 
						|
//
 | 
						|
// It returns (true, error) when sv was written in expanded format or an error
 | 
						|
// was encountered.
 | 
						|
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
 | 
						|
	turl := sv.FieldByName("TypeUrl")
 | 
						|
	val := sv.FieldByName("Value")
 | 
						|
	if !turl.IsValid() || !val.IsValid() {
 | 
						|
		return true, errors.New("proto: invalid google.protobuf.Any message")
 | 
						|
	}
 | 
						|
 | 
						|
	b, ok := val.Interface().([]byte)
 | 
						|
	if !ok {
 | 
						|
		return true, errors.New("proto: invalid google.protobuf.Any message")
 | 
						|
	}
 | 
						|
 | 
						|
	parts := strings.Split(turl.String(), "/")
 | 
						|
	mt := MessageType(parts[len(parts)-1])
 | 
						|
	if mt == nil {
 | 
						|
		return false, nil
 | 
						|
	}
 | 
						|
	m := reflect.New(mt.Elem())
 | 
						|
	if err := Unmarshal(b, m.Interface().(Message)); err != nil {
 | 
						|
		return false, nil
 | 
						|
	}
 | 
						|
	w.Write([]byte("["))
 | 
						|
	u := turl.String()
 | 
						|
	if requiresQuotes(u) {
 | 
						|
		writeString(w, u)
 | 
						|
	} else {
 | 
						|
		w.Write([]byte(u))
 | 
						|
	}
 | 
						|
	if w.compact {
 | 
						|
		w.Write([]byte("]:<"))
 | 
						|
	} else {
 | 
						|
		w.Write([]byte("]: <\n"))
 | 
						|
		w.ind++
 | 
						|
	}
 | 
						|
	if err := tm.writeStruct(w, m.Elem()); err != nil {
 | 
						|
		return true, err
 | 
						|
	}
 | 
						|
	if w.compact {
 | 
						|
		w.Write([]byte("> "))
 | 
						|
	} else {
 | 
						|
		w.ind--
 | 
						|
		w.Write([]byte(">\n"))
 | 
						|
	}
 | 
						|
	return true, nil
 | 
						|
}
 | 
						|
 | 
						|
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
 | 
						|
	if tm.ExpandAny && isAny(sv) {
 | 
						|
		if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	st := sv.Type()
 | 
						|
	sprops := GetProperties(st)
 | 
						|
	for i := 0; i < sv.NumField(); i++ {
 | 
						|
		fv := sv.Field(i)
 | 
						|
		props := sprops.Prop[i]
 | 
						|
		name := st.Field(i).Name
 | 
						|
 | 
						|
		if name == "XXX_NoUnkeyedLiteral" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if strings.HasPrefix(name, "XXX_") {
 | 
						|
			// There are two XXX_ fields:
 | 
						|
			//   XXX_unrecognized []byte
 | 
						|
			//   XXX_extensions   map[int32]proto.Extension
 | 
						|
			// The first is handled here;
 | 
						|
			// the second is handled at the bottom of this function.
 | 
						|
			if name == "XXX_unrecognized" && !fv.IsNil() {
 | 
						|
				if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if fv.Kind() == reflect.Ptr && fv.IsNil() {
 | 
						|
			// Field not filled in. This could be an optional field or
 | 
						|
			// a required field that wasn't filled in. Either way, there
 | 
						|
			// isn't anything we can show for it.
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if fv.Kind() == reflect.Slice && fv.IsNil() {
 | 
						|
			// Repeated field that is empty, or a bytes field that is unused.
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if props.Repeated && fv.Kind() == reflect.Slice {
 | 
						|
			// Repeated field.
 | 
						|
			for j := 0; j < fv.Len(); j++ {
 | 
						|
				if err := writeName(w, props); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if !w.compact {
 | 
						|
					if err := w.WriteByte(' '); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				v := fv.Index(j)
 | 
						|
				if v.Kind() == reflect.Ptr && v.IsNil() {
 | 
						|
					// A nil message in a repeated field is not valid,
 | 
						|
					// but we can handle that more gracefully than panicking.
 | 
						|
					if _, err := w.Write([]byte("<nil>\n")); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				if err := tm.writeAny(w, v, props); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if err := w.WriteByte('\n'); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if fv.Kind() == reflect.Map {
 | 
						|
			// Map fields are rendered as a repeated struct with key/value fields.
 | 
						|
			keys := fv.MapKeys()
 | 
						|
			sort.Sort(mapKeys(keys))
 | 
						|
			for _, key := range keys {
 | 
						|
				val := fv.MapIndex(key)
 | 
						|
				if err := writeName(w, props); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if !w.compact {
 | 
						|
					if err := w.WriteByte(' '); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				// open struct
 | 
						|
				if err := w.WriteByte('<'); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if !w.compact {
 | 
						|
					if err := w.WriteByte('\n'); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				w.indent()
 | 
						|
				// key
 | 
						|
				if _, err := w.WriteString("key:"); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if !w.compact {
 | 
						|
					if err := w.WriteByte(' '); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if err := w.WriteByte('\n'); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				// nil values aren't legal, but we can avoid panicking because of them.
 | 
						|
				if val.Kind() != reflect.Ptr || !val.IsNil() {
 | 
						|
					// value
 | 
						|
					if _, err := w.WriteString("value:"); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
					if !w.compact {
 | 
						|
						if err := w.WriteByte(' '); err != nil {
 | 
						|
							return err
 | 
						|
						}
 | 
						|
					}
 | 
						|
					if err := tm.writeAny(w, val, props.MapValProp); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
					if err := w.WriteByte('\n'); err != nil {
 | 
						|
						return err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				// close struct
 | 
						|
				w.unindent()
 | 
						|
				if err := w.WriteByte('>'); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				if err := w.WriteByte('\n'); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 {
 | 
						|
			// empty bytes field
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {
 | 
						|
			// proto3 non-repeated scalar field; skip if zero value
 | 
						|
			if isProto3Zero(fv) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if fv.Kind() == reflect.Interface {
 | 
						|
			// Check if it is a oneof.
 | 
						|
			if st.Field(i).Tag.Get("protobuf_oneof") != "" {
 | 
						|
				// fv is nil, or holds a pointer to generated struct.
 | 
						|
				// That generated struct has exactly one field,
 | 
						|
				// which has a protobuf struct tag.
 | 
						|
				if fv.IsNil() {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				inner := fv.Elem().Elem() // interface -> *T -> T
 | 
						|
				tag := inner.Type().Field(0).Tag.Get("protobuf")
 | 
						|
				props = new(Properties) // Overwrite the outer props var, but not its pointee.
 | 
						|
				props.Parse(tag)
 | 
						|
				// Write the value in the oneof, not the oneof itself.
 | 
						|
				fv = inner.Field(0)
 | 
						|
 | 
						|
				// Special case to cope with malformed messages gracefully:
 | 
						|
				// If the value in the oneof is a nil pointer, don't panic
 | 
						|
				// in writeAny.
 | 
						|
				if fv.Kind() == reflect.Ptr && fv.IsNil() {
 | 
						|
					// Use errors.New so writeAny won't render quotes.
 | 
						|
					msg := errors.New("/* nil */")
 | 
						|
					fv = reflect.ValueOf(&msg).Elem()
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if err := writeName(w, props); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if !w.compact {
 | 
						|
			if err := w.WriteByte(' '); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Enums have a String method, so writeAny will work fine.
 | 
						|
		if err := tm.writeAny(w, fv, props); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if err := w.WriteByte('\n'); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Extensions (the XXX_extensions field).
 | 
						|
	pv := sv.Addr()
 | 
						|
	if _, err := extendable(pv.Interface()); err == nil {
 | 
						|
		if err := tm.writeExtensions(w, pv); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// writeAny writes an arbitrary field.
 | 
						|
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
 | 
						|
	v = reflect.Indirect(v)
 | 
						|
 | 
						|
	// Floats have special cases.
 | 
						|
	if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
 | 
						|
		x := v.Float()
 | 
						|
		var b []byte
 | 
						|
		switch {
 | 
						|
		case math.IsInf(x, 1):
 | 
						|
			b = posInf
 | 
						|
		case math.IsInf(x, -1):
 | 
						|
			b = negInf
 | 
						|
		case math.IsNaN(x):
 | 
						|
			b = nan
 | 
						|
		}
 | 
						|
		if b != nil {
 | 
						|
			_, err := w.Write(b)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		// Other values are handled below.
 | 
						|
	}
 | 
						|
 | 
						|
	// We don't attempt to serialise every possible value type; only those
 | 
						|
	// that can occur in protocol buffers.
 | 
						|
	switch v.Kind() {
 | 
						|
	case reflect.Slice:
 | 
						|
		// Should only be a []byte; repeated fields are handled in writeStruct.
 | 
						|
		if err := writeString(w, string(v.Bytes())); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	case reflect.String:
 | 
						|
		if err := writeString(w, v.String()); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	case reflect.Struct:
 | 
						|
		// Required/optional group/message.
 | 
						|
		var bra, ket byte = '<', '>'
 | 
						|
		if props != nil && props.Wire == "group" {
 | 
						|
			bra, ket = '{', '}'
 | 
						|
		}
 | 
						|
		if err := w.WriteByte(bra); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if !w.compact {
 | 
						|
			if err := w.WriteByte('\n'); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		w.indent()
 | 
						|
		if v.CanAddr() {
 | 
						|
			// Calling v.Interface on a struct causes the reflect package to
 | 
						|
			// copy the entire struct. This is racy with the new Marshaler
 | 
						|
			// since we atomically update the XXX_sizecache.
 | 
						|
			//
 | 
						|
			// Thus, we retrieve a pointer to the struct if possible to avoid
 | 
						|
			// a race since v.Interface on the pointer doesn't copy the struct.
 | 
						|
			//
 | 
						|
			// If v is not addressable, then we are not worried about a race
 | 
						|
			// since it implies that the binary Marshaler cannot possibly be
 | 
						|
			// mutating this value.
 | 
						|
			v = v.Addr()
 | 
						|
		}
 | 
						|
		if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
 | 
						|
			text, err := etm.MarshalText()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			if _, err = w.Write(text); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if v.Kind() == reflect.Ptr {
 | 
						|
				v = v.Elem()
 | 
						|
			}
 | 
						|
			if err := tm.writeStruct(w, v); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		w.unindent()
 | 
						|
		if err := w.WriteByte(ket); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		_, err := fmt.Fprint(w, v.Interface())
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// equivalent to C's isprint.
 | 
						|
func isprint(c byte) bool {
 | 
						|
	return c >= 0x20 && c < 0x7f
 | 
						|
}
 | 
						|
 | 
						|
// writeString writes a string in the protocol buffer text format.
 | 
						|
// It is similar to strconv.Quote except we don't use Go escape sequences,
 | 
						|
// we treat the string as a byte sequence, and we use octal escapes.
 | 
						|
// These differences are to maintain interoperability with the other
 | 
						|
// languages' implementations of the text format.
 | 
						|
func writeString(w *textWriter, s string) error {
 | 
						|
	// use WriteByte here to get any needed indent
 | 
						|
	if err := w.WriteByte('"'); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// Loop over the bytes, not the runes.
 | 
						|
	for i := 0; i < len(s); i++ {
 | 
						|
		var err error
 | 
						|
		// Divergence from C++: we don't escape apostrophes.
 | 
						|
		// There's no need to escape them, and the C++ parser
 | 
						|
		// copes with a naked apostrophe.
 | 
						|
		switch c := s[i]; c {
 | 
						|
		case '\n':
 | 
						|
			_, err = w.w.Write(backslashN)
 | 
						|
		case '\r':
 | 
						|
			_, err = w.w.Write(backslashR)
 | 
						|
		case '\t':
 | 
						|
			_, err = w.w.Write(backslashT)
 | 
						|
		case '"':
 | 
						|
			_, err = w.w.Write(backslashDQ)
 | 
						|
		case '\\':
 | 
						|
			_, err = w.w.Write(backslashBS)
 | 
						|
		default:
 | 
						|
			if isprint(c) {
 | 
						|
				err = w.w.WriteByte(c)
 | 
						|
			} else {
 | 
						|
				_, err = fmt.Fprintf(w.w, "\\%03o", c)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return w.WriteByte('"')
 | 
						|
}
 | 
						|
 | 
						|
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
 | 
						|
	if !w.compact {
 | 
						|
		if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	b := NewBuffer(data)
 | 
						|
	for b.index < len(b.buf) {
 | 
						|
		x, err := b.DecodeVarint()
 | 
						|
		if err != nil {
 | 
						|
			_, err := fmt.Fprintf(w, "/* %v */\n", err)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		wire, tag := x&7, x>>3
 | 
						|
		if wire == WireEndGroup {
 | 
						|
			w.unindent()
 | 
						|
			if _, err := w.Write(endBraceNewline); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if _, err := fmt.Fprint(w, tag); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if wire != WireStartGroup {
 | 
						|
			if err := w.WriteByte(':'); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !w.compact || wire == WireStartGroup {
 | 
						|
			if err := w.WriteByte(' '); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		switch wire {
 | 
						|
		case WireBytes:
 | 
						|
			buf, e := b.DecodeRawBytes(false)
 | 
						|
			if e == nil {
 | 
						|
				_, err = fmt.Fprintf(w, "%q", buf)
 | 
						|
			} else {
 | 
						|
				_, err = fmt.Fprintf(w, "/* %v */", e)
 | 
						|
			}
 | 
						|
		case WireFixed32:
 | 
						|
			x, err = b.DecodeFixed32()
 | 
						|
			err = writeUnknownInt(w, x, err)
 | 
						|
		case WireFixed64:
 | 
						|
			x, err = b.DecodeFixed64()
 | 
						|
			err = writeUnknownInt(w, x, err)
 | 
						|
		case WireStartGroup:
 | 
						|
			err = w.WriteByte('{')
 | 
						|
			w.indent()
 | 
						|
		case WireVarint:
 | 
						|
			x, err = b.DecodeVarint()
 | 
						|
			err = writeUnknownInt(w, x, err)
 | 
						|
		default:
 | 
						|
			_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if err = w.WriteByte('\n'); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func writeUnknownInt(w *textWriter, x uint64, err error) error {
 | 
						|
	if err == nil {
 | 
						|
		_, err = fmt.Fprint(w, x)
 | 
						|
	} else {
 | 
						|
		_, err = fmt.Fprintf(w, "/* %v */", err)
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
type int32Slice []int32
 | 
						|
 | 
						|
func (s int32Slice) Len() int           { return len(s) }
 | 
						|
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
 | 
						|
func (s int32Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 | 
						|
 | 
						|
// writeExtensions writes all the extensions in pv.
 | 
						|
// pv is assumed to be a pointer to a protocol message struct that is extendable.
 | 
						|
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
 | 
						|
	emap := extensionMaps[pv.Type().Elem()]
 | 
						|
	ep, _ := extendable(pv.Interface())
 | 
						|
 | 
						|
	// Order the extensions by ID.
 | 
						|
	// This isn't strictly necessary, but it will give us
 | 
						|
	// canonical output, which will also make testing easier.
 | 
						|
	m, mu := ep.extensionsRead()
 | 
						|
	if m == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	mu.Lock()
 | 
						|
	ids := make([]int32, 0, len(m))
 | 
						|
	for id := range m {
 | 
						|
		ids = append(ids, id)
 | 
						|
	}
 | 
						|
	sort.Sort(int32Slice(ids))
 | 
						|
	mu.Unlock()
 | 
						|
 | 
						|
	for _, extNum := range ids {
 | 
						|
		ext := m[extNum]
 | 
						|
		var desc *ExtensionDesc
 | 
						|
		if emap != nil {
 | 
						|
			desc = emap[extNum]
 | 
						|
		}
 | 
						|
		if desc == nil {
 | 
						|
			// Unknown extension.
 | 
						|
			if err := writeUnknownStruct(w, ext.enc); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		pb, err := GetExtension(ep, desc)
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed getting extension: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Repeated extensions will appear as a slice.
 | 
						|
		if !desc.repeated() {
 | 
						|
			if err := tm.writeExtension(w, desc.Name, pb); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			v := reflect.ValueOf(pb)
 | 
						|
			for i := 0; i < v.Len(); i++ {
 | 
						|
				if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
 | 
						|
	if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if !w.compact {
 | 
						|
		if err := w.WriteByte(' '); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := w.WriteByte('\n'); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (w *textWriter) writeIndent() {
 | 
						|
	if !w.complete {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	remain := w.ind * 2
 | 
						|
	for remain > 0 {
 | 
						|
		n := remain
 | 
						|
		if n > len(spaces) {
 | 
						|
			n = len(spaces)
 | 
						|
		}
 | 
						|
		w.w.Write(spaces[:n])
 | 
						|
		remain -= n
 | 
						|
	}
 | 
						|
	w.complete = false
 | 
						|
}
 | 
						|
 | 
						|
// TextMarshaler is a configurable text format marshaler.
 | 
						|
type TextMarshaler struct {
 | 
						|
	Compact   bool // use compact text format (one line).
 | 
						|
	ExpandAny bool // expand google.protobuf.Any messages of known types
 | 
						|
}
 | 
						|
 | 
						|
// Marshal writes a given protocol buffer in text format.
 | 
						|
// The only errors returned are from w.
 | 
						|
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
 | 
						|
	val := reflect.ValueOf(pb)
 | 
						|
	if pb == nil || val.IsNil() {
 | 
						|
		w.Write([]byte("<nil>"))
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	var bw *bufio.Writer
 | 
						|
	ww, ok := w.(writer)
 | 
						|
	if !ok {
 | 
						|
		bw = bufio.NewWriter(w)
 | 
						|
		ww = bw
 | 
						|
	}
 | 
						|
	aw := &textWriter{
 | 
						|
		w:        ww,
 | 
						|
		complete: true,
 | 
						|
		compact:  tm.Compact,
 | 
						|
	}
 | 
						|
 | 
						|
	if etm, ok := pb.(encoding.TextMarshaler); ok {
 | 
						|
		text, err := etm.MarshalText()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if _, err = aw.Write(text); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if bw != nil {
 | 
						|
			return bw.Flush()
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	// Dereference the received pointer so we don't have outer < and >.
 | 
						|
	v := reflect.Indirect(val)
 | 
						|
	if err := tm.writeStruct(aw, v); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if bw != nil {
 | 
						|
		return bw.Flush()
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Text is the same as Marshal, but returns the string directly.
 | 
						|
func (tm *TextMarshaler) Text(pb Message) string {
 | 
						|
	var buf bytes.Buffer
 | 
						|
	tm.Marshal(&buf, pb)
 | 
						|
	return buf.String()
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	defaultTextMarshaler = TextMarshaler{}
 | 
						|
	compactTextMarshaler = TextMarshaler{Compact: true}
 | 
						|
)
 | 
						|
 | 
						|
// TODO: consider removing some of the Marshal functions below.
 | 
						|
 | 
						|
// MarshalText writes a given protocol buffer in text format.
 | 
						|
// The only errors returned are from w.
 | 
						|
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
 | 
						|
 | 
						|
// MarshalTextString is the same as MarshalText, but returns the string directly.
 | 
						|
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
 | 
						|
 | 
						|
// CompactText writes a given protocol buffer in compact text format (one line).
 | 
						|
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
 | 
						|
 | 
						|
// CompactTextString is the same as CompactText, but returns the string directly.
 | 
						|
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
 |