// 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 = pool.New(func() *jsonEncoder {
	return &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 {
	 := _jsonPool.Get()
	.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) {
	safeAppendStringLike(
		(*buffer.Buffer).AppendString,
		utf8.DecodeRuneInString,
		.buf,
		,
	)
}

// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
func ( *jsonEncoder) ( []byte) {
	safeAppendStringLike(
		(*buffer.Buffer).AppendBytes,
		utf8.DecodeRune,
		.buf,
		,
	)
}

// safeAppendStringLike is a generic implementation of safeAddString and safeAddByteString.
// It appends a string or byte slice to the buffer, escaping all special characters.
func [ []byte | string](
	// appendTo appends this string-like object to the buffer.
	 func(*buffer.Buffer, ),
	// decodeRune decodes the next rune from the string-like object
	// and returns its value and width in bytes.
	 func() (rune, int),
	 *buffer.Buffer,
	 ,
) {
	// The encoding logic below works by skipping over characters
	// that can be safely copied as-is,
	// until a character is found that needs special handling.
	// At that point, we copy everything we've seen so far,
	// and then handle that special character.
	//
	// last is the index of the last byte that was copied to the buffer.
	 := 0
	for  := 0;  < len(); {
		if [] >= utf8.RuneSelf {
			// Character >= RuneSelf may be part of a multi-byte rune.
			// They need to be decoded before we can decide how to handle them.
			,  := ([:])
			if  != utf8.RuneError ||  != 1 {
				// No special handling required.
				// Skip over this rune and continue.
				 += 
				continue
			}

			// Invalid UTF-8 sequence.
			// Replace it with the Unicode replacement character.
			(, [:])
			.AppendString(`\ufffd`)

			++
			 = 
		} else {
			// Character < RuneSelf is a single-byte UTF-8 rune.
			if [] >= 0x20 && [] != '\\' && [] != '"' {
				// No escaping necessary.
				// Skip over this character and continue.
				++
				continue
			}

			// This character needs to be escaped.
			(, [:])
			switch [] {
			case '\\', '"':
				.AppendByte('\\')
				.AppendByte([])
			case '\n':
				.AppendByte('\\')
				.AppendByte('n')
			case '\r':
				.AppendByte('\\')
				.AppendByte('r')
			case '\t':
				.AppendByte('\\')
				.AppendByte('t')
			default:
				// Encode bytes < 0x20, except for the escape sequences above.
				.AppendString(`\u00`)
				.AppendByte(_hex[[]>>4])
				.AppendByte(_hex[[]&0xF])
			}

			++
			 = 
		}
	}

	// add remaining
	(, [:])
}