openreplay/backend/pkg/messages/bytes.go
Alexander 17d9a4a116
[Iterator] batch pre-decoding (#852)
* feat(backend): batch pre-decoding implementation
2022-12-05 11:21:26 +01:00

119 lines
2 KiB
Go

package messages
import (
"errors"
"fmt"
"io"
)
type BytesReader interface {
ReadSize() (uint64, error)
ReadByte() (byte, error)
ReadUint() (uint64, error)
ReadInt() (int64, error)
ReadBoolean() (bool, error)
ReadString() (string, error)
Data() []byte
Pointer() int64
SetPointer(p int64)
}
type bytesReaderImpl struct {
data []byte
curr int64
}
func NewBytesReader(data []byte) BytesReader {
return &bytesReaderImpl{
data: data,
}
}
func (m *bytesReaderImpl) ReadSize() (uint64, error) {
if len(m.data)-int(m.curr) < 3 {
return 0, fmt.Errorf("out of range")
}
var size uint64
for i, b := range m.data[m.curr : m.curr+3] {
size += uint64(b) << (8 * i)
}
m.curr += 3
return size, nil
}
func (m *bytesReaderImpl) ReadByte() (byte, error) {
if int(m.curr) >= len(m.data) {
return 0, io.EOF
}
m.curr++
return m.data[m.curr-1], nil
}
func (m *bytesReaderImpl) ReadUint() (uint64, error) {
var x uint64
var s uint
i := 0
for {
b, err := m.ReadByte()
if err != nil {
return x, err
}
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
return x, errors.New("uint overflow")
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
s += 7
i++
}
}
func (m *bytesReaderImpl) ReadInt() (int64, error) {
ux, err := m.ReadUint()
x := int64(ux >> 1)
if err != nil {
return x, err
}
if ux&1 != 0 {
x = ^x
}
return x, err
}
func (m *bytesReaderImpl) ReadBoolean() (bool, error) {
val, err := m.ReadByte()
if err != nil {
return false, err
}
return val == 1, nil
}
func (m *bytesReaderImpl) ReadString() (string, error) {
l, err := m.ReadUint()
if err != nil {
return "", err
}
if l > 10e6 {
return "", errors.New("too long string")
}
if len(m.data)-int(m.curr) < int(l) {
return "", fmt.Errorf("out of range")
}
str := string(m.data[m.curr : int(m.curr)+int(l)])
m.curr += int64(l)
return str, nil
}
func (m *bytesReaderImpl) Data() []byte {
return m.data
}
func (m *bytesReaderImpl) Pointer() int64 {
return m.curr
}
func (m *bytesReaderImpl) SetPointer(p int64) {
m.curr = p
}