Jelajahi Sumber

Update buffer to support io.Reader and unroll generic read/write methods to avoid escaping

Matt Bolt 2 bulan lalu
induk
melakukan
5525f0922d
3 mengubah file dengan 716 tambahan dan 182 penghapusan
  1. 189 182
      core/pkg/util/buffer.go
  2. 458 0
      core/pkg/util/bufferhelper.go
  3. 69 0
      core/pkg/util/bufferpool.go

+ 189 - 182
core/pkg/util/buffer.go

@@ -1,30 +1,36 @@
 package util
 
 import (
+	"bufio"
 	"bytes"
-	"encoding/binary"
 	"errors"
+	"fmt"
 	"io"
 	"math"
+	"os"
 	"unsafe"
 
 	"github.com/opencost/opencost/core/pkg/util/stringutil"
 )
 
+var bytePool *bufferPool = newBufferPool()
+
 // NonPrimitiveTypeError represents an error where the user provided a non-primitive data type for reading/writing
 var NonPrimitiveTypeError error = errors.New("Type provided to read/write does not fit inside 8 bytes.")
 
 // Buffer is a utility type which implements a very basic binary protocol for
 // writing core go types.
 type Buffer struct {
-	b *bytes.Buffer
+	b  *bufio.Reader
+	bw *bytes.Buffer
 }
 
 // NewBuffer creates a new Buffer instance using LittleEndian ByteOrder.
 func NewBuffer() *Buffer {
 	var b bytes.Buffer
 	return &Buffer{
-		b: &b,
+		b:  nil,
+		bw: &b,
 	}
 }
 
@@ -32,7 +38,7 @@ func NewBuffer() *Buffer {
 // The new buffer assumes ownership of the byte slice.
 func NewBufferFromBytes(b []byte) *Buffer {
 	return &Buffer{
-		b: bytes.NewBuffer(b),
+		bw: bytes.NewBuffer(b),
 	}
 }
 
@@ -41,180 +47,296 @@ func NewBufferFromBytes(b []byte) *Buffer {
 func NewBufferFrom(b *Buffer) *Buffer {
 	bb := b.Bytes()
 	return &Buffer{
-		b: bytes.NewBuffer(bb),
+		bw: bytes.NewBuffer(bb),
+	}
+}
+
+// NewBufferFromReader creates a new Buffer instance using the provided io.Reader. This
+// buffer is set to read-only.
+func NewBufferFromReader(reader io.Reader) *Buffer {
+	return &Buffer{
+		b:  bufio.NewReader(reader),
+		bw: nil,
 	}
 }
 
-// WriteBool writes a bool value to the buffer.
-func (b *Buffer) WriteBool(t bool) {
-	write(b.b, t)
+// WriteBool writes a bool value to the buffer
+func (b *Buffer) WriteBool(i bool) {
+	b.checkRO()
+	writeBool(b.bw, i)
 }
 
 // WriteInt writes an int value to the buffer.
 func (b *Buffer) WriteInt(i int) {
-	write(b.b, int32(i))
+	b.checkRO()
+	writeInt(b.bw, i)
 }
 
 // WriteInt8 writes an int8 value to the buffer.
 func (b *Buffer) WriteInt8(i int8) {
-	write(b.b, i)
+	b.checkRO()
+	writeInt8(b.bw, i)
 }
 
 // WriteInt16 writes an int16 value to the buffer.
 func (b *Buffer) WriteInt16(i int16) {
-	write(b.b, i)
+	b.checkRO()
+	writeInt16(b.bw, i)
 }
 
 // WriteInt32 writes an int32 value to the buffer.
 func (b *Buffer) WriteInt32(i int32) {
-	write(b.b, i)
+	b.checkRO()
+	writeInt32(b.bw, i)
 }
 
 // WriteInt64 writes an int64 value to the buffer.
 func (b *Buffer) WriteInt64(i int64) {
-	write(b.b, i)
+	b.checkRO()
+	writeInt64(b.bw, i)
 }
 
 // WriteUInt writes a uint value to the buffer.
 func (b *Buffer) WriteUInt(i uint) {
-	write(b.b, i)
+	b.checkRO()
+	writeUint(b.bw, i)
 }
 
 // WriteUInt8 writes a uint8 value to the buffer.
 func (b *Buffer) WriteUInt8(i uint8) {
-	write(b.b, i)
+	b.checkRO()
+	writeUint8(b.bw, i)
 }
 
 // WriteUInt16 writes a uint16 value to the buffer.
 func (b *Buffer) WriteUInt16(i uint16) {
-	write(b.b, i)
+	b.checkRO()
+	writeUint16(b.bw, i)
 }
 
 // WriteUInt32 writes a uint32 value to the buffer.
 func (b *Buffer) WriteUInt32(i uint32) {
-	write(b.b, i)
+	b.checkRO()
+	writeUint32(b.bw, i)
 }
 
 // WriteUInt64 writes a uint64 value to the buffer.
 func (b *Buffer) WriteUInt64(i uint64) {
-	write(b.b, i)
+	b.checkRO()
+	writeUint64(b.bw, i)
 }
 
 // WriteFloat32 writes a float32 value to the buffer.
 func (b *Buffer) WriteFloat32(i float32) {
-	write(b.b, i)
+	b.checkRO()
+	writeFloat32(b.bw, i)
 }
 
 // WriteFloat64 writes a float64 value to the buffer.
 func (b *Buffer) WriteFloat64(i float64) {
-	write(b.b, i)
+	b.checkRO()
+	writeFloat64(b.bw, i)
 }
 
 // WriteString writes the string's length as a uint16 followed by the string contents.
 func (b *Buffer) WriteString(i string) {
+	b.checkRO()
 	s := stringToBytes(i)
 
 	// string lengths are limited to uint16 - See ReadString()
 	if len(s) > math.MaxUint16 {
 		s = s[:math.MaxUint16]
 	}
-	write(b.b, uint16(len(s)))
-	b.b.Write(s)
+	writeUint16(b.bw, uint16(len(s)))
+	b.bw.Write(s)
 }
 
 // WriteBytes writes the contents of the byte slice to the buffer.
 func (b *Buffer) WriteBytes(bytes []byte) {
-	b.b.Write(bytes)
+	b.checkRO()
+	b.bw.Write(bytes)
+}
+
+// Bytes returns the unread portion of the underlying buffer storage.
+func (b *Buffer) Bytes() []byte {
+	if b.bw != nil {
+		return b.bw.Bytes()
+	}
+
+	bytes, err := io.ReadAll(b.b)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "failed to read remaining bytes from Buffer: %s\n", err)
+	}
+	return bytes
+}
+
+func (b *Buffer) Peek(length int) ([]byte, error) {
+	if b.bw != nil {
+		return nil, fmt.Errorf("unsupported Peek() operation on read/write buffer.")
+	}
+	return b.b.Peek(length)
+}
+
+// this should be inlined
+func (b *Buffer) checkRO() {
+	if b.bw == nil {
+		panic("Buffer is set to read-only")
+	}
 }
 
 // ReadBool reads a bool value from the buffer.
 func (b *Buffer) ReadBool() bool {
 	var i bool
-	read(b.b, &i)
+	if b.bw != nil {
+		readBool(b.bw, &i)
+		return i
+	}
+
+	readBuffBool(b.b, &i)
 	return i
 }
 
 // ReadInt reads an int value from the buffer.
 func (b *Buffer) ReadInt() int {
-	var i int32
-	read(b.b, &i)
-	return int(i)
+	var i int
+	if b.bw != nil {
+		readInt(b.bw, &i)
+		return i
+	}
+
+	readBuffInt(b.b, &i)
+	return i
 }
 
 // ReadInt8 reads an int8 value from the buffer.
 func (b *Buffer) ReadInt8() int8 {
 	var i int8
-	read(b.b, &i)
+	if b.bw != nil {
+		readInt8(b.bw, &i)
+		return i
+	}
+
+	readBuffInt8(b.b, &i)
 	return i
 }
 
 // ReadInt16 reads an int16 value from the buffer.
 func (b *Buffer) ReadInt16() int16 {
 	var i int16
-	read(b.b, &i)
+	if b.bw != nil {
+		readInt16(b.bw, &i)
+		return i
+	}
+
+	readBuffInt16(b.b, &i)
 	return i
 }
 
 // ReadInt32 reads an int32 value from the buffer.
 func (b *Buffer) ReadInt32() int32 {
 	var i int32
-	read(b.b, &i)
+	if b.bw != nil {
+		readInt32(b.bw, &i)
+		return i
+	}
+
+	readBuffInt32(b.b, &i)
 	return i
 }
 
 // ReadInt64 reads an int64 value from the buffer.
 func (b *Buffer) ReadInt64() int64 {
 	var i int64
-	read(b.b, &i)
+	if b.bw != nil {
+		readInt64(b.bw, &i)
+		return i
+	}
+
+	readBuffInt64(b.b, &i)
 	return i
 }
 
 // ReadUInt reads a uint value from the buffer.
 func (b *Buffer) ReadUInt() uint {
 	var i uint
-	read(b.b, &i)
+	if b.bw != nil {
+		readUint(b.bw, &i)
+		return i
+	}
+
+	readBuffUint(b.b, &i)
 	return i
 }
 
 // ReadUInt8 reads a uint8 value from the buffer.
 func (b *Buffer) ReadUInt8() uint8 {
 	var i uint8
-	read(b.b, &i)
+	if b.bw != nil {
+		readUint8(b.bw, &i)
+		return i
+	}
+
+	readBuffUint8(b.b, &i)
 	return i
 }
 
 // ReadUInt16 reads a uint16 value from the buffer.
 func (b *Buffer) ReadUInt16() uint16 {
 	var i uint16
-	read(b.b, &i)
+	if b.bw != nil {
+		readUint16(b.bw, &i)
+		return i
+	}
+
+	readBuffUint16(b.b, &i)
 	return i
 }
 
 // ReadUInt32 reads a uint32 value from the buffer.
 func (b *Buffer) ReadUInt32() uint32 {
 	var i uint32
-	read(b.b, &i)
+	if b.bw != nil {
+		readUint32(b.bw, &i)
+		return i
+	}
+
+	readBuffUint32(b.b, &i)
 	return i
 }
 
 // ReadUInt64 reads a uint64 value from the buffer.
 func (b *Buffer) ReadUInt64() uint64 {
 	var i uint64
-	read(b.b, &i)
+	if b.bw != nil {
+		readUint64(b.bw, &i)
+		return i
+	}
+
+	readBuffUint64(b.b, &i)
 	return i
 }
 
 // ReadFloat32 reads a float32 value from the buffer.
 func (b *Buffer) ReadFloat32() float32 {
 	var i float32
-	read(b.b, &i)
+	if b.bw != nil {
+		readFloat32(b.bw, &i)
+		return i
+	}
+
+	readBuffFloat32(b.b, &i)
 	return i
 }
 
 // ReadFloat64 reads a float64 value from the buffer.
 func (b *Buffer) ReadFloat64() float64 {
 	var i float64
-	read(b.b, &i)
+	if b.bw != nil {
+		readFloat64(b.bw, &i)
+		return i
+	}
+
+	readBuffFloat64(b.b, &i)
 	return i
 }
 
@@ -222,70 +344,45 @@ func (b *Buffer) ReadFloat64() float64 {
 // then uses the length to extract the exact length []byte representing the string.
 func (b *Buffer) ReadString() string {
 	var l uint16
-	read(b.b, &l)
-	return bytesToString(b.b.Next(int(l)))
+	if b.bw != nil {
+		readUint16(b.bw, &l)
+		return bytesToString(b.bw.Next(int(l)))
+	}
+
+	readBuffUint16(b.b, &l)
+
+	bytes := bytePool.Get(int(l))
+	defer bytePool.Put(bytes)
+
+	_, err := readFull(b.b, bytes)
+	if err != nil {
+		return ""
+	}
+
+	return bytesToString(bytes)
 }
 
 // ReadBytes reads the specified length from the buffer and returns the byte slice.
 func (b *Buffer) ReadBytes(length int) []byte {
-	return b.b.Next(length)
-}
+	if b.bw != nil {
+		return b.bw.Next(length)
+	}
 
-// Bytes returns the unread portion of the underlying buffer storage.
-func (b *Buffer) Bytes() []byte {
-	return b.b.Bytes()
-}
-
-// Read reads structured binary data from r into data.
-func read(r *bytes.Buffer, data interface{}) error {
-	order := binary.LittleEndian
-
-	var b [8]byte
-	if n := intDataSize(data); n != 0 {
-		bs := b[:n]
-
-		if _, err := readFull(r, bs); err != nil {
-			return err
-		}
-
-		switch data := data.(type) {
-		case *bool:
-			*data = bs[0] != 0
-		case *int8:
-			*data = int8(bs[0])
-		case *uint8:
-			*data = bs[0]
-		case *int16:
-			*data = int16(order.Uint16(bs))
-		case *uint16:
-			*data = order.Uint16(bs)
-		case *int32:
-			*data = int32(order.Uint32(bs))
-		case *uint32:
-			*data = order.Uint32(bs)
-		case *int64:
-			*data = int64(order.Uint64(bs))
-		case *uint64:
-			*data = order.Uint64(bs)
-		case *float32:
-			*data = math.Float32frombits(order.Uint32(bs))
-		case *float64:
-			*data = math.Float64frombits(order.Uint64(bs))
-		default:
-			n = 0 // fast path doesn't apply
-		}
-
-		if n != 0 {
-			return nil
-		}
+	bytes := bytePool.Get(length)
+	defer bytePool.Put(bytes)
+
+	_, err := readFull(b.b, bytes)
+	if err != nil {
+		return bytes
 	}
 
-	return NonPrimitiveTypeError
+	return bytes
 }
 
-// read full is a bytes.Buffer specific implementation of ioutil.ReadFull() which
+// read full is a bufio.Reader specific implementation of io.ReadFull() which
 // avoids escaping our stack allocated scratch bytes
-func readFull(r *bytes.Buffer, buf []byte) (n int, err error) {
+func readFull(r *bufio.Reader, buf []byte) (n int, err error) {
+
 	min := len(buf)
 	for n < min && err == nil {
 		var nn int
@@ -300,96 +397,6 @@ func readFull(r *bytes.Buffer, buf []byte) (n int, err error) {
 	return
 }
 
-// Write writes the binary representation of data into w.
-func write(w *bytes.Buffer, data interface{}) error {
-	order := binary.LittleEndian
-
-	var b [8]byte
-	if n := intDataSize(data); n != 0 {
-		bs := b[:n]
-
-		switch v := data.(type) {
-		case *bool:
-			if *v {
-				bs[0] = 1
-			} else {
-				bs[0] = 0
-			}
-		case bool:
-			if v {
-				bs[0] = 1
-			} else {
-				bs[0] = 0
-			}
-		case *int8:
-			bs[0] = byte(*v)
-		case int8:
-			bs[0] = byte(v)
-		case *uint8:
-			bs[0] = *v
-		case uint8:
-			bs[0] = v
-		case *int16:
-			order.PutUint16(bs, uint16(*v))
-		case int16:
-			order.PutUint16(bs, uint16(v))
-		case *uint16:
-			order.PutUint16(bs, *v)
-		case uint16:
-			order.PutUint16(bs, v)
-		case *int32:
-			order.PutUint32(bs, uint32(*v))
-		case int32:
-			order.PutUint32(bs, uint32(v))
-		case *uint32:
-			order.PutUint32(bs, *v)
-		case uint32:
-			order.PutUint32(bs, v)
-		case *int64:
-			order.PutUint64(bs, uint64(*v))
-		case int64:
-			order.PutUint64(bs, uint64(v))
-		case *uint64:
-			order.PutUint64(bs, *v)
-		case uint64:
-			order.PutUint64(bs, v)
-		case *float32:
-			order.PutUint32(bs, math.Float32bits(*v))
-		case float32:
-			order.PutUint32(bs, math.Float32bits(v))
-		case *float64:
-			order.PutUint64(bs, math.Float64bits(*v))
-		case float64:
-			order.PutUint64(bs, math.Float64bits(v))
-		}
-
-		_, err := w.Write(bs)
-		return err
-	}
-
-	return NonPrimitiveTypeError
-}
-
-// intDataSize returns the size of the data required to represent the data when encoded.
-// It returns zero if the type cannot be implemented by the fast path in Read or Write.
-func intDataSize(data interface{}) int {
-	switch data.(type) {
-	case bool, int8, uint8, *bool, *int8, *uint8:
-		return 1
-	case int16, uint16, *int16, *uint16:
-		return 2
-	case int32, uint32, *int32, *uint32:
-		return 4
-	case int64, uint64, *int64, *uint64:
-		return 8
-	case float32, *float32:
-		return 4
-	case float64, *float64:
-		return 8
-	}
-	return 0
-}
-
 // Conversion from byte slice to string
 func bytesToString(b []byte) string {
 	// This code will take the passed byte slice and cast it in-place into a string. By doing

+ 458 - 0
core/pkg/util/bufferhelper.go

@@ -0,0 +1,458 @@
+package util
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/binary"
+	"math"
+)
+
+func readBool(r *bytes.Buffer, data *bool) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = b != 0
+	return nil
+}
+
+func readInt8(r *bytes.Buffer, data *int8) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = int8(b)
+	return nil
+}
+
+func readUint8(r *bytes.Buffer, data *uint8) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = uint8(b)
+	return nil
+}
+
+func readInt16(r *bytes.Buffer, data *int16) error {
+	order := binary.LittleEndian
+	var b [2]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int16(order.Uint16(bs))
+	return nil
+}
+
+func readUint16(r *bytes.Buffer, data *uint16) error {
+	order := binary.LittleEndian
+	var b [2]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint16(bs)
+	return nil
+}
+
+func readInt(r *bytes.Buffer, data *int) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int(order.Uint32(bs))
+	return nil
+}
+
+func readInt32(r *bytes.Buffer, data *int32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int32(order.Uint32(bs))
+	return nil
+}
+
+func readUint(r *bytes.Buffer, data *uint) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = uint(order.Uint32(bs))
+	return nil
+}
+
+func readUint32(r *bytes.Buffer, data *uint32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint32(bs)
+	return nil
+}
+
+func readInt64(r *bytes.Buffer, data *int64) error {
+	order := binary.LittleEndian
+	var b [8]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int64(order.Uint64(bs))
+	return nil
+}
+
+func readUint64(r *bytes.Buffer, data *uint64) error {
+	order := binary.LittleEndian
+	var b [8]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint64(bs)
+	return nil
+}
+
+func readFloat32(r *bytes.Buffer, data *float32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = math.Float32frombits(order.Uint32(bs))
+	return nil
+}
+
+func readFloat64(r *bytes.Buffer, data *float64) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = math.Float64frombits(order.Uint64(bs))
+	return nil
+}
+
+func readBuffBool(r *bufio.Reader, data *bool) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = b != 0
+	return nil
+}
+
+func readBuffInt8(r *bufio.Reader, data *int8) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = int8(b)
+	return nil
+}
+
+func readBuffUint8(r *bufio.Reader, data *uint8) error {
+	b, err := r.ReadByte()
+	if err != nil {
+		return err
+	}
+
+	*data = uint8(b)
+	return nil
+}
+
+func readBuffInt16(r *bufio.Reader, data *int16) error {
+	order := binary.LittleEndian
+	var b [2]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int16(order.Uint16(bs))
+	return nil
+}
+
+func readBuffUint16(r *bufio.Reader, data *uint16) error {
+	order := binary.LittleEndian
+	var b [2]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint16(bs)
+	return nil
+}
+
+func readBuffInt(r *bufio.Reader, data *int) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int(order.Uint32(bs))
+	return nil
+}
+
+func readBuffInt32(r *bufio.Reader, data *int32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int32(order.Uint32(bs))
+	return nil
+}
+
+func readBuffUint(r *bufio.Reader, data *uint) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = uint(order.Uint32(bs))
+	return nil
+}
+
+func readBuffUint32(r *bufio.Reader, data *uint32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint32(bs)
+	return nil
+}
+
+func readBuffInt64(r *bufio.Reader, data *int64) error {
+	order := binary.LittleEndian
+	var b [8]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = int64(order.Uint64(bs))
+	return nil
+}
+
+func readBuffUint64(r *bufio.Reader, data *uint64) error {
+	order := binary.LittleEndian
+	var b [8]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = order.Uint64(bs)
+	return nil
+}
+
+func readBuffFloat32(r *bufio.Reader, data *float32) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = math.Float32frombits(order.Uint32(bs))
+	return nil
+}
+
+func readBuffFloat64(r *bufio.Reader, data *float64) error {
+	order := binary.LittleEndian
+	var b [4]byte
+
+	bs := b[:]
+	_, err := r.Read(bs)
+	if err != nil {
+		return err
+	}
+
+	*data = math.Float64frombits(order.Uint64(bs))
+	return nil
+}
+
+func writeBool(w *bytes.Buffer, data bool) error {
+	if data {
+		w.WriteByte(1)
+		return nil
+	}
+
+	w.WriteByte(0)
+	return nil
+}
+
+func writeInt8(w *bytes.Buffer, data int8) error {
+	w.WriteByte(byte(data))
+	return nil
+}
+
+func writeUint8(w *bytes.Buffer, data uint8) error {
+	w.WriteByte(byte(data))
+	return nil
+}
+
+func writeInt16(w *bytes.Buffer, data int16) error {
+	var b [2]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint16(bs, uint16(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeUint16(w *bytes.Buffer, data uint16) error {
+	var b [2]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint16(bs, data)
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeInt32(w *bytes.Buffer, data int32) error {
+	var b [4]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint32(bs, uint32(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeUint32(w *bytes.Buffer, data uint32) error {
+	var b [4]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint32(bs, data)
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeInt(w *bytes.Buffer, data int) error {
+	var b [4]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint32(bs, uint32(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeUint(w *bytes.Buffer, data uint) error {
+	var b [4]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint32(bs, uint32(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeInt64(w *bytes.Buffer, data int64) error {
+	var b [8]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint64(bs, uint64(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeUint64(w *bytes.Buffer, data uint64) error {
+	var b [8]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint64(bs, data)
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeFloat32(w *bytes.Buffer, data float32) error {
+	var b [4]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint32(bs, math.Float32bits(data))
+	_, err := w.Write(bs)
+	return err
+}
+
+func writeFloat64(w *bytes.Buffer, data float64) error {
+	var b [8]byte
+	bs := b[:]
+
+	binary.LittleEndian.PutUint64(bs, math.Float64bits(data))
+	_, err := w.Write(bs)
+	return err
+}

+ 69 - 0
core/pkg/util/bufferpool.go

@@ -0,0 +1,69 @@
+package util
+
+import (
+	"math"
+	"math/bits"
+	"sync"
+)
+
+type bufferPool struct {
+	pools [32]sync.Pool
+}
+
+func newBufferPool() *bufferPool {
+	bp := new(bufferPool)
+
+	for i := 0; i < 32; i++ {
+		length := 1 << i
+		bp.pools[i].New = func() any {
+			return make([]byte, length)
+		}
+	}
+	return bp
+}
+
+// index on the min number of bits required to store the byte data up to 32 bits.
+func nextIndex(length int) int {
+	return bits.Len32(uint32(length))
+}
+
+// the previous index for a provided length
+func prevIndex(length int) int {
+	next := nextIndex(length)
+	if uint32(length) == (1 << uint32(next)) {
+		return next
+	}
+	return next - 1
+}
+
+func (bp *bufferPool) Get(length int) []byte {
+	if length <= 0 {
+		return nil
+	}
+
+	// if it's beyond our pool bounds, just allocate and return
+	if length > math.MaxInt32 {
+		return make([]byte, length)
+	}
+
+	i := nextIndex(length)
+	if entry := bp.pools[i].Get(); entry != nil {
+		bytes := entry.([]byte)
+		bytes = bytes[:length]
+		return bytes
+	}
+
+	// should never get here, as there should always be an entry
+	// coming from the pool
+	return make([]byte, 1<<i)[:length]
+}
+
+func (bp *bufferPool) Put(buf []byte) {
+	capacity := cap(buf)
+	if capacity == 0 || capacity > math.MaxInt32 {
+		return
+	}
+
+	i := prevIndex(capacity)
+	bp.pools[i].Put(buf)
+}