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