podman
1// Protocol Buffers for Go with Gadgets
2//
3// Copyright (c) 2013, The GoGo Authors. All rights reserved.
4// http://github.com/gogo/protobuf
5//
6// Go support for Protocol Buffers - Google's data interchange format
7//
8// Copyright 2010 The Go Authors. All rights reserved.
9// https://github.com/golang/protobuf
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// * Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17// * Redistributions in binary form must reproduce the above
18// copyright notice, this list of conditions and the following disclaimer
19// in the documentation and/or other materials provided with the
20// distribution.
21// * Neither the name of Google Inc. nor the names of its
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37package proto38
39// Functions for writing the text protocol buffer format.
40
41import (42"bufio"43"bytes"44"encoding"45"errors"46"fmt"47"io"48"log"49"math"50"reflect"51"sort"52"strings"53"sync"54"time"55)
56
57var (58newline = []byte("\n")59spaces = []byte(" ")60endBraceNewline = []byte("}\n")61backslashN = []byte{'\\', 'n'}62backslashR = []byte{'\\', 'r'}63backslashT = []byte{'\\', 't'}64backslashDQ = []byte{'\\', '"'}65backslashBS = []byte{'\\', '\\'}66posInf = []byte("inf")67negInf = []byte("-inf")68nan = []byte("nan")69)
70
71type writer interface {72io.Writer73WriteByte(byte) error74}
75
76// textWriter is an io.Writer that tracks its indentation level.
77type textWriter struct {78ind int79complete bool // if the current position is a complete line80compact bool // whether to write out as a one-liner81w writer
82}
83
84func (w *textWriter) WriteString(s string) (n int, err error) {85if !strings.Contains(s, "\n") {86if !w.compact && w.complete {87w.writeIndent()88}89w.complete = false90return io.WriteString(w.w, s)91}92// WriteString is typically called without newlines, so this93// codepath and its copy are rare. We copy to avoid94// duplicating all of Write's logic here.95return w.Write([]byte(s))96}
97
98func (w *textWriter) Write(p []byte) (n int, err error) {99newlines := bytes.Count(p, newline)100if newlines == 0 {101if !w.compact && w.complete {102w.writeIndent()103}104n, err = w.w.Write(p)105w.complete = false106return n, err107}108
109frags := bytes.SplitN(p, newline, newlines+1)110if w.compact {111for i, frag := range frags {112if i > 0 {113if err := w.w.WriteByte(' '); err != nil {114return n, err115}116n++117}118nn, err := w.w.Write(frag)119n += nn120if err != nil {121return n, err122}123}124return n, nil125}126
127for i, frag := range frags {128if w.complete {129w.writeIndent()130}131nn, err := w.w.Write(frag)132n += nn133if err != nil {134return n, err135}136if i+1 < len(frags) {137if err := w.w.WriteByte('\n'); err != nil {138return n, err139}140n++141}142}143w.complete = len(frags[len(frags)-1]) == 0144return n, nil145}
146
147func (w *textWriter) WriteByte(c byte) error {148if w.compact && c == '\n' {149c = ' '150}151if !w.compact && w.complete {152w.writeIndent()153}154err := w.w.WriteByte(c)155w.complete = c == '\n'156return err157}
158
159func (w *textWriter) indent() { w.ind++ }160
161func (w *textWriter) unindent() {162if w.ind == 0 {163log.Print("proto: textWriter unindented too far")164return165}166w.ind--167}
168
169func writeName(w *textWriter, props *Properties) error {170if _, err := w.WriteString(props.OrigName); err != nil {171return err172}173if props.Wire != "group" {174return w.WriteByte(':')175}176return nil177}
178
179func requiresQuotes(u string) bool {180// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.181for _, ch := range u {182switch {183case ch == '.' || ch == '/' || ch == '_':184continue185case '0' <= ch && ch <= '9':186continue187case 'A' <= ch && ch <= 'Z':188continue189case 'a' <= ch && ch <= 'z':190continue191default:192return true193}194}195return false196}
197
198// isAny reports whether sv is a google.protobuf.Any message
199func isAny(sv reflect.Value) bool {200type wkt interface {201XXX_WellKnownType() string202}203t, ok := sv.Addr().Interface().(wkt)204return ok && t.XXX_WellKnownType() == "Any"205}
206
207// writeProto3Any writes an expanded google.protobuf.Any message.
208//
209// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
210// required messages are not linked in).
211//
212// It returns (true, error) when sv was written in expanded format or an error
213// was encountered.
214func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {215turl := sv.FieldByName("TypeUrl")216val := sv.FieldByName("Value")217if !turl.IsValid() || !val.IsValid() {218return true, errors.New("proto: invalid google.protobuf.Any message")219}220
221b, ok := val.Interface().([]byte)222if !ok {223return true, errors.New("proto: invalid google.protobuf.Any message")224}225
226parts := strings.Split(turl.String(), "/")227mt := MessageType(parts[len(parts)-1])228if mt == nil {229return false, nil230}231m := reflect.New(mt.Elem())232if err := Unmarshal(b, m.Interface().(Message)); err != nil {233return false, nil234}235w.Write([]byte("["))236u := turl.String()237if requiresQuotes(u) {238writeString(w, u)239} else {240w.Write([]byte(u))241}242if w.compact {243w.Write([]byte("]:<"))244} else {245w.Write([]byte("]: <\n"))246w.ind++247}248if err := tm.writeStruct(w, m.Elem()); err != nil {249return true, err250}251if w.compact {252w.Write([]byte("> "))253} else {254w.ind--255w.Write([]byte(">\n"))256}257return true, nil258}
259
260func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {261if tm.ExpandAny && isAny(sv) {262if canExpand, err := tm.writeProto3Any(w, sv); canExpand {263return err264}265}266st := sv.Type()267sprops := GetProperties(st)268for i := 0; i < sv.NumField(); i++ {269fv := sv.Field(i)270props := sprops.Prop[i]271name := st.Field(i).Name272
273if name == "XXX_NoUnkeyedLiteral" {274continue275}276
277if strings.HasPrefix(name, "XXX_") {278// There are two XXX_ fields:279// XXX_unrecognized []byte280// XXX_extensions map[int32]proto.Extension281// The first is handled here;282// the second is handled at the bottom of this function.283if name == "XXX_unrecognized" && !fv.IsNil() {284if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {285return err286}287}288continue289}290if fv.Kind() == reflect.Ptr && fv.IsNil() {291// Field not filled in. This could be an optional field or292// a required field that wasn't filled in. Either way, there293// isn't anything we can show for it.294continue295}296if fv.Kind() == reflect.Slice && fv.IsNil() {297// Repeated field that is empty, or a bytes field that is unused.298continue299}300
301if props.Repeated && fv.Kind() == reflect.Slice {302// Repeated field.303for j := 0; j < fv.Len(); j++ {304if err := writeName(w, props); err != nil {305return err306}307if !w.compact {308if err := w.WriteByte(' '); err != nil {309return err310}311}312v := fv.Index(j)313if v.Kind() == reflect.Ptr && v.IsNil() {314// A nil message in a repeated field is not valid,315// but we can handle that more gracefully than panicking.316if _, err := w.Write([]byte("<nil>\n")); err != nil {317return err318}319continue320}321if len(props.Enum) > 0 {322if err := tm.writeEnum(w, v, props); err != nil {323return err324}325} else if err := tm.writeAny(w, v, props); err != nil {326return err327}328if err := w.WriteByte('\n'); err != nil {329return err330}331}332continue333}334if fv.Kind() == reflect.Map {335// Map fields are rendered as a repeated struct with key/value fields.336keys := fv.MapKeys()337sort.Sort(mapKeys(keys))338for _, key := range keys {339val := fv.MapIndex(key)340if err := writeName(w, props); err != nil {341return err342}343if !w.compact {344if err := w.WriteByte(' '); err != nil {345return err346}347}348// open struct349if err := w.WriteByte('<'); err != nil {350return err351}352if !w.compact {353if err := w.WriteByte('\n'); err != nil {354return err355}356}357w.indent()358// key359if _, err := w.WriteString("key:"); err != nil {360return err361}362if !w.compact {363if err := w.WriteByte(' '); err != nil {364return err365}366}367if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {368return err369}370if err := w.WriteByte('\n'); err != nil {371return err372}373// nil values aren't legal, but we can avoid panicking because of them.374if val.Kind() != reflect.Ptr || !val.IsNil() {375// value376if _, err := w.WriteString("value:"); err != nil {377return err378}379if !w.compact {380if err := w.WriteByte(' '); err != nil {381return err382}383}384if err := tm.writeAny(w, val, props.MapValProp); err != nil {385return err386}387if err := w.WriteByte('\n'); err != nil {388return err389}390}391// close struct392w.unindent()393if err := w.WriteByte('>'); err != nil {394return err395}396if err := w.WriteByte('\n'); err != nil {397return err398}399}400continue401}402if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 {403// empty bytes field404continue405}406if props.proto3 && fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {407// proto3 non-repeated scalar field; skip if zero value408if isProto3Zero(fv) {409continue410}411}412
413if fv.Kind() == reflect.Interface {414// Check if it is a oneof.415if st.Field(i).Tag.Get("protobuf_oneof") != "" {416// fv is nil, or holds a pointer to generated struct.417// That generated struct has exactly one field,418// which has a protobuf struct tag.419if fv.IsNil() {420continue421}422inner := fv.Elem().Elem() // interface -> *T -> T423tag := inner.Type().Field(0).Tag.Get("protobuf")424props = new(Properties) // Overwrite the outer props var, but not its pointee.425props.Parse(tag)426// Write the value in the oneof, not the oneof itself.427fv = inner.Field(0)428
429// Special case to cope with malformed messages gracefully:430// If the value in the oneof is a nil pointer, don't panic431// in writeAny.432if fv.Kind() == reflect.Ptr && fv.IsNil() {433// Use errors.New so writeAny won't render quotes.434msg := errors.New("/* nil */")435fv = reflect.ValueOf(&msg).Elem()436}437}438}439
440if err := writeName(w, props); err != nil {441return err442}443if !w.compact {444if err := w.WriteByte(' '); err != nil {445return err446}447}448
449if len(props.Enum) > 0 {450if err := tm.writeEnum(w, fv, props); err != nil {451return err452}453} else if err := tm.writeAny(w, fv, props); err != nil {454return err455}456
457if err := w.WriteByte('\n'); err != nil {458return err459}460}461
462// Extensions (the XXX_extensions field).463pv := sv464if pv.CanAddr() {465pv = sv.Addr()466} else {467pv = reflect.New(sv.Type())468pv.Elem().Set(sv)469}470if _, err := extendable(pv.Interface()); err == nil {471if err := tm.writeExtensions(w, pv); err != nil {472return err473}474}475
476return nil477}
478
479var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()480
481// writeAny writes an arbitrary field.
482func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {483v = reflect.Indirect(v)484
485if props != nil {486if len(props.CustomType) > 0 {487custom, ok := v.Interface().(Marshaler)488if ok {489data, err := custom.Marshal()490if err != nil {491return err492}493if err := writeString(w, string(data)); err != nil {494return err495}496return nil497}498} else if len(props.CastType) > 0 {499if _, ok := v.Interface().(interface {500String() string501}); ok {502switch v.Kind() {503case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,504reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:505_, err := fmt.Fprintf(w, "%d", v.Interface())506return err507}508}509} else if props.StdTime {510t, ok := v.Interface().(time.Time)511if !ok {512return fmt.Errorf("stdtime is not time.Time, but %T", v.Interface())513}514tproto, err := timestampProto(t)515if err != nil {516return err517}518propsCopy := *props // Make a copy so that this is goroutine-safe519propsCopy.StdTime = false520err = tm.writeAny(w, reflect.ValueOf(tproto), &propsCopy)521return err522} else if props.StdDuration {523d, ok := v.Interface().(time.Duration)524if !ok {525return fmt.Errorf("stdtime is not time.Duration, but %T", v.Interface())526}527dproto := durationProto(d)528propsCopy := *props // Make a copy so that this is goroutine-safe529propsCopy.StdDuration = false530err := tm.writeAny(w, reflect.ValueOf(dproto), &propsCopy)531return err532}533}534
535// Floats have special cases.536if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {537x := v.Float()538var b []byte539switch {540case math.IsInf(x, 1):541b = posInf542case math.IsInf(x, -1):543b = negInf544case math.IsNaN(x):545b = nan546}547if b != nil {548_, err := w.Write(b)549return err550}551// Other values are handled below.552}553
554// We don't attempt to serialise every possible value type; only those555// that can occur in protocol buffers.556switch v.Kind() {557case reflect.Slice:558// Should only be a []byte; repeated fields are handled in writeStruct.559if err := writeString(w, string(v.Bytes())); err != nil {560return err561}562case reflect.String:563if err := writeString(w, v.String()); err != nil {564return err565}566case reflect.Struct:567// Required/optional group/message.568var bra, ket byte = '<', '>'569if props != nil && props.Wire == "group" {570bra, ket = '{', '}'571}572if err := w.WriteByte(bra); err != nil {573return err574}575if !w.compact {576if err := w.WriteByte('\n'); err != nil {577return err578}579}580w.indent()581if v.CanAddr() {582// Calling v.Interface on a struct causes the reflect package to583// copy the entire struct. This is racy with the new Marshaler584// since we atomically update the XXX_sizecache.585//586// Thus, we retrieve a pointer to the struct if possible to avoid587// a race since v.Interface on the pointer doesn't copy the struct.588//589// If v is not addressable, then we are not worried about a race590// since it implies that the binary Marshaler cannot possibly be591// mutating this value.592v = v.Addr()593}594if v.Type().Implements(textMarshalerType) {595text, err := v.Interface().(encoding.TextMarshaler).MarshalText()596if err != nil {597return err598}599if _, err = w.Write(text); err != nil {600return err601}602} else {603if v.Kind() == reflect.Ptr {604v = v.Elem()605}606if err := tm.writeStruct(w, v); err != nil {607return err608}609}610w.unindent()611if err := w.WriteByte(ket); err != nil {612return err613}614default:615_, err := fmt.Fprint(w, v.Interface())616return err617}618return nil619}
620
621// equivalent to C's isprint.
622func isprint(c byte) bool {623return c >= 0x20 && c < 0x7f624}
625
626// writeString writes a string in the protocol buffer text format.
627// It is similar to strconv.Quote except we don't use Go escape sequences,
628// we treat the string as a byte sequence, and we use octal escapes.
629// These differences are to maintain interoperability with the other
630// languages' implementations of the text format.
631func writeString(w *textWriter, s string) error {632// use WriteByte here to get any needed indent633if err := w.WriteByte('"'); err != nil {634return err635}636// Loop over the bytes, not the runes.637for i := 0; i < len(s); i++ {638var err error639// Divergence from C++: we don't escape apostrophes.640// There's no need to escape them, and the C++ parser641// copes with a naked apostrophe.642switch c := s[i]; c {643case '\n':644_, err = w.w.Write(backslashN)645case '\r':646_, err = w.w.Write(backslashR)647case '\t':648_, err = w.w.Write(backslashT)649case '"':650_, err = w.w.Write(backslashDQ)651case '\\':652_, err = w.w.Write(backslashBS)653default:654if isprint(c) {655err = w.w.WriteByte(c)656} else {657_, err = fmt.Fprintf(w.w, "\\%03o", c)658}659}660if err != nil {661return err662}663}664return w.WriteByte('"')665}
666
667func writeUnknownStruct(w *textWriter, data []byte) (err error) {668if !w.compact {669if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {670return err671}672}673b := NewBuffer(data)674for b.index < len(b.buf) {675x, err := b.DecodeVarint()676if err != nil {677_, ferr := fmt.Fprintf(w, "/* %v */\n", err)678return ferr679}680wire, tag := x&7, x>>3681if wire == WireEndGroup {682w.unindent()683if _, werr := w.Write(endBraceNewline); werr != nil {684return werr685}686continue687}688if _, ferr := fmt.Fprint(w, tag); ferr != nil {689return ferr690}691if wire != WireStartGroup {692if err = w.WriteByte(':'); err != nil {693return err694}695}696if !w.compact || wire == WireStartGroup {697if err = w.WriteByte(' '); err != nil {698return err699}700}701switch wire {702case WireBytes:703buf, e := b.DecodeRawBytes(false)704if e == nil {705_, err = fmt.Fprintf(w, "%q", buf)706} else {707_, err = fmt.Fprintf(w, "/* %v */", e)708}709case WireFixed32:710x, err = b.DecodeFixed32()711err = writeUnknownInt(w, x, err)712case WireFixed64:713x, err = b.DecodeFixed64()714err = writeUnknownInt(w, x, err)715case WireStartGroup:716err = w.WriteByte('{')717w.indent()718case WireVarint:719x, err = b.DecodeVarint()720err = writeUnknownInt(w, x, err)721default:722_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)723}724if err != nil {725return err726}727if err := w.WriteByte('\n'); err != nil {728return err729}730}731return nil732}
733
734func writeUnknownInt(w *textWriter, x uint64, err error) error {735if err == nil {736_, err = fmt.Fprint(w, x)737} else {738_, err = fmt.Fprintf(w, "/* %v */", err)739}740return err741}
742
743type int32Slice []int32744
745func (s int32Slice) Len() int { return len(s) }746func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }747func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }748
749// writeExtensions writes all the extensions in pv.
750// pv is assumed to be a pointer to a protocol message struct that is extendable.
751func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {752emap := extensionMaps[pv.Type().Elem()]753e := pv.Interface().(Message)754
755var m map[int32]Extension756var mu sync.Locker757if em, ok := e.(extensionsBytes); ok {758eb := em.GetExtensions()759var err error760m, err = BytesToExtensionsMap(*eb)761if err != nil {762return err763}764mu = notLocker{}765} else if _, ok := e.(extendableProto); ok {766ep, _ := extendable(e)767m, mu = ep.extensionsRead()768if m == nil {769return nil770}771}772
773// Order the extensions by ID.774// This isn't strictly necessary, but it will give us775// canonical output, which will also make testing easier.776
777mu.Lock()778ids := make([]int32, 0, len(m))779for id := range m {780ids = append(ids, id)781}782sort.Sort(int32Slice(ids))783mu.Unlock()784
785for _, extNum := range ids {786ext := m[extNum]787var desc *ExtensionDesc788if emap != nil {789desc = emap[extNum]790}791if desc == nil {792// Unknown extension.793if err := writeUnknownStruct(w, ext.enc); err != nil {794return err795}796continue797}798
799pb, err := GetExtension(e, desc)800if err != nil {801return fmt.Errorf("failed getting extension: %v", err)802}803
804// Repeated extensions will appear as a slice.805if !desc.repeated() {806if err := tm.writeExtension(w, desc.Name, pb); err != nil {807return err808}809} else {810v := reflect.ValueOf(pb)811for i := 0; i < v.Len(); i++ {812if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {813return err814}815}816}817}818return nil819}
820
821func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {822if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {823return err824}825if !w.compact {826if err := w.WriteByte(' '); err != nil {827return err828}829}830if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {831return err832}833if err := w.WriteByte('\n'); err != nil {834return err835}836return nil837}
838
839func (w *textWriter) writeIndent() {840if !w.complete {841return842}843remain := w.ind * 2844for remain > 0 {845n := remain846if n > len(spaces) {847n = len(spaces)848}849w.w.Write(spaces[:n])850remain -= n851}852w.complete = false853}
854
855// TextMarshaler is a configurable text format marshaler.
856type TextMarshaler struct {857Compact bool // use compact text format (one line).858ExpandAny bool // expand google.protobuf.Any messages of known types859}
860
861// Marshal writes a given protocol buffer in text format.
862// The only errors returned are from w.
863func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {864val := reflect.ValueOf(pb)865if pb == nil || val.IsNil() {866w.Write([]byte("<nil>"))867return nil868}869var bw *bufio.Writer870ww, ok := w.(writer)871if !ok {872bw = bufio.NewWriter(w)873ww = bw874}875aw := &textWriter{876w: ww,877complete: true,878compact: tm.Compact,879}880
881if etm, ok := pb.(encoding.TextMarshaler); ok {882text, err := etm.MarshalText()883if err != nil {884return err885}886if _, err = aw.Write(text); err != nil {887return err888}889if bw != nil {890return bw.Flush()891}892return nil893}894// Dereference the received pointer so we don't have outer < and >.895v := reflect.Indirect(val)896if err := tm.writeStruct(aw, v); err != nil {897return err898}899if bw != nil {900return bw.Flush()901}902return nil903}
904
905// Text is the same as Marshal, but returns the string directly.
906func (tm *TextMarshaler) Text(pb Message) string {907var buf bytes.Buffer908tm.Marshal(&buf, pb)909return buf.String()910}
911
912var (913defaultTextMarshaler = TextMarshaler{}914compactTextMarshaler = TextMarshaler{Compact: true}915)
916
917// TODO: consider removing some of the Marshal functions below.
918
919// MarshalText writes a given protocol buffer in text format.
920// The only errors returned are from w.
921func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }922
923// MarshalTextString is the same as MarshalText, but returns the string directly.
924func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }925
926// CompactText writes a given protocol buffer in compact text format (one line).
927func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }928
929// CompactTextString is the same as CompactText, but returns the string directly.
930func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }931