package json

import (
	
	
	
	

	
	
	
	
	
)

// An Encoder writes JSON values to an output stream.
type Encoder struct {
	w                 io.Writer
	enabledIndent     bool
	enabledHTMLEscape bool
	prefix            string
	indentStr         string
}

// NewEncoder returns a new encoder that writes to w.
func ( io.Writer) *Encoder {
	return &Encoder{w: , enabledHTMLEscape: true}
}

// Encode writes the JSON encoding of v to the stream, followed by a newline character.
//
// See the documentation for Marshal for details about the conversion of Go values to JSON.
func ( *Encoder) ( interface{}) error {
	return .EncodeWithOption()
}

// EncodeWithOption call Encode with EncodeOption.
func ( *Encoder) ( interface{},  ...EncodeOptionFunc) error {
	 := encoder.TakeRuntimeContext()
	.Option.Flag = 0

	 := .encodeWithOption(, , ...)

	encoder.ReleaseRuntimeContext()
	return 
}

// EncodeContext call Encode with context.Context and EncodeOption.
func ( *Encoder) ( context.Context,  interface{},  ...EncodeOptionFunc) error {
	 := encoder.TakeRuntimeContext()
	.Option.Flag = 0
	.Option.Flag |= encoder.ContextOption
	.Option.Context = 

	 := .encodeWithOption(, , ...) //nolint: contextcheck

	encoder.ReleaseRuntimeContext()
	return 
}

func ( *Encoder) ( *encoder.RuntimeContext,  interface{},  ...EncodeOptionFunc) error {
	if .enabledHTMLEscape {
		.Option.Flag |= encoder.HTMLEscapeOption
	}
	.Option.Flag |= encoder.NormalizeUTF8Option
	.Option.DebugOut = os.Stdout
	for ,  := range  {
		(.Option)
	}
	var (
		 []byte
		 error
	)
	if .enabledIndent {
		,  = encodeIndent(, , .prefix, .indentStr)
	} else {
		,  = encode(, )
	}
	if  != nil {
		return 
	}
	if .enabledIndent {
		 = [:len()-2]
	} else {
		 = [:len()-1]
	}
	 = append(, '\n')
	if ,  := .w.Write();  != nil {
		return 
	}
	return nil
}

// SetEscapeHTML specifies whether problematic HTML characters should be escaped inside JSON quoted strings.
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when embedding JSON in HTML.
//
// In non-HTML settings where the escaping interferes with the readability of the output, SetEscapeHTML(false) disables this behavior.
func ( *Encoder) ( bool) {
	.enabledHTMLEscape = 
}

// SetIndent instructs the encoder to format each subsequent encoded value as if indented by the package-level function Indent(dst, src, prefix, indent).
// Calling SetIndent("", "") disables indentation.
func ( *Encoder) (,  string) {
	if  == "" &&  == "" {
		.enabledIndent = false
		return
	}
	.prefix = 
	.indentStr = 
	.enabledIndent = true
}

func marshalContext( context.Context,  interface{},  ...EncodeOptionFunc) ([]byte, error) {
	 := encoder.TakeRuntimeContext()
	.Option.Flag = 0
	.Option.Flag = encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.ContextOption
	.Option.Context = 
	for ,  := range  {
		(.Option)
	}

	,  := encode(, ) //nolint: contextcheck
	if  != nil {
		encoder.ReleaseRuntimeContext()
		return nil, 
	}

	// this line exists to escape call of `runtime.makeslicecopy` .
	// if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`,
	// dst buffer size and src buffer size are differrent.
	// in this case, compiler uses `runtime.makeslicecopy`, but it is slow.
	 = [:len()-1]
	 := make([]byte, len())
	copy(, )

	encoder.ReleaseRuntimeContext()
	return , nil
}

func marshal( interface{},  ...EncodeOptionFunc) ([]byte, error) {
	 := encoder.TakeRuntimeContext()

	.Option.Flag = 0
	.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)
	for ,  := range  {
		(.Option)
	}

	,  := encode(, )
	if  != nil {
		encoder.ReleaseRuntimeContext()
		return nil, 
	}

	// this line exists to escape call of `runtime.makeslicecopy` .
	// if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`,
	// dst buffer size and src buffer size are differrent.
	// in this case, compiler uses `runtime.makeslicecopy`, but it is slow.
	 = [:len()-1]
	 := make([]byte, len())
	copy(, )

	encoder.ReleaseRuntimeContext()
	return , nil
}

func marshalNoEscape( interface{}) ([]byte, error) {
	 := encoder.TakeRuntimeContext()

	.Option.Flag = 0
	.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)

	,  := encodeNoEscape(, )
	if  != nil {
		encoder.ReleaseRuntimeContext()
		return nil, 
	}

	// this line exists to escape call of `runtime.makeslicecopy` .
	// if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`,
	// dst buffer size and src buffer size are differrent.
	// in this case, compiler uses `runtime.makeslicecopy`, but it is slow.
	 = [:len()-1]
	 := make([]byte, len())
	copy(, )

	encoder.ReleaseRuntimeContext()
	return , nil
}

func marshalIndent( interface{}, ,  string,  ...EncodeOptionFunc) ([]byte, error) {
	 := encoder.TakeRuntimeContext()

	.Option.Flag = 0
	.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.IndentOption)
	for ,  := range  {
		(.Option)
	}

	,  := encodeIndent(, , , )
	if  != nil {
		encoder.ReleaseRuntimeContext()
		return nil, 
	}

	 = [:len()-2]
	 := make([]byte, len())
	copy(, )

	encoder.ReleaseRuntimeContext()
	return , nil
}

func encode( *encoder.RuntimeContext,  interface{}) ([]byte, error) {
	 := .Buf[:0]
	if  == nil {
		 = encoder.AppendNull(, )
		 = encoder.AppendComma(, )
		return , nil
	}
	 := (*emptyInterface)(unsafe.Pointer(&))
	 := .typ

	 := uintptr(unsafe.Pointer())
	,  := encoder.CompileToGetCodeSet(, )
	if  != nil {
		return nil, 
	}

	 := uintptr(.ptr)
	.Init(, .CodeLength)
	.KeepRefs = append(.KeepRefs, .ptr)

	,  := encodeRunCode(, , )
	if  != nil {
		return nil, 
	}
	.Buf = 
	return , nil
}

func encodeNoEscape( *encoder.RuntimeContext,  interface{}) ([]byte, error) {
	 := .Buf[:0]
	if  == nil {
		 = encoder.AppendNull(, )
		 = encoder.AppendComma(, )
		return , nil
	}
	 := (*emptyInterface)(unsafe.Pointer(&))
	 := .typ

	 := uintptr(unsafe.Pointer())
	,  := encoder.CompileToGetCodeSet(, )
	if  != nil {
		return nil, 
	}

	 := uintptr(.ptr)
	.Init(, .CodeLength)
	,  := encodeRunCode(, , )
	if  != nil {
		return nil, 
	}

	.Buf = 
	return , nil
}

func encodeIndent( *encoder.RuntimeContext,  interface{}, ,  string) ([]byte, error) {
	 := .Buf[:0]
	if  == nil {
		 = encoder.AppendNull(, )
		 = encoder.AppendCommaIndent(, )
		return , nil
	}
	 := (*emptyInterface)(unsafe.Pointer(&))
	 := .typ

	 := uintptr(unsafe.Pointer())
	,  := encoder.CompileToGetCodeSet(, )
	if  != nil {
		return nil, 
	}

	 := uintptr(.ptr)
	.Init(, .CodeLength)
	,  := encodeRunIndentCode(, , , , )

	.KeepRefs = append(.KeepRefs, .ptr)

	if  != nil {
		return nil, 
	}

	.Buf = 
	return , nil
}

func encodeRunCode( *encoder.RuntimeContext,  []byte,  *encoder.OpcodeSet) ([]byte, error) {
	if (.Option.Flag & encoder.DebugOption) != 0 {
		if (.Option.Flag & encoder.ColorizeOption) != 0 {
			return vm_color.DebugRun(, , )
		}
		return vm.DebugRun(, , )
	}
	if (.Option.Flag & encoder.ColorizeOption) != 0 {
		return vm_color.Run(, , )
	}
	return vm.Run(, , )
}

func encodeRunIndentCode( *encoder.RuntimeContext,  []byte,  *encoder.OpcodeSet, ,  string) ([]byte, error) {
	.Prefix = []byte()
	.IndentStr = []byte()
	if (.Option.Flag & encoder.DebugOption) != 0 {
		if (.Option.Flag & encoder.ColorizeOption) != 0 {
			return vm_color_indent.DebugRun(, , )
		}
		return vm_indent.DebugRun(, , )
	}
	if (.Option.Flag & encoder.ColorizeOption) != 0 {
		return vm_color_indent.Run(, , )
	}
	return vm_indent.Run(, , )
}