1// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 The Go Authors.  All rights reserved.
4// https://github.com/golang/protobuf
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10//     * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//     * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16//     * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32package proto
33
34// Functions for writing the text protocol buffer format.
35
36import (
37	"bufio"
38	"bytes"
39	"encoding"
40	"errors"
41	"fmt"
42	"io"
43	"log"
44	"math"
45	"reflect"
46	"sort"
47	"strings"
48)
49
50var (
51	newline         = []byte("\n")
52	spaces          = []byte("                                        ")
53	gtNewline       = []byte(">\n")
54	endBraceNewline = []byte("}\n")
55	backslashN      = []byte{'\\', 'n'}
56	backslashR      = []byte{'\\', 'r'}
57	backslashT      = []byte{'\\', 't'}
58	backslashDQ     = []byte{'\\', '"'}
59	backslashBS     = []byte{'\\', '\\'}
60	posInf          = []byte("inf")
61	negInf          = []byte("-inf")
62	nan             = []byte("nan")
63)
64
65type writer interface {
66	io.Writer
67	WriteByte(byte) error
68}
69
70// textWriter is an io.Writer that tracks its indentation level.
71type textWriter struct {
72	ind      int
73	complete bool // if the current position is a complete line
74	compact  bool // whether to write out as a one-liner
75	w        writer
76}
77
78func (w *textWriter) WriteString(s string) (n int, err error) {
79	if !strings.Contains(s, "\n") {
80		if !w.compact && w.complete {
81			w.writeIndent()
82		}
83		w.complete = false
84		return io.WriteString(w.w, s)
85	}
86	// WriteString is typically called without newlines, so this
87	// codepath and its copy are rare.  We copy to avoid
88	// duplicating all of Write's logic here.
89	return w.Write([]byte(s))
90}
91
92func (w *textWriter) Write(p []byte) (n int, err error) {
93	newlines := bytes.Count(p, newline)
94	if newlines == 0 {
95		if !w.compact && w.complete {
96			w.writeIndent()
97		}
98		n, err = w.w.Write(p)
99		w.complete = false
100		return n, err
101	}
102
103	frags := bytes.SplitN(p, newline, newlines+1)
104	if w.compact {
105		for i, frag := range frags {
106			if i > 0 {
107				if err := w.w.WriteByte(' '); err != nil {
108					return n, err
109				}
110				n++
111			}
112			nn, err := w.w.Write(frag)
113			n += nn
114			if err != nil {
115				return n, err
116			}
117		}
118		return n, nil
119	}
120
121	for i, frag := range frags {
122		if w.complete {
123			w.writeIndent()
124		}
125		nn, err := w.w.Write(frag)
126		n += nn
127		if err != nil {
128			return n, err
129		}
130		if i+1 < len(frags) {
131			if err := w.w.WriteByte('\n'); err != nil {
132				return n, err
133			}
134			n++
135		}
136	}
137	w.complete = len(frags[len(frags)-1]) == 0
138	return n, nil
139}
140
141func (w *textWriter) WriteByte(c byte) error {
142	if w.compact && c == '\n' {
143		c = ' '
144	}
145	if !w.compact && w.complete {
146		w.writeIndent()
147	}
148	err := w.w.WriteByte(c)
149	w.complete = c == '\n'
150	return err
151}
152
153func (w *textWriter) indent() { w.ind++ }
154
155func (w *textWriter) unindent() {
156	if w.ind == 0 {
157		log.Print("proto: textWriter unindented too far")
158		return
159	}
160	w.ind--
161}
162
163func writeName(w *textWriter, props *Properties) error {
164	if _, err := w.WriteString(props.OrigName); err != nil {
165		return err
166	}
167	if props.Wire != "group" {
168		return w.WriteByte(':')
169	}
170	return nil
171}
172
173// raw is the interface satisfied by RawMessage.
174type raw interface {
175	Bytes() []byte
176}
177
178func requiresQuotes(u string) bool {
179	// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
180	for _, ch := range u {
181		switch {
182		case ch == '.' || ch == '/' || ch == '_':
183			continue
184		case '0' <= ch && ch <= '9':
185			continue
186		case 'A' <= ch && ch <= 'Z':
187			continue
188		case 'a' <= ch && ch <= 'z':
189			continue
190		default:
191			return true
192		}
193	}
194	return false
195}
196
197// isAny reports whether sv is a google.protobuf.Any message
198func isAny(sv reflect.Value) bool {
199	type wkt interface {
200		XXX_WellKnownType() string
201	}
202	t, ok := sv.Addr().Interface().(wkt)
203	return ok && t.XXX_WellKnownType() == "Any"
204}
205
206// writeProto3Any writes an expanded google.protobuf.Any message.
207//
208// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
209// required messages are not linked in).
210//
211// It returns (true, error) when sv was written in expanded format or an error
212// was encountered.
213func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
214	turl := sv.FieldByName("TypeUrl")
215	val := sv.FieldByName("Value")
216	if !turl.IsValid() || !val.IsValid() {
217		return true, errors.New("proto: invalid google.protobuf.Any message")
218	}
219
220	b, ok := val.Interface().([]byte)
221	if !ok {
222		return true, errors.New("proto: invalid google.protobuf.Any message")
223	}
224
225	parts := strings.Split(turl.String(), "/")
226	mt := MessageType(parts[len(parts)-1])
227	if mt == nil {
228		return false, nil
229	}
230	m := reflect.New(mt.Elem())
231	if err := Unmarshal(b, m.Interface().(Message)); err != nil {
232		return false, nil
233	}
234	w.Write([]byte("["))
235	u := turl.String()
236	if requiresQuotes(u) {
237		writeString(w, u)
238	} else {
239		w.Write([]byte(u))
240	}
241	if w.compact {
242		w.Write([]byte("]:<"))
243	} else {
244		w.Write([]byte("]: <\n"))
245		w.ind++
246	}
247	if err := tm.writeStruct(w, m.Elem()); err != nil {
248		return true, err
249	}
250	if w.compact {
251		w.Write([]byte("> "))
252	} else {
253		w.ind--
254		w.Write([]byte(">\n"))
255	}
256	return true, nil
257}
258
259func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
260	if tm.ExpandAny && isAny(sv) {
261		if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
262			return err
263		}
264	}
265	st := sv.Type()
266	sprops := GetProperties(st)
267	for i := 0; i < sv.NumField(); i++ {
268		fv := sv.Field(i)
269		props := sprops.Prop[i]
270		name := st.Field(i).Name
271
272		if strings.HasPrefix(name, "XXX_") {
273			// There are two XXX_ fields:
274			//   XXX_unrecognized []byte
275			//   XXX_extensions   map[int32]proto.Extension
276			// The first is handled here;
277			// the second is handled at the bottom of this function.
278			if name == "XXX_unrecognized" && !fv.IsNil() {
279				if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
280					return err
281				}
282			}
283			continue
284		}
285		if fv.Kind() == reflect.Ptr && fv.IsNil() {
286			// Field not filled in. This could be an optional field or
287			// a required field that wasn't filled in. Either way, there
288			// isn't anything we can show for it.
289			continue
290		}
291		if fv.Kind() == reflect.Slice && fv.IsNil() {
292			// Repeated field that is empty, or a bytes field that is unused.
293			continue
294		}
295
296		if props.Repeated && fv.Kind() == reflect.Slice {
297			// Repeated field.
298			for j := 0; j < fv.Len(); j++ {
299				if err := writeName(w, props); err != nil {
300					return err
301				}
302				if !w.compact {
303					if err := w.WriteByte(' '); err != nil {
304						return err
305					}
306				}
307				v := fv.Index(j)
308				if v.Kind() == reflect.Ptr && v.IsNil() {
309					// A nil message in a repeated field is not valid,
310					// but we can handle that more gracefully than panicking.
311					if _, err := w.Write([]byte("<nil>\n")); err != nil {
312						return err
313					}
314					continue
315				}
316				if err := tm.writeAny(w, v, props); err != nil {
317					return err
318				}
319				if err := w.WriteByte('\n'); err != nil {
320					return err
321				}
322			}
323			continue
324		}
325		if fv.Kind() == reflect.Map {
326			// Map fields are rendered as a repeated struct with key/value fields.
327			keys := fv.MapKeys()
328			sort.Sort(mapKeys(keys))
329			for _, key := range keys {
330				val := fv.MapIndex(key)
331				if err := writeName(w, props); err != nil {
332					return err
333				}
334				if !w.compact {
335					if err := w.WriteByte(' '); err != nil {
336						return err
337					}
338				}
339				// open struct
340				if err := w.WriteByte('<'); err != nil {
341					return err
342				}
343				if !w.compact {
344					if err := w.WriteByte('\n'); err != nil {
345						return err
346					}
347				}
348				w.indent()
349				// key
350				if _, err := w.WriteString("key:"); err != nil {
351					return err
352				}
353				if !w.compact {
354					if err := w.WriteByte(' '); err != nil {
355						return err
356					}
357				}
358				if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
359					return err
360				}
361				if err := w.WriteByte('\n'); err != nil {
362					return err
363				}
364				// nil values aren't legal, but we can avoid panicking because of them.
365				if val.Kind() != reflect.Ptr || !val.IsNil() {
366					// value
367					if _, err := w.WriteString("value:"); err != nil {
368						return err
369					}
370					if !w.compact {
371						if err := w.WriteByte(' '); err != nil {
372							return err
373						}
374					}
375					if err := tm.writeAny(w, val, props.mvalprop); err != nil {
376						return err
377					}
378					if err := w.WriteByte('\n'); err != nil {
379						return err
380					}
381				}
382				// close struct
383				w.unindent()
384				if err := w.WriteByte('>'); err != nil {
385					return err
386				}
387				if err := w.WriteByte('\n'); err != nil {
388					return err
389				}
390			}
391			continue
392		}
393		if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 {
394			// empty bytes field
395			continue
396		}
397		if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {
398			// proto3 non-repeated scalar field; skip if zero value
399			if isProto3Zero(fv) {
400				continue
401			}
402		}
403
404		if fv.Kind() == reflect.Interface {
405			// Check if it is a oneof.
406			if st.Field(i).Tag.Get("protobuf_oneof") != "" {
407				// fv is nil, or holds a pointer to generated struct.
408				// That generated struct has exactly one field,
409				// which has a protobuf struct tag.
410				if fv.IsNil() {
411					continue
412				}
413				inner := fv.Elem().Elem() // interface -> *T -> T
414				tag := inner.Type().Field(0).Tag.Get("protobuf")
415				props = new(Properties) // Overwrite the outer props var, but not its pointee.
416				props.Parse(tag)
417				// Write the value in the oneof, not the oneof itself.
418				fv = inner.Field(0)
419
420				// Special case to cope with malformed messages gracefully:
421				// If the value in the oneof is a nil pointer, don't panic
422				// in writeAny.
423				if fv.Kind() == reflect.Ptr && fv.IsNil() {
424					// Use errors.New so writeAny won't render quotes.
425					msg := errors.New("/* nil */")
426					fv = reflect.ValueOf(&msg).Elem()
427				}
428			}
429		}
430
431		if err := writeName(w, props); err != nil {
432			return err
433		}
434		if !w.compact {
435			if err := w.WriteByte(' '); err != nil {
436				return err
437			}
438		}
439		if b, ok := fv.Interface().(raw); ok {
440			if err := writeRaw(w, b.Bytes()); err != nil {
441				return err
442			}
443			continue
444		}
445
446		// Enums have a String method, so writeAny will work fine.
447		if err := tm.writeAny(w, fv, props); err != nil {
448			return err
449		}
450
451		if err := w.WriteByte('\n'); err != nil {
452			return err
453		}
454	}
455
456	// Extensions (the XXX_extensions field).
457	pv := sv.Addr()
458	if _, ok := extendable(pv.Interface()); ok {
459		if err := tm.writeExtensions(w, pv); err != nil {
460			return err
461		}
462	}
463
464	return nil
465}
466
467// writeRaw writes an uninterpreted raw message.
468func writeRaw(w *textWriter, b []byte) error {
469	if err := w.WriteByte('<'); err != nil {
470		return err
471	}
472	if !w.compact {
473		if err := w.WriteByte('\n'); err != nil {
474			return err
475		}
476	}
477	w.indent()
478	if err := writeUnknownStruct(w, b); err != nil {
479		return err
480	}
481	w.unindent()
482	if err := w.WriteByte('>'); err != nil {
483		return err
484	}
485	return nil
486}
487
488// writeAny writes an arbitrary field.
489func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
490	v = reflect.Indirect(v)
491
492	// Floats have special cases.
493	if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
494		x := v.Float()
495		var b []byte
496		switch {
497		case math.IsInf(x, 1):
498			b = posInf
499		case math.IsInf(x, -1):
500			b = negInf
501		case math.IsNaN(x):
502			b = nan
503		}
504		if b != nil {
505			_, err := w.Write(b)
506			return err
507		}
508		// Other values are handled below.
509	}
510
511	// We don't attempt to serialise every possible value type; only those
512	// that can occur in protocol buffers.
513	switch v.Kind() {
514	case reflect.Slice:
515		// Should only be a []byte; repeated fields are handled in writeStruct.
516		if err := writeString(w, string(v.Bytes())); err != nil {
517			return err
518		}
519	case reflect.String:
520		if err := writeString(w, v.String()); err != nil {
521			return err
522		}
523	case reflect.Struct:
524		// Required/optional group/message.
525		var bra, ket byte = '<', '>'
526		if props != nil && props.Wire == "group" {
527			bra, ket = '{', '}'
528		}
529		if err := w.WriteByte(bra); err != nil {
530			return err
531		}
532		if !w.compact {
533			if err := w.WriteByte('\n'); err != nil {
534				return err
535			}
536		}
537		w.indent()
538		if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
539			text, err := etm.MarshalText()
540			if err != nil {
541				return err
542			}
543			if _, err = w.Write(text); err != nil {
544				return err
545			}
546		} else if err := tm.writeStruct(w, v); err != nil {
547			return err
548		}
549		w.unindent()
550		if err := w.WriteByte(ket); err != nil {
551			return err
552		}
553	default:
554		_, err := fmt.Fprint(w, v.Interface())
555		return err
556	}
557	return nil
558}
559
560// equivalent to C's isprint.
561func isprint(c byte) bool {
562	return c >= 0x20 && c < 0x7f
563}
564
565// writeString writes a string in the protocol buffer text format.
566// It is similar to strconv.Quote except we don't use Go escape sequences,
567// we treat the string as a byte sequence, and we use octal escapes.
568// These differences are to maintain interoperability with the other
569// languages' implementations of the text format.
570func writeString(w *textWriter, s string) error {
571	// use WriteByte here to get any needed indent
572	if err := w.WriteByte('"'); err != nil {
573		return err
574	}
575	// Loop over the bytes, not the runes.
576	for i := 0; i < len(s); i++ {
577		var err error
578		// Divergence from C++: we don't escape apostrophes.
579		// There's no need to escape them, and the C++ parser
580		// copes with a naked apostrophe.
581		switch c := s[i]; c {
582		case '\n':
583			_, err = w.w.Write(backslashN)
584		case '\r':
585			_, err = w.w.Write(backslashR)
586		case '\t':
587			_, err = w.w.Write(backslashT)
588		case '"':
589			_, err = w.w.Write(backslashDQ)
590		case '\\':
591			_, err = w.w.Write(backslashBS)
592		default:
593			if isprint(c) {
594				err = w.w.WriteByte(c)
595			} else {
596				_, err = fmt.Fprintf(w.w, "\\%03o", c)
597			}
598		}
599		if err != nil {
600			return err
601		}
602	}
603	return w.WriteByte('"')
604}
605
606func writeUnknownStruct(w *textWriter, data []byte) (err error) {
607	if !w.compact {
608		if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
609			return err
610		}
611	}
612	b := NewBuffer(data)
613	for b.index < len(b.buf) {
614		x, err := b.DecodeVarint()
615		if err != nil {
616			_, err := fmt.Fprintf(w, "/* %v */\n", err)
617			return err
618		}
619		wire, tag := x&7, x>>3
620		if wire == WireEndGroup {
621			w.unindent()
622			if _, err := w.Write(endBraceNewline); err != nil {
623				return err
624			}
625			continue
626		}
627		if _, err := fmt.Fprint(w, tag); err != nil {
628			return err
629		}
630		if wire != WireStartGroup {
631			if err := w.WriteByte(':'); err != nil {
632				return err
633			}
634		}
635		if !w.compact || wire == WireStartGroup {
636			if err := w.WriteByte(' '); err != nil {
637				return err
638			}
639		}
640		switch wire {
641		case WireBytes:
642			buf, e := b.DecodeRawBytes(false)
643			if e == nil {
644				_, err = fmt.Fprintf(w, "%q", buf)
645			} else {
646				_, err = fmt.Fprintf(w, "/* %v */", e)
647			}
648		case WireFixed32:
649			x, err = b.DecodeFixed32()
650			err = writeUnknownInt(w, x, err)
651		case WireFixed64:
652			x, err = b.DecodeFixed64()
653			err = writeUnknownInt(w, x, err)
654		case WireStartGroup:
655			err = w.WriteByte('{')
656			w.indent()
657		case WireVarint:
658			x, err = b.DecodeVarint()
659			err = writeUnknownInt(w, x, err)
660		default:
661			_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
662		}
663		if err != nil {
664			return err
665		}
666		if err = w.WriteByte('\n'); err != nil {
667			return err
668		}
669	}
670	return nil
671}
672
673func writeUnknownInt(w *textWriter, x uint64, err error) error {
674	if err == nil {
675		_, err = fmt.Fprint(w, x)
676	} else {
677		_, err = fmt.Fprintf(w, "/* %v */", err)
678	}
679	return err
680}
681
682type int32Slice []int32
683
684func (s int32Slice) Len() int           { return len(s) }
685func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
686func (s int32Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
687
688// writeExtensions writes all the extensions in pv.
689// pv is assumed to be a pointer to a protocol message struct that is extendable.
690func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
691	emap := extensionMaps[pv.Type().Elem()]
692	ep, _ := extendable(pv.Interface())
693
694	// Order the extensions by ID.
695	// This isn't strictly necessary, but it will give us
696	// canonical output, which will also make testing easier.
697	m, mu := ep.extensionsRead()
698	if m == nil {
699		return nil
700	}
701	mu.Lock()
702	ids := make([]int32, 0, len(m))
703	for id := range m {
704		ids = append(ids, id)
705	}
706	sort.Sort(int32Slice(ids))
707	mu.Unlock()
708
709	for _, extNum := range ids {
710		ext := m[extNum]
711		var desc *ExtensionDesc
712		if emap != nil {
713			desc = emap[extNum]
714		}
715		if desc == nil {
716			// Unknown extension.
717			if err := writeUnknownStruct(w, ext.enc); err != nil {
718				return err
719			}
720			continue
721		}
722
723		pb, err := GetExtension(ep, desc)
724		if err != nil {
725			return fmt.Errorf("failed getting extension: %v", err)
726		}
727
728		// Repeated extensions will appear as a slice.
729		if !desc.repeated() {
730			if err := tm.writeExtension(w, desc.Name, pb); err != nil {
731				return err
732			}
733		} else {
734			v := reflect.ValueOf(pb)
735			for i := 0; i < v.Len(); i++ {
736				if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
737					return err
738				}
739			}
740		}
741	}
742	return nil
743}
744
745func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
746	if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
747		return err
748	}
749	if !w.compact {
750		if err := w.WriteByte(' '); err != nil {
751			return err
752		}
753	}
754	if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
755		return err
756	}
757	if err := w.WriteByte('\n'); err != nil {
758		return err
759	}
760	return nil
761}
762
763func (w *textWriter) writeIndent() {
764	if !w.complete {
765		return
766	}
767	remain := w.ind * 2
768	for remain > 0 {
769		n := remain
770		if n > len(spaces) {
771			n = len(spaces)
772		}
773		w.w.Write(spaces[:n])
774		remain -= n
775	}
776	w.complete = false
777}
778
779// TextMarshaler is a configurable text format marshaler.
780type TextMarshaler struct {
781	Compact   bool // use compact text format (one line).
782	ExpandAny bool // expand google.protobuf.Any messages of known types
783}
784
785// Marshal writes a given protocol buffer in text format.
786// The only errors returned are from w.
787func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
788	val := reflect.ValueOf(pb)
789	if pb == nil || val.IsNil() {
790		w.Write([]byte("<nil>"))
791		return nil
792	}
793	var bw *bufio.Writer
794	ww, ok := w.(writer)
795	if !ok {
796		bw = bufio.NewWriter(w)
797		ww = bw
798	}
799	aw := &textWriter{
800		w:        ww,
801		complete: true,
802		compact:  tm.Compact,
803	}
804
805	if etm, ok := pb.(encoding.TextMarshaler); ok {
806		text, err := etm.MarshalText()
807		if err != nil {
808			return err
809		}
810		if _, err = aw.Write(text); err != nil {
811			return err
812		}
813		if bw != nil {
814			return bw.Flush()
815		}
816		return nil
817	}
818	// Dereference the received pointer so we don't have outer < and >.
819	v := reflect.Indirect(val)
820	if err := tm.writeStruct(aw, v); err != nil {
821		return err
822	}
823	if bw != nil {
824		return bw.Flush()
825	}
826	return nil
827}
828
829// Text is the same as Marshal, but returns the string directly.
830func (tm *TextMarshaler) Text(pb Message) string {
831	var buf bytes.Buffer
832	tm.Marshal(&buf, pb)
833	return buf.String()
834}
835
836var (
837	defaultTextMarshaler = TextMarshaler{}
838	compactTextMarshaler = TextMarshaler{Compact: true}
839)
840
841// TODO: consider removing some of the Marshal functions below.
842
843// MarshalText writes a given protocol buffer in text format.
844// The only errors returned are from w.
845func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
846
847// MarshalTextString is the same as MarshalText, but returns the string directly.
848func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
849
850// CompactText writes a given protocol buffer in compact text format (one line).
851func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
852
853// CompactTextString is the same as CompactText, but returns the string directly.
854func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
855