package thrift

import (
	
	
	
	
	
	

	
)

// BinaryProtocol is a Protocol implementation for the binary thrift protocol.
//
// https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md
type BinaryProtocol struct {
	NonStrict bool
}

func ( *BinaryProtocol) ( io.Reader) Reader {
	return &binaryReader{p: , r: }
}

func ( *BinaryProtocol) ( io.Writer) Writer {
	return &binaryWriter{p: , w: }
}

func ( *BinaryProtocol) () Features {
	return 0
}

type binaryReader struct {
	p *BinaryProtocol
	r io.Reader
	b [8]byte
}

func ( *binaryReader) () Protocol {
	return .p
}

func ( *binaryReader) () io.Reader {
	return .r
}

func ( *binaryReader) () (bool, error) {
	,  := .ReadByte()
	return  != 0, 
}

func ( *binaryReader) () (int8, error) {
	,  := .ReadByte()
	return int8(), 
}

func ( *binaryReader) () (int16, error) {
	,  := .read(2)
	if len() < 2 {
		return 0, 
	}
	return int16(binary.BigEndian.Uint16()), nil
}

func ( *binaryReader) () (int32, error) {
	,  := .read(4)
	if len() < 4 {
		return 0, 
	}
	return int32(binary.BigEndian.Uint32()), nil
}

func ( *binaryReader) () (int64, error) {
	,  := .read(8)
	if len() < 8 {
		return 0, 
	}
	return int64(binary.BigEndian.Uint64()), nil
}

func ( *binaryReader) () (float64, error) {
	,  := .read(8)
	if len() < 8 {
		return 0, 
	}
	return math.Float64frombits(binary.BigEndian.Uint64()), nil
}

func ( *binaryReader) () ([]byte, error) {
	,  := .ReadLength()
	if  != nil {
		return nil, 
	}
	 := make([]byte, )
	_,  = io.ReadFull(.r, )
	return , 
}

func ( *binaryReader) () (string, error) {
	,  := .ReadBytes()
	return unsafecast.String(), 
}

func ( *binaryReader) () (int, error) {
	,  := .read(4)
	if len() < 4 {
		return 0, 
	}
	 := binary.BigEndian.Uint32()
	if  > math.MaxInt32 {
		return 0, fmt.Errorf("length out of range: %d", )
	}
	return int(), nil
}

func ( *binaryReader) () (Message, error) {
	 := Message{}

	,  := .read(4)
	if len() < 4 {
		return , 
	}

	if ([0] >> 7) == 0 { // non-strict
		 := int(binary.BigEndian.Uint32())
		 := make([]byte, )
		,  := io.ReadFull(.r, )
		if  != nil {
			return , dontExpectEOF()
		}
		.Name = unsafecast.String()

		,  := .ReadInt8()
		if  != nil {
			return , dontExpectEOF()
		}

		.Type = MessageType( & 0x7)
	} else {
		.Type = MessageType([3] & 0x7)

		if .Name,  = .ReadString();  != nil {
			return , dontExpectEOF()
		}
	}

	.SeqID,  = .ReadInt32()
	return , 
}

func ( *binaryReader) () (Field, error) {
	,  := .ReadInt8()
	if  != nil {
		return Field{}, 
	}
	,  := .ReadInt16()
	if  != nil {
		return Field{}, 
	}
	return Field{ID: , Type: Type()}, nil
}

func ( *binaryReader) () (List, error) {
	,  := .ReadInt8()
	if  != nil {
		return List{}, 
	}
	,  := .ReadInt32()
	if  != nil {
		return List{}, dontExpectEOF()
	}
	return List{Size: , Type: Type()}, nil
}

func ( *binaryReader) () (Set, error) {
	,  := .ReadList()
	return Set(), 
}

func ( *binaryReader) () (Map, error) {
	,  := .ReadByte()
	if  != nil {
		return Map{}, 
	}
	,  := .ReadByte()
	if  != nil {
		return Map{}, dontExpectEOF()
	}
	,  := .ReadInt32()
	if  != nil {
		return Map{}, dontExpectEOF()
	}
	return Map{Size: , Key: Type(), Value: Type()}, nil
}

func ( *binaryReader) () (byte, error) {
	switch x := .r.(type) {
	case *bytes.Buffer:
		return .ReadByte()
	case *bytes.Reader:
		return .ReadByte()
	case *bufio.Reader:
		return .ReadByte()
	case io.ByteReader:
		return .ReadByte()
	default:
		,  := .read(1)
		if  != nil {
			return 0, 
		}
		return [0], nil
	}
}

func ( *binaryReader) ( int) ([]byte, error) {
	,  := io.ReadFull(.r, .b[:])
	return .b[:], 
}

type binaryWriter struct {
	p *BinaryProtocol
	b [8]byte
	w io.Writer
}

func ( *binaryWriter) () Protocol {
	return .p
}

func ( *binaryWriter) () io.Writer {
	return .w
}

func ( *binaryWriter) ( bool) error {
	var  byte
	if  {
		 = 1
	}
	return .writeByte()
}

func ( *binaryWriter) ( int8) error {
	return .writeByte(byte())
}

func ( *binaryWriter) ( int16) error {
	binary.BigEndian.PutUint16(.b[:2], uint16())
	return .write(.b[:2])
}

func ( *binaryWriter) ( int32) error {
	binary.BigEndian.PutUint32(.b[:4], uint32())
	return .write(.b[:4])
}

func ( *binaryWriter) ( int64) error {
	binary.BigEndian.PutUint64(.b[:8], uint64())
	return .write(.b[:8])
}

func ( *binaryWriter) ( float64) error {
	binary.BigEndian.PutUint64(.b[:8], math.Float64bits())
	return .write(.b[:8])
}

func ( *binaryWriter) ( []byte) error {
	if  := .WriteLength(len());  != nil {
		return 
	}
	return .write()
}

func ( *binaryWriter) ( string) error {
	if  := .WriteLength(len());  != nil {
		return 
	}
	return .writeString()
}

func ( *binaryWriter) ( int) error {
	if  < 0 {
		return fmt.Errorf("negative length cannot be encoded in thrift: %d", )
	}
	if  > math.MaxInt32 {
		return fmt.Errorf("length is too large to be encoded in thrift: %d", )
	}
	return .WriteInt32(int32())
}

func ( *binaryWriter) ( Message) error {
	if .p.NonStrict {
		if  := .WriteString(.Name);  != nil {
			return 
		}
		if  := .writeByte(byte(.Type));  != nil {
			return 
		}
	} else {
		.b[0] = 1 << 7
		.b[1] = 0
		.b[2] = 0
		.b[3] = byte(.Type) & 0x7
		binary.BigEndian.PutUint32(.b[4:], uint32(len(.Name)))

		if  := .write(.b[:8]);  != nil {
			return 
		}
		if  := .writeString(.Name);  != nil {
			return 
		}
	}
	return .WriteInt32(.SeqID)
}

func ( *binaryWriter) ( Field) error {
	if  := .writeByte(byte(.Type));  != nil {
		return 
	}
	return .WriteInt16(.ID)
}

func ( *binaryWriter) ( List) error {
	if  := .writeByte(byte(.Type));  != nil {
		return 
	}
	return .WriteInt32(.Size)
}

func ( *binaryWriter) ( Set) error {
	return .WriteList(List())
}

func ( *binaryWriter) ( Map) error {
	if  := .writeByte(byte(.Key));  != nil {
		return 
	}
	if  := .writeByte(byte(.Value));  != nil {
		return 
	}
	return .WriteInt32(.Size)
}

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

func ( *binaryWriter) ( string) error {
	,  := io.WriteString(.w, )
	return 
}

func ( *binaryWriter) ( byte) error {
	// The special cases are intended to reduce the runtime overheadof testing
	// for the io.ByteWriter interface for common types. Type assertions on a
	// concrete type is just a pointer comparison, instead of requiring a
	// complex lookup in the type metadata.
	switch x := .w.(type) {
	case *bytes.Buffer:
		return .WriteByte()
	case *bufio.Writer:
		return .WriteByte()
	case io.ByteWriter:
		return .WriteByte()
	default:
		.b[0] = 
		return .write(.b[:1])
	}
}