Copyright 2018 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package text

import (
	
	
	
	
	

	
	
)
encType represents an encoding type.
type encType uint8

const (
	_ encType = (1 << iota) / 2
	name
	scalar
	messageOpen
	messageClose
)
Encoder provides methods to write out textproto constructs and values. The user is responsible for producing valid sequences of constructs and values.
type Encoder struct {
	encoderState

	indent      string
	newline     string // set to "\n" if len(indent) > 0
	delims      [2]byte
	outputASCII bool
}

type encoderState struct {
	lastType encType
	indents  []byte
	out      []byte
}
NewEncoder returns an Encoder. If indent is a non-empty string, it causes every entry in a List or Message to be preceded by the indent and trailed by a newline. If delims is not the zero value, it controls the delimiter characters used for messages (e.g., "{}" vs "<>"). If outputASCII is true, strings will be serialized in such a way that multi-byte UTF-8 sequences are escaped. This property ensures that the overall output is ASCII (as opposed to UTF-8).
func ( string,  [2]byte,  bool) (*Encoder, error) {
	 := &Encoder{}
	if len() > 0 {
		if strings.Trim(, " \t") != "" {
			return nil, errors.New("indent may only be composed of space and tab characters")
		}
		.indent = 
		.newline = "\n"
	}
	switch  {
	case [2]byte{0, 0}:
		.delims = [2]byte{'{', '}'}
	case [2]byte{'{', '}'}, [2]byte{'<', '>'}:
		.delims = 
	default:
		return nil, errors.New("delimiters may only be \"{}\" or \"<>\"")
	}
	.outputASCII = 

	return , nil
}
Bytes returns the content of the written bytes.
func ( *Encoder) () []byte {
	return .out
}
StartMessage writes out the '{' or '<' symbol.
func ( *Encoder) () {
	.prepareNext(messageOpen)
	.out = append(.out, .delims[0])
}
EndMessage writes out the '}' or '>' symbol.
func ( *Encoder) () {
	.prepareNext(messageClose)
	.out = append(.out, .delims[1])
}
WriteName writes out the field name and the separator ':'.
func ( *Encoder) ( string) {
	.prepareNext(name)
	.out = append(.out, ...)
	.out = append(.out, ':')
}
WriteBool writes out the given boolean value.
func ( *Encoder) ( bool) {
	if  {
		.WriteLiteral("true")
	} else {
		.WriteLiteral("false")
	}
}
WriteString writes out the given string value.
func ( *Encoder) ( string) {
	.prepareNext(scalar)
	.out = appendString(.out, , .outputASCII)
}

func ( []byte,  string,  bool) []byte {
	 = append(, '"')
	 := indexNeedEscapeInString()
	,  = [:], append(, [:]...)
	for len() > 0 {
		switch ,  := utf8.DecodeRuneInString(); {
We do not report invalid UTF-8 because strings in the text format are used to represent both the proto string and bytes type.
			 = rune([0])
			fallthrough
		case  < ' ' ||  == '"' ||  == '\\':
			 = append(, '\\')
			switch  {
			case '"', '\\':
				 = append(, byte())
			case '\n':
				 = append(, 'n')
			case '\r':
				 = append(, 'r')
			case '\t':
				 = append(, 't')
			default:
				 = append(, 'x')
				 = append(, "00"[1+(bits.Len32(uint32())-1)/4:]...)
				 = strconv.AppendUint(, uint64(), 16)
			}
			 = [:]
		case  &&  >= utf8.RuneSelf:
			 = append(, '\\')
			if  <= math.MaxUint16 {
				 = append(, 'u')
				 = append(, "0000"[1+(bits.Len32(uint32())-1)/4:]...)
				 = strconv.AppendUint(, uint64(), 16)
			} else {
				 = append(, 'U')
				 = append(, "00000000"[1+(bits.Len32(uint32())-1)/4:]...)
				 = strconv.AppendUint(, uint64(), 16)
			}
			 = [:]
		default:
			 := indexNeedEscapeInString([:])
			,  = [+:], append(, [:+]...)
		}
	}
	 = append(, '"')
	return 
}
indexNeedEscapeInString returns the index of the character that needs escaping. If no characters need escaping, this returns the input length.
func ( string) int {
	for  := 0;  < len(); ++ {
		if  := [];  < ' ' ||  == '"' ||  == '\'' ||  == '\\' ||  >= utf8.RuneSelf {
			return 
		}
	}
	return len()
}
WriteFloat writes out the given float value for given bitSize.
func ( *Encoder) ( float64,  int) {
	.prepareNext(scalar)
	.out = appendFloat(.out, , )
}

func ( []byte,  float64,  int) []byte {
	switch {
	case math.IsNaN():
		return append(, "nan"...)
	case math.IsInf(, +1):
		return append(, "inf"...)
	case math.IsInf(, -1):
		return append(, "-inf"...)
	default:
		return strconv.AppendFloat(, , 'g', -1, )
	}
}
WriteInt writes out the given signed integer value.
func ( *Encoder) ( int64) {
	.prepareNext(scalar)
	.out = append(.out, strconv.FormatInt(, 10)...)
}
WriteUint writes out the given unsigned integer value.
func ( *Encoder) ( uint64) {
	.prepareNext(scalar)
	.out = append(.out, strconv.FormatUint(, 10)...)
}
WriteLiteral writes out the given string as a literal value without quotes. This is used for writing enum literal strings.
func ( *Encoder) ( string) {
	.prepareNext(scalar)
	.out = append(.out, ...)
}
prepareNext adds possible space and indentation for the next value based on last encType and indent option. It also updates e.lastType to next.
func ( *Encoder) ( encType) {
	defer func() {
		.lastType = 
	}()
Single line.
Add space after each field before the next one.
		if .lastType&(scalar|messageClose) != 0 &&  == name {
Add a random extra space to make output unstable.
			if detrand.Bool() {
				.out = append(.out, ' ')
			}
		}
		return
	}
Multi-line.
	switch {
	case .lastType == name:
Add a random extra space after name: to make output unstable.
		if detrand.Bool() {
			.out = append(.out, ' ')
		}

	case .lastType == messageOpen &&  != messageClose:
		.indents = append(.indents, .indent...)
		.out = append(.out, '\n')
		.out = append(.out, .indents...)

	case .lastType&(scalar|messageClose) != 0:
		if  == messageClose {
			.indents = .indents[:len(.indents)-len(.indent)]
		}
		.out = append(.out, '\n')
		.out = append(.out, .indents...)
	}
}
Snapshot returns the current snapshot for use in Reset.
func ( *Encoder) () encoderState {
	return .encoderState
}
Reset resets the Encoder to the given encoderState from a Snapshot.
func ( *Encoder) ( encoderState) {
	.encoderState =