diff --git a/bytebuffer/bytebuffer.go b/bytebuffer/bytebuffer.go new file mode 100644 index 0000000..824de93 --- /dev/null +++ b/bytebuffer/bytebuffer.go @@ -0,0 +1,218 @@ +package bytebuffer + +import ( + "encoding/binary" + "errors" +) + +var ( + ErrBufferUnderflow = errors.New("bytebuffer: buffer underflow") + ErrBufferOverflow = errors.New("bytebuffer: buffer overflow") + ErrInvalidPosition = errors.New("bytebuffer: invalid position") + ErrInvalidLimit = errors.New("bytebuffer: invalid limit") +) + +type ByteBuffer struct { + buf []byte + pos int + limit int + order binary.ByteOrder +} + +func Allocate(capacity int) *ByteBuffer { + if capacity < 0 { + capacity = 0 + } + b := make([]byte, capacity) + return &ByteBuffer{ + buf: b, + pos: 0, + limit: capacity, + order: binary.BigEndian, + } +} + +func Wrap(data []byte) *ByteBuffer { + return &ByteBuffer{ + buf: data, + pos: 0, + limit: len(data), + order: binary.BigEndian, + } +} + +func (b *ByteBuffer) Order(order binary.ByteOrder) *ByteBuffer { + if order != nil { + b.order = order + } + return b +} + +func (b *ByteBuffer) Capacity() int { return len(b.buf) } +func (b *ByteBuffer) Position() int { return b.pos } +func (b *ByteBuffer) Limit() int { return b.limit } + +func (b *ByteBuffer) SetPosition(pos int) error { + if pos < 0 || pos > b.limit { + return ErrInvalidPosition + } + b.pos = pos + return nil +} + +func (b *ByteBuffer) SetLimit(limit int) error { + if limit < 0 || limit > len(b.buf) { + return ErrInvalidLimit + } + b.limit = limit + if b.pos > b.limit { + b.pos = b.limit + } + return nil +} + +func (b *ByteBuffer) Remaining() int { + return b.limit - b.pos +} + +func (b *ByteBuffer) HasRemaining() bool { + return b.Remaining() > 0 +} + +// Clear: position=0, limit=capacity +func (b *ByteBuffer) Clear() *ByteBuffer { + b.pos = 0 + b.limit = len(b.buf) + return b +} + +// Flip: limit=position, position=0 +func (b *ByteBuffer) Flip() *ByteBuffer { + b.limit = b.pos + b.pos = 0 + return b +} + +// Rewind: position=0 +func (b *ByteBuffer) Rewind() *ByteBuffer { + b.pos = 0 + return b +} + +// Array возвращает весь underlying массив. +func (b *ByteBuffer) Array() []byte { + return b.buf +} + +// Bytes возвращает readable срез [position:limit]. +func (b *ByteBuffer) Bytes() []byte { + return b.buf[b.pos:b.limit] +} + +func (b *ByteBuffer) ensureWrite(n int) error { + if b.pos+n > b.limit { + return ErrBufferOverflow + } + return nil +} + +func (b *ByteBuffer) ensureRead(n int) error { + if b.pos+n > b.limit { + return ErrBufferUnderflow + } + return nil +} + +func (b *ByteBuffer) Put(v byte) error { + if err := b.ensureWrite(1); err != nil { + return err + } + b.buf[b.pos] = v + b.pos++ + return nil +} + +func (b *ByteBuffer) PutBytes(p []byte) error { + if err := b.ensureWrite(len(p)); err != nil { + return err + } + copy(b.buf[b.pos:], p) + b.pos += len(p) + return nil +} + +func (b *ByteBuffer) PutUint16(v uint16) error { + if err := b.ensureWrite(2); err != nil { + return err + } + b.order.PutUint16(b.buf[b.pos:b.pos+2], v) + b.pos += 2 + return nil +} + +func (b *ByteBuffer) PutUint32(v uint32) error { + if err := b.ensureWrite(4); err != nil { + return err + } + b.order.PutUint32(b.buf[b.pos:b.pos+4], v) + b.pos += 4 + return nil +} + +func (b *ByteBuffer) PutUint64(v uint64) error { + if err := b.ensureWrite(8); err != nil { + return err + } + b.order.PutUint64(b.buf[b.pos:b.pos+8], v) + b.pos += 8 + return nil +} + +func (b *ByteBuffer) Get() (byte, error) { + if err := b.ensureRead(1); err != nil { + return 0, err + } + v := b.buf[b.pos] + b.pos++ + return v, nil +} + +func (b *ByteBuffer) GetBytes(n int) ([]byte, error) { + if n < 0 { + return nil, ErrBufferUnderflow + } + if err := b.ensureRead(n); err != nil { + return nil, err + } + out := make([]byte, n) + copy(out, b.buf[b.pos:b.pos+n]) + b.pos += n + return out, nil +} + +func (b *ByteBuffer) GetUint16() (uint16, error) { + if err := b.ensureRead(2); err != nil { + return 0, err + } + v := b.order.Uint16(b.buf[b.pos : b.pos+2]) + b.pos += 2 + return v, nil +} + +func (b *ByteBuffer) GetUint32() (uint32, error) { + if err := b.ensureRead(4); err != nil { + return 0, err + } + v := b.order.Uint32(b.buf[b.pos : b.pos+4]) + b.pos += 4 + return v, nil +} + +func (b *ByteBuffer) GetUint64() (uint64, error) { + if err := b.ensureRead(8); err != nil { + return 0, err + } + v := b.order.Uint64(b.buf[b.pos : b.pos+8]) + b.pos += 8 + return v, nil +}