diff --git a/tests/lux_data_test.go b/tests/lux_data_test.go index c2cff75..92e6570 100644 --- a/tests/lux_data_test.go +++ b/tests/lux_data_test.go @@ -10,7 +10,7 @@ func TestWriteGrow(t *testing.T) { first, second := []byte{1, 2, 3, 4}, []byte{5, 6, 7, 8} must := []byte{1, 2, 3, 4, 5, 6, 7, 8} - buf := types.NewLuxBuffer(4) + buf := types.AllocLuxBuffer(4) buf.WriteBytes(first) t.Log(buf.AllBytes()) @@ -21,3 +21,40 @@ func TestWriteGrow(t *testing.T) { t.Fail() } } + +func TestInts(t *testing.T) { + wd := types.AllocLuxBuffer(1) + wd.WriteUint16(1234) + wd.WriteUint16(4321) + wd.WriteUint64(69) + wd.WriteUint32(2967279234) + + if rd := wd.ReadUint16(); rd != 1234 { + t.Fatal(rd) + } + if rd := wd.ReadUint16(); rd != 4321 { + t.Fatal(rd) + } + if rd := wd.ReadUint64(); rd != 69 { + t.Fatal(rd) + } + if rd := wd.ReadUint32(); rd != 2967279234 { + t.Fatal(rd) + } +} + +func TestStrings(t *testing.T) { + wd := types.AllocLuxBuffer(1) + wd.WriteString("a") // 4 + wd.WriteString("hello") // 8 + + if rd := wd.ReadString(); rd != "a" { + t.Fatal(rd) + } + if rd := wd.ReadString(); rd != "hello" { + t.Fatal(rd) + } + if wd.Length() != 12 { + t.Fatalf("string misaligned size: %d\n", wd.Length()) + } +} diff --git a/types/lux_data.go b/types/lux_data.go index f6b9967..b019e27 100644 --- a/types/lux_data.go +++ b/types/lux_data.go @@ -14,7 +14,7 @@ type LuxBuffer struct { len int } -func NewLuxBuffer(cap int) *LuxBuffer { +func AllocLuxBuffer(cap int) *LuxBuffer { return &LuxBuffer{ data: make([]byte, cap), offset: 0, @@ -22,6 +22,10 @@ func NewLuxBuffer(cap int) *LuxBuffer { } } +func NewLuxBuffer() *LuxBuffer { + return AllocLuxBuffer(MIN_BUFFER_SIZE) +} + func FromSlice(bytes []byte) *LuxBuffer { return &LuxBuffer{ data: bytes, @@ -42,8 +46,14 @@ func (buf *LuxBuffer) Length() int { return buf.len } +// available capacity to write (before growing) func (buf *LuxBuffer) Available() int { - return buf.Capacity() - buf.Length() + return buf.Capacity() - buf.len +} + +// available length to read +func (buf *LuxBuffer) Remaining() int { + return buf.len - buf.offset } func (buf *LuxBuffer) Grow(grow int) { @@ -74,3 +84,78 @@ func (buf *LuxBuffer) WriteNext(size int) []byte { func (buf *LuxBuffer) WriteBytes(bytes []byte) { copy(buf.WriteNext(len(bytes)), bytes) } + +func (buf *LuxBuffer) ReadNext(size int) []byte { + next := buf.data[buf.offset : buf.offset+size] + buf.offset += size + + return next +} + +func (buf *LuxBuffer) Skip(skip int) { + buf.offset += skip +} + +// explicit copy of read bytes +func (buf *LuxBuffer) CopyBytes(size int) []byte { + read := make([]byte, size) + copy(read, buf.ReadNext(size)) + + return read +} + +func (buf *LuxBuffer) ReadUint16() uint16 { + return NO.Uint16(buf.ReadNext(2)) +} + +func (buf *LuxBuffer) ReadUint32() uint32 { + return NO.Uint32(buf.ReadNext(4)) +} + +func (buf *LuxBuffer) ReadUint64() uint64 { + return NO.Uint64(buf.ReadNext(8)) +} + +func (buf *LuxBuffer) WriteUint16(val uint16) { + NO.PutUint16(buf.WriteNext(2), val) +} + +func (buf *LuxBuffer) WriteUint32(val uint32) { + NO.PutUint32(buf.WriteNext(4), val) +} + +func (buf *LuxBuffer) WriteUint64(val uint64) { + NO.PutUint64(buf.WriteNext(8), val) +} + +// variable-length blocks can cause misaligned size, +// so we make method for them, forcing padding + +func (buf *LuxBuffer) ReadVarBlock() []byte { + len := buf.ReadUint16() + bytes := buf.ReadNext(int(len)) + if len%2 != 0 { + buf.Skip(1) // skip padding + } + + return bytes +} + +func (buf *LuxBuffer) WriteVarBlock(bytes []byte) { + len := uint16(len(bytes)) + + buf.WriteUint16(len) + buf.WriteBytes(bytes) + if len%2 != 0 { + buf.WriteNext(1) // padding + } +} + +// strings in LUX protocol format will be padded to align of 2 +func (buf *LuxBuffer) ReadString() string { + return string(buf.ReadVarBlock()) +} + +func (buf *LuxBuffer) WriteString(val string) { + buf.WriteVarBlock([]byte(val)) +}