func (d *Deserializer) ReadString(s *string, lenType SeriLengthPrefixType, errProducer ErrProducer, maxSize ...int) *Deserializer {
	if d.err != nil {
		return d
	}
	strLen, err := d.readSliceLength(lenType, errProducer)
	if err != nil {
		d.err = err
		return d
	}
	if len(maxSize) > 0 && strLen > maxSize[0] {
		d.err = errProducer(fmt.Errorf("%w: string defined to be of %d bytes length but max %d is allowed", ErrDeserializationLengthInvalid, strLen, maxSize[0]))
	}
	if len(d.src) < int(strLen) {
		d.err = errProducer(fmt.Errorf("%w: data is smaller than (%d) denoted string length of %d", ErrDeserializationNotEnoughData, len(d.src), strLen))
		return d
	}
	*s = string(d.src[:strLen])
	d.offset += int(strLen)
	d.src = d.src[strLen:]
	return d
}
ReadString reads a string.
package serializer
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"time"
)
type (
	ArrayOf32Bytes = [32]byte
	ArrayOf64Bytes = [64]byte
	ArrayOf49Bytes = [49]byte
	SliceOfArraysOf32Bytes = []ArrayOf32Bytes
	SliceOfArraysOf64Bytes = []ArrayOf64Bytes
	ErrProducer func(err error) error
	ErrProducerWithLeftOver func(left int, err error) error
	WrittenObjectConsumer func(index int, written []byte) error
	ReadObjectConsumerFunc func(seri Serializable)
	ReadObjectsConsumerFunc func(seri Serializables)
)
type SeriLengthPrefixType byte
const (
	SeriLengthPrefixTypeAsByte SeriLengthPrefixType = iota
	SeriLengthPrefixTypeAsUint16
	SeriLengthPrefixTypeAsUint32
)
func NewSerializer() *Serializer {
	return &Serializer{}
}
type Serializer struct {
	buf bytes.Buffer
	err error
}
func (s *Serializer) Serialize() ([]byte, error) {
	if s.err != nil {
		return nil, s.err
	}
	return s.buf.Bytes(), nil
}
func (s *Serializer) AbortIf(errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	if err := errProducer(nil); err != nil {
		s.err = err
	}
	return s
}
func (s *Serializer) Do(f func()) *Serializer {
	if s.err != nil {
		return s
	}
	f()
	return s
}
func (s *Serializer) Written() int {
	return s.buf.Len()
}
func (s *Serializer) WriteNum(v interface{}, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	if err := binary.Write(&s.buf, binary.LittleEndian, v); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) WriteBool(v bool, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	var val byte
	if v {
		val = 1
	}
	if err := s.buf.WriteByte(val); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) WriteByte(data byte, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	if err := s.buf.WriteByte(data); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) WriteBytes(data []byte, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	if _, err := s.buf.Write(data); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) writeSliceLength(l int, lenType SeriLengthPrefixType, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	switch lenType {
	case SeriLengthPrefixTypeAsByte:
		if l > math.MaxUint8 {
			s.err = errProducer(fmt.Errorf("unable to serialize collection length: length %d is out of range (0-%d)", l, math.MaxUint8))
			return s
		}
		if err := s.buf.WriteByte(byte(l)); err != nil {
			s.err = errProducer(err)
			return s
		}
	case SeriLengthPrefixTypeAsUint16:
		if l > math.MaxUint16 {
			s.err = errProducer(fmt.Errorf("unable to serialize collection length: length %d is out of range (0-%d)", l, math.MaxUint16))
			return s
		}
		if err := binary.Write(&s.buf, binary.LittleEndian, uint16(l)); err != nil {
			s.err = errProducer(err)
			return s
		}
	case SeriLengthPrefixTypeAsUint32:
		if l > math.MaxUint32 {
			s.err = errProducer(fmt.Errorf("unable to serialize collection length: length %d is out of range (0-%d)", l, math.MaxUint32))
			return s
		}
		if err := binary.Write(&s.buf, binary.LittleEndian, uint32(l)); err != nil {
			s.err = errProducer(err)
			return s
		}
	default:
		panic(fmt.Sprintf("unknown slice length type %v", lenType))
	}
	return s
}
func (s *Serializer) WriteVariableByteSlice(data []byte, lenType SeriLengthPrefixType, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	_ = s.writeSliceLength(len(data), lenType, errProducer)
	if s.err != nil {
		return s
	}
	if _, err := s.buf.Write(data); err != nil {
		s.err = errProducer(err)
		return s
	}
	return s
}
func (s *Serializer) Write32BytesArraySlice(data SliceOfArraysOf32Bytes, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, arrayRules *ArrayRules, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	sliceLength := len(data)
	var arrayElementValidator ElementValidationFunc
	if arrayRules != nil && deSeriMode.HasMode(DeSeriModePerformValidation) {
		if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil {
			s.err = errProducer(err)
			return s
		}
		arrayElementValidator = arrayRules.ElementValidationFunc(arrayRules.ValidationMode)
	}
	_ = s.writeSliceLength(sliceLength, lenType, errProducer)
	if s.err != nil {
		return s
	}
	for i := range data {
		element := data[i][:]
		if arrayElementValidator != nil {
			if err := arrayElementValidator(i, element); err != nil {
				s.err = errProducer(err)
				return s
			}
		}
		if _, err := s.buf.Write(element); err != nil {
			s.err = errProducer(err)
			return s
		}
	}
	return s
}
func (s *Serializer) Write64BytesArraySlice(data SliceOfArraysOf64Bytes, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, arrayRules *ArrayRules, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	sliceLength := len(data)
	var arrayElementValidator ElementValidationFunc
	if arrayRules != nil && deSeriMode.HasMode(DeSeriModePerformValidation) {
		if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil {
			s.err = errProducer(err)
			return s
		}
		arrayElementValidator = arrayRules.ElementValidationFunc(arrayRules.ValidationMode)
	}
	_ = s.writeSliceLength(sliceLength, lenType, errProducer)
	if s.err != nil {
		return s
	}
	for i := range data {
		element := data[i][:]
		if arrayElementValidator != nil {
			if err := arrayElementValidator(i, element); err != nil {
				s.err = errProducer(err)
				return s
			}
		}
		if _, err := s.buf.Write(element); err != nil {
			s.err = errProducer(err)
			return s
		}
	}
	return s
}
func (s *Serializer) WriteObject(seri Serializable, deSeriMode DeSerializationMode, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	seriBytes, err := seri.Serialize(deSeriMode)
	if err != nil {
		s.err = errProducer(err)
		return s
	}
	if _, err := s.buf.Write(seriBytes); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) WriteSliceOfObjects(seris Serializables, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, woc WrittenObjectConsumer, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	_ = s.writeSliceLength(len(seris), lenType, errProducer)
	if s.err != nil {
		return s
	}
	for i, seri := range seris {
		ser, err := seri.Serialize(deSeriMode)
		if err != nil {
			s.err = errProducer(err)
			return s
		}
		if _, err := s.buf.Write(ser); err != nil {
			s.err = errProducer(err)
			return s
		}
		if woc != nil {
			if err := woc(i, ser); err != nil {
				s.err = errProducer(err)
				return s
			}
		}
	}
	return s
}
func (s *Serializer) WriteTime(timeToWrite time.Time, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	nanoSeconds := timeToWrite.UnixNano()
	timeToWrite.IsZero()
	if nanoSeconds == -6795364578871345152 {
		if err := binary.Write(&s.buf, binary.LittleEndian, nanoSeconds); err != nil {
			s.err = errProducer(err)
		}
	} else {
		if err := binary.Write(&s.buf, binary.LittleEndian, nanoSeconds); err != nil {
			s.err = errProducer(err)
		}
	}
	return s
}
func (s *Serializer) WritePayload(payload Serializable, deSeriMode DeSerializationMode, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	if payload == nil {
		if err := binary.Write(&s.buf, binary.LittleEndian, uint32(0)); err != nil {
			s.err = errProducer(fmt.Errorf("unable to serialize zero payload length: %w", err))
		}
		return s
	}
	payloadBytes, err := payload.Serialize(deSeriMode)
	if err != nil {
		s.err = errProducer(fmt.Errorf("unable to serialize payload: %w", err))
		return s
	}
	if err := binary.Write(&s.buf, binary.LittleEndian, uint32(len(payloadBytes))); err != nil {
		s.err = errProducer(fmt.Errorf("unable to serialize payload length: %w", err))
		return s
	}
	if _, err := s.buf.Write(payloadBytes); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func (s *Serializer) WriteString(str string, lenType SeriLengthPrefixType, errProducer ErrProducer) *Serializer {
	if s.err != nil {
		return s
	}
	_ = s.writeSliceLength(len(str), lenType, errProducer)
	if s.err != nil {
		return s
	}
	if _, err := s.buf.Write([]byte(str)); err != nil {
		s.err = errProducer(err)
	}
	return s
}
func NewDeserializer(src []byte) *Deserializer {
	return &Deserializer{src: src}
}
type Deserializer struct {
	src    []byte
	offset int
	err    error
}
func (d *Deserializer) Skip(skip int, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	if len(d.src) < skip {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	d.offset += skip
	d.src = d.src[skip:]
	return d
}
func (d *Deserializer) ReadBool(dest *bool, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	if len(d.src) == 0 {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	switch d.src[0] {
	case 0:
		*dest = false
	case 1:
		*dest = true
	default:
		d.err = errProducer(ErrDeserializationInvalidBoolValue)
		return d
	}
	d.offset += OneByte
	d.src = d.src[OneByte:]
	return d
}
func (d *Deserializer) ReadByte(dest *byte, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	if len(d.src) == 0 {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	*dest = d.src[0]
	d.offset += OneByte
	d.src = d.src[OneByte:]
	return d
}
func (d *Deserializer) ReadNum(dest interface{}, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	l := len(d.src)
	switch x := dest.(type) {
	case *uint8:
		if l < OneByte {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		l = OneByte
		*x = d.src[0]
	case *uint16:
		if l < UInt16ByteSize {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		l = UInt16ByteSize
		*x = binary.LittleEndian.Uint16(d.src[:UInt16ByteSize])
	case *uint32:
		if l < UInt32ByteSize {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		l = UInt32ByteSize
		*x = binary.LittleEndian.Uint32(d.src[:UInt32ByteSize])
	case *uint64:
		if l < UInt64ByteSize {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		l = UInt64ByteSize
		*x = binary.LittleEndian.Uint64(d.src[:UInt64ByteSize])
	default:
		panic(fmt.Sprintf("unsupported ReadNum type %T", dest))
	}
	d.offset += l
	d.src = d.src[l:]
	return d
}
func (d *Deserializer) ReadBytes(slice *[]byte, numBytes int, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	dest := make([]byte, numBytes)
	if len(d.src) < numBytes {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	copy(dest, d.src[:numBytes])
	*slice = dest
	d.offset += numBytes
	d.src = d.src[numBytes:]
	return d
}
func (d *Deserializer) ReadVariableByteSlice(slice *[]byte, lenType SeriLengthPrefixType, errProducer ErrProducer, maxRead ...int) *Deserializer {
	if d.err != nil {
		return d
	}
	sliceLength, err := d.readSliceLength(lenType, errProducer)
	if err != nil {
		d.err = err
		return d
	}
	if len(maxRead) > 0 && sliceLength > maxRead[0] {
		d.err = errProducer(fmt.Errorf("%w: denoted %d bytes, max allowed %d ", ErrDeserializationLengthInvalid, sliceLength, maxRead[0]))
		return d
	}
	dest := make([]byte, sliceLength)
	if len(d.src) < sliceLength {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	copy(dest, d.src[:sliceLength])
	*slice = dest
	d.offset += sliceLength
	d.src = d.src[sliceLength:]
	return d
}
func (d *Deserializer) ReadArrayOf32Bytes(arr *ArrayOf32Bytes, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	const length = 32
	l := len(d.src)
	if l < length {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	copy(arr[:], d.src[:length])
	d.offset += length
	d.src = d.src[length:]
	return d
}
func (d *Deserializer) ReadArrayOf64Bytes(arr *ArrayOf64Bytes, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	const length = 64
	l := len(d.src)
	if l < length {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	copy(arr[:], d.src[:length])
	d.offset += length
	d.src = d.src[length:]
	return d
}
func (d *Deserializer) ReadArrayOf49Bytes(arr *ArrayOf49Bytes, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	const length = 49
	l := len(d.src)
	if l < length {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	copy(arr[:], d.src[:length])
	d.offset += length
	d.src = d.src[length:]
	return d
}
func (d *Deserializer) readSliceLength(lenType SeriLengthPrefixType, errProducer ErrProducer) (int, error) {
	l := len(d.src)
	var sliceLength int
	switch lenType {
	case SeriLengthPrefixTypeAsByte:
		if l < OneByte {
			return 0, errProducer(ErrDeserializationNotEnoughData)
		}
		l = OneByte
		sliceLength = int(d.src[0])
	case SeriLengthPrefixTypeAsUint16:
		if l < UInt16ByteSize {
			return 0, errProducer(ErrDeserializationNotEnoughData)
		}
		l = UInt16ByteSize
		sliceLength = int(binary.LittleEndian.Uint16(d.src[:UInt16ByteSize]))
	case SeriLengthPrefixTypeAsUint32:
		if l < UInt32ByteSize {
			return 0, errProducer(ErrDeserializationNotEnoughData)
		}
		l = UInt32ByteSize
		sliceLength = int(binary.LittleEndian.Uint32(d.src[:UInt32ByteSize]))
	default:
		panic(fmt.Sprintf("unknown slice length type %v", lenType))
	}
	d.offset += l
	d.src = d.src[l:]
	return sliceLength, nil
}
func (d *Deserializer) ReadSliceOfArraysOf32Bytes(slice *SliceOfArraysOf32Bytes, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, arrayRules *ArrayRules, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	const length = 32
	sliceLength, err := d.readSliceLength(lenType, errProducer)
	if err != nil {
		d.err = err
		return d
	}
	var arrayElementValidator ElementValidationFunc
	if arrayRules != nil && deSeriMode.HasMode(DeSeriModePerformValidation) {
		if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil {
			d.err = errProducer(err)
			return d
		}
		arrayElementValidator = arrayRules.ElementValidationFunc(arrayRules.ValidationMode)
	}
	s := make(SliceOfArraysOf32Bytes, sliceLength)
	for i := 0; i < sliceLength; i++ {
		if len(d.src) < length {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		if arrayElementValidator != nil {
			if err := arrayElementValidator(i, d.src[:length]); err != nil {
				d.err = errProducer(err)
				return d
			}
		}
		copy(s[i][:], d.src[:length])
		d.offset += length
		d.src = d.src[length:]
	}
	*slice = s
	return d
}
func (d *Deserializer) ReadSliceOfArraysOf64Bytes(slice *SliceOfArraysOf64Bytes, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, arrayRules *ArrayRules, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	const length = 64
	sliceLength, err := d.readSliceLength(lenType, errProducer)
	if err != nil {
		d.err = err
		return d
	}
	var arrayElementValidator ElementValidationFunc
	if arrayRules != nil && deSeriMode.HasMode(DeSeriModePerformValidation) {
		if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil {
			d.err = errProducer(err)
			return d
		}
		arrayElementValidator = arrayRules.ElementValidationFunc(arrayRules.ValidationMode)
	}
	s := make(SliceOfArraysOf64Bytes, sliceLength)
	for i := 0; i < sliceLength; i++ {
		if len(d.src) < length {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		if arrayElementValidator != nil {
			if err := arrayElementValidator(i, d.src[:length]); err != nil {
				d.err = errProducer(err)
				return d
			}
		}
		copy(s[i][:], d.src[:length])
		d.offset += length
		d.src = d.src[length:]
	}
	*slice = s
	return d
}
func (d *Deserializer) ReadObject(f ReadObjectConsumerFunc, deSeriMode DeSerializationMode, typeDen TypeDenotationType, serSel SerializableSelectorFunc, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	l := len(d.src)
	var ty uint32
	switch typeDen {
	case TypeDenotationUint32:
		if l < UInt32ByteSize {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		ty = binary.LittleEndian.Uint32(d.src)
	case TypeDenotationByte:
		if l < OneByte {
			d.err = errProducer(ErrDeserializationNotEnoughData)
			return d
		}
		ty = uint32(d.src[0])
	case TypeDenotationNone:
	}
	seri, err := serSel(ty)
	if err != nil {
		d.err = errProducer(err)
		return d
	}
	bytesConsumed, err := seri.Deserialize(d.src, deSeriMode)
	if err != nil {
		d.err = errProducer(err)
		return d
	}
	d.offset += bytesConsumed
	d.src = d.src[bytesConsumed:]
	f(seri)
	return d
}
func (d *Deserializer) ReadSliceOfObjects(f ReadObjectsConsumerFunc, deSeriMode DeSerializationMode, lenType SeriLengthPrefixType, typeDen TypeDenotationType, serSel SerializableSelectorFunc, arrayRules *ArrayRules, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	sliceLength, err := d.readSliceLength(lenType, errProducer)
	if err != nil {
		d.err = err
		return d
	}
	var arrayElementValidator ElementValidationFunc
	if arrayRules != nil && deSeriMode.HasMode(DeSeriModePerformValidation) {
		if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil {
			d.err = errProducer(err)
			return d
		}
		arrayElementValidator = arrayRules.ElementValidationFunc(arrayRules.ValidationMode)
	}
	var seris Serializables
	for i := 0; i < int(sliceLength); i++ {
		srcBefore := d.src
		offsetBefore := d.offset
		var seri Serializable
		d.ReadObject(func(readSeri Serializable) { seri = readSeri }, deSeriMode, typeDen, serSel, func(err error) error {
			return errProducer(err)
		})
		if seri == nil {
			return d
		}
		bytesConsumed := d.offset - offsetBefore
		if arrayElementValidator != nil {
			if err := arrayElementValidator(i, srcBefore[:bytesConsumed]); err != nil {
				d.err = errProducer(err)
				return d
			}
		}
		seris = append(seris, seri)
	}
	f(seris)
	return d
}
func (d *Deserializer) ReadTime(dest *time.Time, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	l := len(d.src)
	if l < Int64ByteSize {
		d.err = errProducer(ErrDeserializationNotEnoughData)
		return d
	}
	l = Int64ByteSize
	nanoSeconds := int64(binary.LittleEndian.Uint64(d.src[:Int64ByteSize]))
	if nanoSeconds == 0 {
		*dest = time.Time{}
	} else {
		*dest = time.Unix(0, nanoSeconds)
	}
	d.offset += l
	d.src = d.src[l:]
	return d
}
func (d *Deserializer) ReadPayload(f ReadObjectConsumerFunc, deSeriMode DeSerializationMode, sel SerializableSelectorFunc, errProducer ErrProducer) *Deserializer {
	if d.err != nil {
		return d
	}
	if len(d.src) < PayloadLengthByteSize {
		d.err = errProducer(fmt.Errorf("%w: data is smaller than payload length denotation", ErrDeserializationNotEnoughData))
		return d
	}
	payloadLength := binary.LittleEndian.Uint32(d.src)
	d.offset += PayloadLengthByteSize
	d.src = d.src[PayloadLengthByteSize:]
	if payloadLength == 0 {
		return d
	}
	switch {
	case len(d.src) < MinPayloadByteSize:
		d.err = errProducer(fmt.Errorf("%w: payload data is smaller than min. required length %d", ErrDeserializationNotEnoughData, MinPayloadByteSize))
		return d
	case len(d.src) < int(payloadLength):
		d.err = errProducer(fmt.Errorf("%w: payload length denotes more bytes than are available", ErrDeserializationNotEnoughData))
		return d
	}
	payload, err := sel(binary.LittleEndian.Uint32(d.src))
	if err != nil {
		d.err = errProducer(err)
		return d
	}
	payloadBytesConsumed, err := payload.Deserialize(d.src, deSeriMode)
	if err != nil {
		d.err = errProducer(err)
		return d
	}
	if payloadBytesConsumed != int(payloadLength) {
		d.err = errProducer(fmt.Errorf("%w: denoted payload length (%d) doesn't equal the size of deserialized payload (%d)", ErrInvalidBytes, payloadLength, payloadBytesConsumed))
		return d
	}
	d.offset += payloadBytesConsumed
	d.src = d.src[payloadBytesConsumed:]
	f(payload)
	return d
}