package gojay

import (
	
	
	
)

var nullBytes = []byte("null")

// MarshalJSONArray returns the JSON encoding of v, an implementation of MarshalerJSONArray.
//
//
// Example:
// 	type TestSlice []*TestStruct
//
// 	func (t TestSlice) MarshalJSONArray(enc *Encoder) {
//		for _, e := range t {
//			enc.AddObject(e)
//		}
//	}
//
//	func main() {
//		test := &TestSlice{
//			&TestStruct{123456},
//			&TestStruct{7890},
// 		}
// 		b, _ := Marshal(test)
//		fmt.Println(b) // [{"id":123456},{"id":7890}]
//	}
func ( MarshalerJSONArray) ([]byte, error) {
	 := BorrowEncoder(nil)
	.grow(512)
	.writeByte('[')
	.(MarshalerJSONArray).MarshalJSONArray()
	.writeByte(']')

	defer func() {
		.buf = make([]byte, 0, 512)
		.Release()
	}()

	return .buf, nil
}

// MarshalJSONObject returns the JSON encoding of v, an implementation of MarshalerJSONObject.
//
// Example:
//	type Object struct {
//		id int
//	}
//	func (s *Object) MarshalJSONObject(enc *gojay.Encoder) {
//		enc.IntKey("id", s.id)
//	}
//	func (s *Object) IsNil() bool {
//		return s == nil
//	}
//
// 	func main() {
//		test := &Object{
//			id: 123456,
//		}
//		b, _ := gojay.Marshal(test)
// 		fmt.Println(b) // {"id":123456}
//	}
func ( MarshalerJSONObject) ([]byte, error) {
	 := BorrowEncoder(nil)
	.grow(512)

	defer func() {
		.buf = make([]byte, 0, 512)
		.Release()
	}()

	return .encodeObject()
}

// Marshal returns the JSON encoding of v.
//
// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types:
//	string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool
// Marshal returns an InvalidMarshalError.
func ( interface{}) ([]byte, error) {
	return marshal(, false)
}

// MarshalAny returns the JSON encoding of v.
//
// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types:
//	string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool
// MarshalAny falls back to "json/encoding" package to marshal the value.
func ( interface{}) ([]byte, error) {
	return marshal(, true)
}

func marshal( interface{},  bool) ([]byte, error) {
	var (
		 = BorrowEncoder(nil)

		 []byte
		 error
	)

	defer func() {
		.buf = make([]byte, 0, 512)
		.Release()
	}()

	,  = func() ([]byte, error) {
		switch vt := .(type) {
		case MarshalerJSONObject:
			return .encodeObject()
		case MarshalerJSONArray:
			return .encodeArray()
		case string:
			return .encodeString()
		case bool:
			return .encodeBool()
		case int:
			return .encodeInt()
		case int64:
			return .encodeInt64()
		case int32:
			return .encodeInt(int())
		case int16:
			return .encodeInt(int())
		case int8:
			return .encodeInt(int())
		case uint64:
			return .encodeInt(int())
		case uint32:
			return .encodeInt(int())
		case uint16:
			return .encodeInt(int())
		case uint8:
			return .encodeInt(int())
		case float64:
			return .encodeFloat()
		case float32:
			return .encodeFloat32()
		case *EmbeddedJSON:
			return .encodeEmbeddedJSON()
		default:
			if  {
				return json.Marshal()
			}

			return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, ))
		}
	}()
	return , 
}

// MarshalerJSONObject is the interface to implement for struct to be encoded
type MarshalerJSONObject interface {
	MarshalJSONObject(enc *Encoder)
	IsNil() bool
}

// MarshalerJSONArray is the interface to implement
// for a slice or an array to be encoded
type MarshalerJSONArray interface {
	MarshalJSONArray(enc *Encoder)
	IsNil() bool
}

// An Encoder writes JSON values to an output stream.
type Encoder struct {
	buf      []byte
	isPooled byte
	w        io.Writer
	err      error
	hasKeys  bool
	keys     []string
}

// AppendBytes allows a modular usage by appending bytes manually to the current state of the buffer.
func ( *Encoder) ( []byte) {
	.writeBytes()
}

// AppendByte allows a modular usage by appending a single byte manually to the current state of the buffer.
func ( *Encoder) ( byte) {
	.writeByte()
}

// Buf returns the Encoder's buffer.
func ( *Encoder) () []byte {
	return .buf
}

// Write writes to the io.Writer and resets the buffer.
func ( *Encoder) () (int, error) {
	,  := .w.Write(.buf)
	.buf = .buf[:0]
	return , 
}

func ( *Encoder) () byte {
	 := len(.buf) - 1
	return .buf[]
}