package jsoniter

import (
	
	
	
	
	
)

func encoderOfStruct( *ctx,  reflect2.Type) ValEncoder {
	type  struct {
		 *Binding
		  string
		 bool
	}
	 := []*{}
	 := describeStruct(, )
	for ,  := range .Fields {
		for ,  := range .ToNames {
			 := &{
				: ,
				:  ,
			}
			for ,  := range  {
				if . !=  {
					continue
				}
				., . = resolveConflictBinding(.frozenConfig, ., .)
			}
			 = append(, )
		}
	}
	if len() == 0 {
		return &emptyStructEncoder{}
	}
	 := []structFieldTo{}
	for ,  := range  {
		if !. {
			 = append(, structFieldTo{
				encoder: ..Encoder.(*structFieldEncoder),
				toName:  .,
			})
		}
	}
	return &structEncoder{, }
}

func createCheckIsEmpty( *ctx,  reflect2.Type) checkIsEmpty {
	 := createEncoderOfNative(, )
	if  != nil {
		return 
	}
	 := .Kind()
	switch  {
	case reflect.Interface:
		return &dynamicEncoder{}
	case reflect.Struct:
		return &structEncoder{typ: }
	case reflect.Array:
		return &arrayEncoder{}
	case reflect.Slice:
		return &sliceEncoder{}
	case reflect.Map:
		return encoderOfMap(, )
	case reflect.Ptr:
		return &OptionalEncoder{}
	default:
		return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", )}
	}
}

func resolveConflictBinding( *frozenConfig, ,  *Binding) (,  bool) {
	 := .Field.Tag().Get(.getTagKey()) != ""
	 := .Field.Tag().Get(.getTagKey()) != ""
	if  {
		if  {
			if len(.levels) > len(.levels) {
				return true, false
			} else if len(.levels) > len(.levels) {
				return false, true
			} else {
				return true, true
			}
		} else {
			return true, false
		}
	} else {
		if  {
			return true, false
		}
		if len(.levels) > len(.levels) {
			return true, false
		} else if len(.levels) > len(.levels) {
			return false, true
		} else {
			return true, true
		}
	}
}

type structFieldEncoder struct {
	field        reflect2.StructField
	fieldEncoder ValEncoder
	omitempty    bool
}

func ( *structFieldEncoder) ( unsafe.Pointer,  *Stream) {
	 := .field.UnsafeGet()
	.fieldEncoder.Encode(, )
	if .Error != nil && .Error != io.EOF {
		.Error = fmt.Errorf("%s: %s", .field.Name(), .Error.Error())
	}
}

func ( *structFieldEncoder) ( unsafe.Pointer) bool {
	 := .field.UnsafeGet()
	return .fieldEncoder.IsEmpty()
}

func ( *structFieldEncoder) ( unsafe.Pointer) bool {
	,  := .fieldEncoder.(IsEmbeddedPtrNil)
	if ! {
		return false
	}
	 := .field.UnsafeGet()
	return .IsEmbeddedPtrNil()
}

type IsEmbeddedPtrNil interface {
	IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
}

type structEncoder struct {
	typ    reflect2.Type
	fields []structFieldTo
}

type structFieldTo struct {
	encoder *structFieldEncoder
	toName  string
}

func ( *structEncoder) ( unsafe.Pointer,  *Stream) {
	.WriteObjectStart()
	 := false
	for ,  := range .fields {
		if .encoder.omitempty && .encoder.IsEmpty() {
			continue
		}
		if .encoder.IsEmbeddedPtrNil() {
			continue
		}
		if  {
			.WriteMore()
		}
		.WriteObjectField(.toName)
		.encoder.Encode(, )
		 = true
	}
	.WriteObjectEnd()
	if .Error != nil && .Error != io.EOF {
		.Error = fmt.Errorf("%v.%s", .typ, .Error.Error())
	}
}

func ( *structEncoder) ( unsafe.Pointer) bool {
	return false
}

type emptyStructEncoder struct {
}

func ( *emptyStructEncoder) ( unsafe.Pointer,  *Stream) {
	.WriteEmptyObject()
}

func ( *emptyStructEncoder) ( unsafe.Pointer) bool {
	return false
}

type stringModeNumberEncoder struct {
	elemEncoder ValEncoder
}

func ( *stringModeNumberEncoder) ( unsafe.Pointer,  *Stream) {
	.writeByte('"')
	.elemEncoder.Encode(, )
	.writeByte('"')
}

func ( *stringModeNumberEncoder) ( unsafe.Pointer) bool {
	return .elemEncoder.IsEmpty()
}

type stringModeStringEncoder struct {
	elemEncoder ValEncoder
	cfg         *frozenConfig
}

func ( *stringModeStringEncoder) ( unsafe.Pointer,  *Stream) {
	 := .cfg.BorrowStream(nil)
	.Attachment = .Attachment
	defer .cfg.ReturnStream()
	.elemEncoder.Encode(, )
	.WriteString(string(.Buffer()))
}

func ( *stringModeStringEncoder) ( unsafe.Pointer) bool {
	return .elemEncoder.IsEmpty()
}