// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zapcore

import (
	
	
	
	
	

	
	
)

// For JSON-escaping; see jsonEncoder.safeAddString below.
const _hex = "0123456789abcdef"

var _jsonPool = sync.Pool{New: func() interface{} {
	return &jsonEncoder{}
}}

func () *jsonEncoder {
	return _jsonPool.Get().(*jsonEncoder)
}

func ( *jsonEncoder) {
	if .reflectBuf != nil {
		.reflectBuf.Free()
	}
	.EncoderConfig = nil
	.buf = nil
	.spaced = false
	.openNamespaces = 0
	.reflectBuf = nil
	.reflectEnc = nil
	_jsonPool.Put()
}

type jsonEncoder struct {
	*EncoderConfig
	buf            *buffer.Buffer
	spaced         bool // include spaces after colons and commas
	openNamespaces int

	// for encoding generic values by reflection
	reflectBuf *buffer.Buffer
	reflectEnc ReflectedEncoder
}

// NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder
// appropriately escapes all field keys and values.
//
// Note that the encoder doesn't deduplicate keys, so it's possible to produce
// a message like
//
//	{"foo":"bar","foo":"baz"}
//
// This is permitted by the JSON specification, but not encouraged. Many
// libraries will ignore duplicate key-value pairs (typically keeping the last
// pair) when unmarshaling, but users should attempt to avoid adding duplicate
// keys.
func ( EncoderConfig) Encoder {
	return newJSONEncoder(, false)
}

func ( EncoderConfig,  bool) *jsonEncoder {
	if .SkipLineEnding {
		.LineEnding = ""
	} else if .LineEnding == "" {
		.LineEnding = DefaultLineEnding
	}

	// If no EncoderConfig.NewReflectedEncoder is provided by the user, then use default
	if .NewReflectedEncoder == nil {
		.NewReflectedEncoder = defaultReflectedEncoder
	}

	return &jsonEncoder{
		EncoderConfig: &,
		buf:           bufferpool.Get(),
		spaced:        ,
	}
}

func ( *jsonEncoder) ( string,  ArrayMarshaler) error {
	.addKey()
	return .AppendArray()
}

func ( *jsonEncoder) ( string,  ObjectMarshaler) error {
	.addKey()
	return .AppendObject()
}

func ( *jsonEncoder) ( string,  []byte) {
	.AddString(, base64.StdEncoding.EncodeToString())
}

func ( *jsonEncoder) ( string,  []byte) {
	.addKey()
	.AppendByteString()
}

func ( *jsonEncoder) ( string,  bool) {
	.addKey()
	.AppendBool()
}

func ( *jsonEncoder) ( string,  complex128) {
	.addKey()
	.AppendComplex128()
}

func ( *jsonEncoder) ( string,  complex64) {
	.addKey()
	.AppendComplex64()
}

func ( *jsonEncoder) ( string,  time.Duration) {
	.addKey()
	.AppendDuration()
}

func ( *jsonEncoder) ( string,  float64) {
	.addKey()
	.AppendFloat64()
}

func ( *jsonEncoder) ( string,  float32) {
	.addKey()
	.AppendFloat32()
}

func ( *jsonEncoder) ( string,  int64) {
	.addKey()
	.AppendInt64()
}

func ( *jsonEncoder) () {
	if .reflectBuf == nil {
		.reflectBuf = bufferpool.Get()
		.reflectEnc = .NewReflectedEncoder(.reflectBuf)
	} else {
		.reflectBuf.Reset()
	}
}

var nullLiteralBytes = []byte("null")

// Only invoke the standard JSON encoder if there is actually something to
// encode; otherwise write JSON null literal directly.
func ( *jsonEncoder) ( interface{}) ([]byte, error) {
	if  == nil {
		return nullLiteralBytes, nil
	}
	.resetReflectBuf()
	if  := .reflectEnc.Encode();  != nil {
		return nil, 
	}
	.reflectBuf.TrimNewline()
	return .reflectBuf.Bytes(), nil
}

func ( *jsonEncoder) ( string,  interface{}) error {
	,  := .encodeReflected()
	if  != nil {
		return 
	}
	.addKey()
	_,  = .buf.Write()
	return 
}

func ( *jsonEncoder) ( string) {
	.addKey()
	.buf.AppendByte('{')
	.openNamespaces++
}

func ( *jsonEncoder) (,  string) {
	.addKey()
	.AppendString()
}

func ( *jsonEncoder) ( string,  time.Time) {
	.addKey()
	.AppendTime()
}

func ( *jsonEncoder) ( string,  uint64) {
	.addKey()
	.AppendUint64()
}

func ( *jsonEncoder) ( ArrayMarshaler) error {
	.addElementSeparator()
	.buf.AppendByte('[')
	 := .MarshalLogArray()
	.buf.AppendByte(']')
	return 
}

func ( *jsonEncoder) ( ObjectMarshaler) error {
	// Close ONLY new openNamespaces that are created during
	// AppendObject().
	 := .openNamespaces
	.openNamespaces = 0
	.addElementSeparator()
	.buf.AppendByte('{')
	 := .MarshalLogObject()
	.buf.AppendByte('}')
	.closeOpenNamespaces()
	.openNamespaces = 
	return 
}

func ( *jsonEncoder) ( bool) {
	.addElementSeparator()
	.buf.AppendBool()
}

func ( *jsonEncoder) ( []byte) {
	.addElementSeparator()
	.buf.AppendByte('"')
	.safeAddByteString()
	.buf.AppendByte('"')
}

// appendComplex appends the encoded form of the provided complex128 value.
// precision specifies the encoding precision for the real and imaginary
// components of the complex number.
func ( *jsonEncoder) ( complex128,  int) {
	.addElementSeparator()
	// Cast to a platform-independent, fixed-size type.
	,  := float64(real()), float64(imag())
	.buf.AppendByte('"')
	// Because we're always in a quoted string, we can use strconv without
	// special-casing NaN and +/-Inf.
	.buf.AppendFloat(, )
	// If imaginary part is less than 0, minus (-) sign is added by default
	// by AppendFloat.
	if  >= 0 {
		.buf.AppendByte('+')
	}
	.buf.AppendFloat(, )
	.buf.AppendByte('i')
	.buf.AppendByte('"')
}

func ( *jsonEncoder) ( time.Duration) {
	 := .buf.Len()
	if  := .EncodeDuration;  != nil {
		(, )
	}
	if  == .buf.Len() {
		// User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep
		// JSON valid.
		.AppendInt64(int64())
	}
}

func ( *jsonEncoder) ( int64) {
	.addElementSeparator()
	.buf.AppendInt()
}

func ( *jsonEncoder) ( interface{}) error {
	,  := .encodeReflected()
	if  != nil {
		return 
	}
	.addElementSeparator()
	_,  = .buf.Write()
	return 
}

func ( *jsonEncoder) ( string) {
	.addElementSeparator()
	.buf.AppendByte('"')
	.safeAddString()
	.buf.AppendByte('"')
}

func ( *jsonEncoder) ( time.Time,  string) {
	.addElementSeparator()
	.buf.AppendByte('"')
	.buf.AppendTime(, )
	.buf.AppendByte('"')
}

func ( *jsonEncoder) ( time.Time) {
	 := .buf.Len()
	if  := .EncodeTime;  != nil {
		(, )
	}
	if  == .buf.Len() {
		// User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep
		// output JSON valid.
		.AppendInt64(.UnixNano())
	}
}

func ( *jsonEncoder) ( uint64) {
	.addElementSeparator()
	.buf.AppendUint()
}

func ( *jsonEncoder) ( string,  int)         { .AddInt64(, int64()) }
func ( *jsonEncoder) ( string,  int32)     { .AddInt64(, int64()) }
func ( *jsonEncoder) ( string,  int16)     { .AddInt64(, int64()) }
func ( *jsonEncoder) ( string,  int8)       { .AddInt64(, int64()) }
func ( *jsonEncoder) ( string,  uint)       { .AddUint64(, uint64()) }
func ( *jsonEncoder) ( string,  uint32)   { .AddUint64(, uint64()) }
func ( *jsonEncoder) ( string,  uint16)   { .AddUint64(, uint64()) }
func ( *jsonEncoder) ( string,  uint8)     { .AddUint64(, uint64()) }
func ( *jsonEncoder) ( string,  uintptr) { .AddUint64(, uint64()) }
func ( *jsonEncoder) ( complex64)    { .appendComplex(complex128(), 32) }
func ( *jsonEncoder) ( complex128)  { .appendComplex(complex128(), 64) }
func ( *jsonEncoder) ( float64)        { .appendFloat(, 64) }
func ( *jsonEncoder) ( float32)        { .appendFloat(float64(), 32) }
func ( *jsonEncoder) ( int)                { .AppendInt64(int64()) }
func ( *jsonEncoder) ( int32)            { .AppendInt64(int64()) }
func ( *jsonEncoder) ( int16)            { .AppendInt64(int64()) }
func ( *jsonEncoder) ( int8)              { .AppendInt64(int64()) }
func ( *jsonEncoder) ( uint)              { .AppendUint64(uint64()) }
func ( *jsonEncoder) ( uint32)          { .AppendUint64(uint64()) }
func ( *jsonEncoder) ( uint16)          { .AppendUint64(uint64()) }
func ( *jsonEncoder) ( uint8)            { .AppendUint64(uint64()) }
func ( *jsonEncoder) ( uintptr)        { .AppendUint64(uint64()) }

func ( *jsonEncoder) () Encoder {
	 := .clone()
	.buf.Write(.buf.Bytes())
	return 
}

func ( *jsonEncoder) () *jsonEncoder {
	 := getJSONEncoder()
	.EncoderConfig = .EncoderConfig
	.spaced = .spaced
	.openNamespaces = .openNamespaces
	.buf = bufferpool.Get()
	return 
}

func ( *jsonEncoder) ( Entry,  []Field) (*buffer.Buffer, error) {
	 := .clone()
	.buf.AppendByte('{')

	if .LevelKey != "" && .EncodeLevel != nil {
		.addKey(.LevelKey)
		 := .buf.Len()
		.EncodeLevel(.Level, )
		if  == .buf.Len() {
			// User-supplied EncodeLevel was a no-op. Fall back to strings to keep
			// output JSON valid.
			.AppendString(.Level.String())
		}
	}
	if .TimeKey != "" {
		.AddTime(.TimeKey, .Time)
	}
	if .LoggerName != "" && .NameKey != "" {
		.addKey(.NameKey)
		 := .buf.Len()
		 := .EncodeName

		// if no name encoder provided, fall back to FullNameEncoder for backwards
		// compatibility
		if  == nil {
			 = FullNameEncoder
		}

		(.LoggerName, )
		if  == .buf.Len() {
			// User-supplied EncodeName was a no-op. Fall back to strings to
			// keep output JSON valid.
			.AppendString(.LoggerName)
		}
	}
	if .Caller.Defined {
		if .CallerKey != "" {
			.addKey(.CallerKey)
			 := .buf.Len()
			.EncodeCaller(.Caller, )
			if  == .buf.Len() {
				// User-supplied EncodeCaller was a no-op. Fall back to strings to
				// keep output JSON valid.
				.AppendString(.Caller.String())
			}
		}
		if .FunctionKey != "" {
			.addKey(.FunctionKey)
			.AppendString(.Caller.Function)
		}
	}
	if .MessageKey != "" {
		.addKey(.MessageKey)
		.AppendString(.Message)
	}
	if .buf.Len() > 0 {
		.addElementSeparator()
		.buf.Write(.buf.Bytes())
	}
	addFields(, )
	.closeOpenNamespaces()
	if .Stack != "" && .StacktraceKey != "" {
		.AddString(.StacktraceKey, .Stack)
	}
	.buf.AppendByte('}')
	.buf.AppendString(.LineEnding)

	 := .buf
	putJSONEncoder()
	return , nil
}

func ( *jsonEncoder) () {
	.buf.Reset()
}

func ( *jsonEncoder) () {
	for  := 0;  < .openNamespaces; ++ {
		.buf.AppendByte('}')
	}
	.openNamespaces = 0
}

func ( *jsonEncoder) ( string) {
	.addElementSeparator()
	.buf.AppendByte('"')
	.safeAddString()
	.buf.AppendByte('"')
	.buf.AppendByte(':')
	if .spaced {
		.buf.AppendByte(' ')
	}
}

func ( *jsonEncoder) () {
	 := .buf.Len() - 1
	if  < 0 {
		return
	}
	switch .buf.Bytes()[] {
	case '{', '[', ':', ',', ' ':
		return
	default:
		.buf.AppendByte(',')
		if .spaced {
			.buf.AppendByte(' ')
		}
	}
}

func ( *jsonEncoder) ( float64,  int) {
	.addElementSeparator()
	switch {
	case math.IsNaN():
		.buf.AppendString(`"NaN"`)
	case math.IsInf(, 1):
		.buf.AppendString(`"+Inf"`)
	case math.IsInf(, -1):
		.buf.AppendString(`"-Inf"`)
	default:
		.buf.AppendFloat(, )
	}
}

// safeAddString JSON-escapes a string and appends it to the internal buffer.
// Unlike the standard library's encoder, it doesn't attempt to protect the
// user from browser vulnerabilities or JSONP-related problems.
func ( *jsonEncoder) ( string) {
	for  := 0;  < len(); {
		if .tryAddRuneSelf([]) {
			++
			continue
		}
		,  := utf8.DecodeRuneInString([:])
		if .tryAddRuneError(, ) {
			++
			continue
		}
		.buf.AppendString([ : +])
		 += 
	}
}

// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
func ( *jsonEncoder) ( []byte) {
	for  := 0;  < len(); {
		if .tryAddRuneSelf([]) {
			++
			continue
		}
		,  := utf8.DecodeRune([:])
		if .tryAddRuneError(, ) {
			++
			continue
		}
		.buf.Write([ : +])
		 += 
	}
}

// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte.
func ( *jsonEncoder) ( byte) bool {
	if  >= utf8.RuneSelf {
		return false
	}
	if 0x20 <=  &&  != '\\' &&  != '"' {
		.buf.AppendByte()
		return true
	}
	switch  {
	case '\\', '"':
		.buf.AppendByte('\\')
		.buf.AppendByte()
	case '\n':
		.buf.AppendByte('\\')
		.buf.AppendByte('n')
	case '\r':
		.buf.AppendByte('\\')
		.buf.AppendByte('r')
	case '\t':
		.buf.AppendByte('\\')
		.buf.AppendByte('t')
	default:
		// Encode bytes < 0x20, except for the escape sequences above.
		.buf.AppendString(`\u00`)
		.buf.AppendByte(_hex[>>4])
		.buf.AppendByte(_hex[&0xF])
	}
	return true
}

func ( *jsonEncoder) ( rune,  int) bool {
	if  == utf8.RuneError &&  == 1 {
		.buf.AppendString(`\ufffd`)
		return true
	}
	return false
}