package msgpack

import (
	
	
	
	
	

	
)

const (
	sortMapKeysFlag uint32 = 1 << iota
	arrayEncodedStructsFlag
	useCompactIntsFlag
	useCompactFloatsFlag
	useInternedStringsFlag
	omitEmptyFlag
)

type writer interface {
	io.Writer
	WriteByte(byte) error
}

type byteWriter struct {
	io.Writer
}

func ( io.Writer) byteWriter {
	return byteWriter{
		Writer: ,
	}
}

func ( byteWriter) ( byte) error {
	,  := .Write([]byte{})
	return 
}

//------------------------------------------------------------------------------

var encPool = sync.Pool{
	New: func() interface{} {
		return NewEncoder(nil)
	},
}

func () *Encoder {
	return encPool.Get().(*Encoder)
}

func ( *Encoder) {
	.w = nil
	encPool.Put()
}

// Marshal returns the MessagePack encoding of v.
func ( interface{}) ([]byte, error) {
	 := GetEncoder()

	var  bytes.Buffer
	.Reset(&)

	 := .Encode()
	 := .Bytes()

	PutEncoder()

	if  != nil {
		return nil, 
	}
	return , 
}

type Encoder struct {
	w writer

	buf     []byte
	timeBuf []byte

	dict map[string]int

	flags     uint32
	structTag string
}

// NewEncoder returns a new encoder that writes to w.
func ( io.Writer) *Encoder {
	 := &Encoder{
		buf: make([]byte, 9),
	}
	.Reset()
	return 
}

// Writer returns the Encoder's writer.
func ( *Encoder) () io.Writer {
	return .w
}

// Reset discards any buffered data, resets all state, and switches the writer to write to w.
func ( *Encoder) ( io.Writer) {
	.ResetDict(, nil)
}

// ResetDict is like Reset, but also resets the dict.
func ( *Encoder) ( io.Writer,  map[string]int) {
	.resetWriter()
	.flags = 0
	.structTag = ""
	.dict = 
}

func ( *Encoder) ( map[string]int,  func(*Encoder) error) error {
	 := .dict
	.dict = 
	 := ()
	.dict = 
	return 
}

func ( *Encoder) ( io.Writer) {
	if ,  := .(writer);  {
		.w = 
	} else {
		.w = newByteWriter()
	}
}

// SetSortMapKeys causes the Encoder to encode map keys in increasing order.
// Supported map types are:
//   - map[string]string
//   - map[string]interface{}
func ( *Encoder) ( bool) *Encoder {
	if  {
		.flags |= sortMapKeysFlag
	} else {
		.flags &= ^sortMapKeysFlag
	}
	return 
}

// SetCustomStructTag causes the Encoder to use a custom struct tag as
// fallback option if there is no msgpack tag.
func ( *Encoder) ( string) {
	.structTag = 
}

// SetOmitEmpty causes the Encoder to omit empty values by default.
func ( *Encoder) ( bool) {
	if  {
		.flags |= omitEmptyFlag
	} else {
		.flags &= ^omitEmptyFlag
	}
}

// UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays.
func ( *Encoder) ( bool) {
	if  {
		.flags |= arrayEncodedStructsFlag
	} else {
		.flags &= ^arrayEncodedStructsFlag
	}
}

// UseCompactEncoding causes the Encoder to chose the most compact encoding.
// For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes.
func ( *Encoder) ( bool) {
	if  {
		.flags |= useCompactIntsFlag
	} else {
		.flags &= ^useCompactIntsFlag
	}
}

// UseCompactFloats causes the Encoder to chose a compact integer encoding
// for floats that can be represented as integers.
func ( *Encoder) ( bool) {
	if  {
		.flags |= useCompactFloatsFlag
	} else {
		.flags &= ^useCompactFloatsFlag
	}
}

// UseInternedStrings causes the Encoder to intern strings.
func ( *Encoder) ( bool) {
	if  {
		.flags |= useInternedStringsFlag
	} else {
		.flags &= ^useInternedStringsFlag
	}
}

func ( *Encoder) ( interface{}) error {
	switch v := .(type) {
	case nil:
		return .EncodeNil()
	case string:
		return .EncodeString()
	case []byte:
		return .EncodeBytes()
	case int:
		return .EncodeInt(int64())
	case int64:
		return .encodeInt64Cond()
	case uint:
		return .EncodeUint(uint64())
	case uint64:
		return .encodeUint64Cond()
	case bool:
		return .EncodeBool()
	case float32:
		return .EncodeFloat32()
	case float64:
		return .EncodeFloat64()
	case time.Duration:
		return .encodeInt64Cond(int64())
	case time.Time:
		return .EncodeTime()
	}
	return .EncodeValue(reflect.ValueOf())
}

func ( *Encoder) ( ...interface{}) error {
	for ,  := range  {
		if  := .Encode();  != nil {
			return 
		}
	}
	return nil
}

func ( *Encoder) ( reflect.Value) error {
	 := getEncoder(.Type())
	return (, )
}

func ( *Encoder) () error {
	return .writeCode(msgpcode.Nil)
}

func ( *Encoder) ( bool) error {
	if  {
		return .writeCode(msgpcode.True)
	}
	return .writeCode(msgpcode.False)
}

func ( *Encoder) ( time.Duration) error {
	return .EncodeInt(int64())
}

func ( *Encoder) ( byte) error {
	return .w.WriteByte()
}

func ( *Encoder) ( []byte) error {
	,  := .w.Write()
	return 
}

func ( *Encoder) ( string) error {
	,  := .w.Write(stringToBytes())
	return 
}