package jsoniter

import (
	
	
	
	
	

	
	
)

// Config customize how the API should behave.
// The API is created from Config by Froze.
type Config struct {
	IndentionStep                 int
	MarshalFloatWith6Digits       bool
	EscapeHTML                    bool
	SortMapKeys                   bool
	UseNumber                     bool
	DisallowUnknownFields         bool
	TagKey                        string
	OnlyTaggedField               bool
	ValidateJsonRawMessage        bool
	ObjectFieldMustBeSimpleString bool
	CaseSensitive                 bool
}

// API the public interface of this package.
// Primary Marshal and Unmarshal.
type API interface {
	IteratorPool
	StreamPool
	MarshalToString(v interface{}) (string, error)
	Marshal(v interface{}) ([]byte, error)
	MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
	UnmarshalFromString(str string, v interface{}) error
	Unmarshal(data []byte, v interface{}) error
	Get(data []byte, path ...interface{}) Any
	NewEncoder(writer io.Writer) *Encoder
	NewDecoder(reader io.Reader) *Decoder
	Valid(data []byte) bool
	RegisterExtension(extension Extension)
	DecoderOf(typ reflect2.Type) ValDecoder
	EncoderOf(typ reflect2.Type) ValEncoder
}

// ConfigDefault the default API
var ConfigDefault = Config{
	EscapeHTML: true,
}.Froze()

// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
var ConfigCompatibleWithStandardLibrary = Config{
	EscapeHTML:             true,
	SortMapKeys:            true,
	ValidateJsonRawMessage: true,
}.Froze()

// ConfigFastest marshals float with only 6 digits precision
var ConfigFastest = Config{
	EscapeHTML:                    false,
	MarshalFloatWith6Digits:       true, // will lose precession
	ObjectFieldMustBeSimpleString: true, // do not unescape object field
}.Froze()

type frozenConfig struct {
	configBeforeFrozen            Config
	sortMapKeys                   bool
	indentionStep                 int
	objectFieldMustBeSimpleString bool
	onlyTaggedField               bool
	disallowUnknownFields         bool
	decoderCache                  *concurrent.Map
	encoderCache                  *concurrent.Map
	encoderExtension              Extension
	decoderExtension              Extension
	extraExtensions               []Extension
	streamPool                    *sync.Pool
	iteratorPool                  *sync.Pool
	caseSensitive                 bool
}

func ( *frozenConfig) () {
	.decoderCache = concurrent.NewMap()
	.encoderCache = concurrent.NewMap()
}

func ( *frozenConfig) ( uintptr,  ValDecoder) {
	.decoderCache.Store(, )
}

func ( *frozenConfig) ( uintptr,  ValEncoder) {
	.encoderCache.Store(, )
}

func ( *frozenConfig) ( uintptr) ValDecoder {
	,  := .decoderCache.Load()
	if  {
		return .(ValDecoder)
	}
	return nil
}

func ( *frozenConfig) ( uintptr) ValEncoder {
	,  := .encoderCache.Load()
	if  {
		return .(ValEncoder)
	}
	return nil
}

var cfgCache = concurrent.NewMap()

func getFrozenConfigFromCache( Config) *frozenConfig {
	,  := cfgCache.Load()
	if  {
		return .(*frozenConfig)
	}
	return nil
}

func addFrozenConfigToCache( Config,  *frozenConfig) {
	cfgCache.Store(, )
}

// Froze forge API from config
func ( Config) () API {
	 := &frozenConfig{
		sortMapKeys:                   .SortMapKeys,
		indentionStep:                 .IndentionStep,
		objectFieldMustBeSimpleString: .ObjectFieldMustBeSimpleString,
		onlyTaggedField:               .OnlyTaggedField,
		disallowUnknownFields:         .DisallowUnknownFields,
		caseSensitive:                 .CaseSensitive,
	}
	.streamPool = &sync.Pool{
		New: func() interface{} {
			return NewStream(, nil, 512)
		},
	}
	.iteratorPool = &sync.Pool{
		New: func() interface{} {
			return NewIterator()
		},
	}
	.initCache()
	 := EncoderExtension{}
	 := DecoderExtension{}
	if .MarshalFloatWith6Digits {
		.marshalFloatWith6Digits()
	}
	if .EscapeHTML {
		.escapeHTML()
	}
	if .UseNumber {
		.useNumber()
	}
	if .ValidateJsonRawMessage {
		.validateJsonRawMessage()
	}
	.encoderExtension = 
	.decoderExtension = 
	.configBeforeFrozen = 
	return 
}

func ( Config) ( []Extension) *frozenConfig {
	 := getFrozenConfigFromCache()
	if  != nil {
		return 
	}
	 = .Froze().(*frozenConfig)
	for ,  := range  {
		.RegisterExtension()
	}
	addFrozenConfigToCache(, )
	return 
}

func ( *frozenConfig) ( EncoderExtension) {
	 := &funcEncoder{func( unsafe.Pointer,  *Stream) {
		 := *(*json.RawMessage)()
		 := .BorrowIterator([]byte())
		defer .ReturnIterator()
		.Read()
		if .Error != nil && .Error != io.EOF {
			.WriteRaw("null")
		} else {
			.WriteRaw(string())
		}
	}, func( unsafe.Pointer) bool {
		return len(*((*json.RawMessage)())) == 0
	}}
	[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = 
	[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = 
}

func ( *frozenConfig) ( DecoderExtension) {
	[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func( unsafe.Pointer,  *Iterator) {
		 := *((*interface{})())
		if  != nil && reflect.TypeOf().Kind() == reflect.Ptr {
			.ReadVal()
			return
		}
		if .WhatIsNext() == NumberValue {
			*((*interface{})()) = json.Number(.readNumberAsString())
		} else {
			*((*interface{})()) = .Read()
		}
	}}
}
func ( *frozenConfig) () string {
	 := .configBeforeFrozen.TagKey
	if  == "" {
		return "json"
	}
	return 
}

func ( *frozenConfig) ( Extension) {
	.extraExtensions = append(.extraExtensions, )
	 := .configBeforeFrozen
	.configBeforeFrozen = 
}

type lossyFloat32Encoder struct {
}

func ( *lossyFloat32Encoder) ( unsafe.Pointer,  *Stream) {
	.WriteFloat32Lossy(*((*float32)()))
}

func ( *lossyFloat32Encoder) ( unsafe.Pointer) bool {
	return *((*float32)()) == 0
}

type lossyFloat64Encoder struct {
}

func ( *lossyFloat64Encoder) ( unsafe.Pointer,  *Stream) {
	.WriteFloat64Lossy(*((*float64)()))
}

func ( *lossyFloat64Encoder) ( unsafe.Pointer) bool {
	return *((*float64)()) == 0
}

// EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance.
func ( *frozenConfig) ( EncoderExtension) {
	// for better performance
	[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{}
	[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{}
}

type htmlEscapedStringEncoder struct {
}

func ( *htmlEscapedStringEncoder) ( unsafe.Pointer,  *Stream) {
	 := *((*string)())
	.WriteStringWithHTMLEscaped()
}

func ( *htmlEscapedStringEncoder) ( unsafe.Pointer) bool {
	return *((*string)()) == ""
}

func ( *frozenConfig) ( EncoderExtension) {
	[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
}

func ( *frozenConfig) () {
	typeDecoders = map[string]ValDecoder{}
	fieldDecoders = map[string]ValDecoder{}
	* = *(.configBeforeFrozen.Froze().(*frozenConfig))
}

func ( *frozenConfig) () {
	typeEncoders = map[string]ValEncoder{}
	fieldEncoders = map[string]ValEncoder{}
	* = *(.configBeforeFrozen.Froze().(*frozenConfig))
}

func ( *frozenConfig) ( interface{}) (string, error) {
	 := .BorrowStream(nil)
	defer .ReturnStream()
	.WriteVal()
	if .Error != nil {
		return "", .Error
	}
	return string(.Buffer()), nil
}

func ( *frozenConfig) ( interface{}) ([]byte, error) {
	 := .BorrowStream(nil)
	defer .ReturnStream()
	.WriteVal()
	if .Error != nil {
		return nil, .Error
	}
	 := .Buffer()
	 := make([]byte, len())
	copy(, )
	return , nil
}

func ( *frozenConfig) ( interface{}, ,  string) ([]byte, error) {
	if  != "" {
		panic("prefix is not supported")
	}
	for ,  := range  {
		if  != ' ' {
			panic("indent can only be space")
		}
	}
	 := .configBeforeFrozen
	.IndentionStep = len()
	return .frozeWithCacheReuse(.extraExtensions).Marshal()
}

func ( *frozenConfig) ( string,  interface{}) error {
	 := []byte()
	 := .BorrowIterator()
	defer .ReturnIterator()
	.ReadVal()
	 := .nextToken()
	if  == 0 {
		if .Error == io.EOF {
			return nil
		}
		return .Error
	}
	.ReportError("Unmarshal", "there are bytes left after unmarshal")
	return .Error
}

func ( *frozenConfig) ( []byte,  ...interface{}) Any {
	 := .BorrowIterator()
	defer .ReturnIterator()
	return locatePath(, )
}

func ( *frozenConfig) ( []byte,  interface{}) error {
	 := .BorrowIterator()
	defer .ReturnIterator()
	.ReadVal()
	 := .nextToken()
	if  == 0 {
		if .Error == io.EOF {
			return nil
		}
		return .Error
	}
	.ReportError("Unmarshal", "there are bytes left after unmarshal")
	return .Error
}

func ( *frozenConfig) ( io.Writer) *Encoder {
	 := NewStream(, , 512)
	return &Encoder{}
}

func ( *frozenConfig) ( io.Reader) *Decoder {
	 := Parse(, , 512)
	return &Decoder{}
}

func ( *frozenConfig) ( []byte) bool {
	 := .BorrowIterator()
	defer .ReturnIterator()
	.Skip()
	return .Error == nil
}