package meta import ( "io" "github.com/pkg/errors" "github.com/vmihailenco/msgpack/v5" "github.com/vmihailenco/msgpack/v5/msgpcode" ) var ( FieldNotFound = errors.New("field not found") NoOpenContainer = errors.New("there is no open container") ) type msgpackReader struct { dec *msgpack.Decoder stack []readContainer curr readContainer } type readContainer struct { length int } func NewMsgpackReader(r io.Reader) Reader { return &msgpackReader{ dec: msgpack.NewDecoder(r), stack: make([]readContainer, 0, 2), curr: readContainer{}, } } func (rd *msgpackReader) ReadInt8(v *int8, targetField string) error { return decodeInt8(rd.dec, v) } func (rd *msgpackReader) ReadInt16(v *int16, targetField string) error { return decodeInt16(rd.dec, v) } func (rd *msgpackReader) ReadInt32(v *int32, targetField string) error { return decodeInt32(rd.dec, v) } func (rd *msgpackReader) ReadInt64(v *int64, targetField string) error { return decodeInt64(rd.dec, v) } func (rd *msgpackReader) ReadUint8(v *uint8, targetField string) error { return decodeUint8(rd.dec, v) } func (rd *msgpackReader) ReadUint16(v *uint16, targetField string) error { return decodeUint16(rd.dec, v) } func (rd *msgpackReader) ReadUint32(v *uint32, targetField string) error { return decodeUint32(rd.dec, v) } func (rd *msgpackReader) ReadUint64(v *uint64, targetField string) error { return decodeUint64(rd.dec, v) } func (rd *msgpackReader) ReadBool(v *bool, targetField string) error { return decodeBool(rd.dec, v) } func (rd *msgpackReader) ReadFloat32(v *float32, targetField string) error { return decodeFloat32(rd.dec, v) } func (rd *msgpackReader) ReadFloat64(v *float64, targetField string) error { return decodeFloat64(rd.dec, v) } func (rd *msgpackReader) ReadString(v *string, targetField string) error { return decodeString(rd.dec, v) } func (rd *msgpackReader) ReadBytes(v *[]byte, targetField string) error { return decodeBytes(rd.dec, v) } func (rd *msgpackReader) BeginContainer(targetField string) error { return rd.beginContainer(targetField) } func (rd *msgpackReader) EndContainer() error { return rd.endContainer() } func (rd *msgpackReader) BeginCollection(targetField string) error { return rd.beginContainer(targetField) } func (rd *msgpackReader) EndCollection() error { return rd.endContainer() } func (rd *msgpackReader) ContainerSize() (int, error) { return rd.curr.length, nil } func (rd *msgpackReader) IsContainerAssoc() (bool, error) { return false, nil } func (rd *msgpackReader) Skip() error { return errors.WithStack(rd.dec.Skip()) } func (rd *msgpackReader) TryReadMask() (bool, FieldsMask, error) { maskLen, err := rd.dec.DecodeArrayLen() if err != nil { if err == io.EOF { return false, FieldsMask{}, nil } return false, FieldsMask{}, errors.WithStack(err) } var mask FieldsMask for i := 0; i < maskLen; i++ { maskPart, err := rd.dec.DecodeUint64() if err != nil { return false, FieldsMask{}, errors.WithStack(err) } mask.SetPartFromUint64(i, maskPart) } return true, mask, nil } func (rd *msgpackReader) beginContainer(field string) error { code, err := rd.dec.PeekCode() if err != nil { return errors.WithStack(err) } switch { case code == msgpcode.Nil: if err := rd.dec.DecodeNil(); err != nil { return errors.WithStack(err) } rd.stack = append(rd.stack, rd.curr) rd.curr = readContainer{ length: 0, } case msgpcode.IsFixedArray(code), code == msgpcode.Array16, code == msgpcode.Array32: l, err := rd.dec.DecodeArrayLen() if err != nil { return errors.WithStack(err) } rd.stack = append(rd.stack, rd.curr) rd.curr = readContainer{ length: l, } default: return errors.Errorf("field `%s` is not an array", field) } return nil } func (rd *msgpackReader) endContainer() error { if len(rd.stack) == 0 { return NoOpenContainer } rd.curr = rd.stack[len(rd.stack)-1] rd.stack = rd.stack[:len(rd.stack)-1] return nil } func decodeUint8(dec *msgpack.Decoder, v *uint8) error { tmp, err := dec.DecodeUint8() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeUint16(dec *msgpack.Decoder, v *uint16) error { tmp, err := dec.DecodeUint16() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeUint32(dec *msgpack.Decoder, v *uint32) error { tmp, err := dec.DecodeUint32() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeUint64(dec *msgpack.Decoder, v *uint64) error { tmp, err := dec.DecodeUint64() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeInt8(dec *msgpack.Decoder, v *int8) error { tmp, err := dec.DecodeInt8() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeInt16(dec *msgpack.Decoder, v *int16) error { tmp, err := dec.DecodeInt16() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeInt32(dec *msgpack.Decoder, v *int32) error { tmp, err := dec.DecodeInt32() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeInt64(dec *msgpack.Decoder, v *int64) error { tmp, err := dec.DecodeInt64() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeBool(dec *msgpack.Decoder, v *bool) error { tmp, err := dec.DecodeBool() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeFloat32(dec *msgpack.Decoder, v *float32) error { code, err := dec.PeekCode() if err != nil { return errors.WithStack(err) } if code == msgpcode.Double { var tmp float64 if err := decodeFloat64(dec, &tmp); err != nil { return err } *v = float32(tmp) return nil } tmp, err := dec.DecodeFloat32() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeFloat64(dec *msgpack.Decoder, v *float64) error { tmp, err := dec.DecodeFloat64() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeString(dec *msgpack.Decoder, v *string) error { tmp, err := dec.DecodeString() if err != nil { return errors.WithStack(err) } *v = tmp return nil } func decodeBytes(dec *msgpack.Decoder, v *[]byte) error { tmp, err := dec.DecodeBytes() if err != nil { return errors.WithStack(err) } *v = tmp return nil }