Package chunkreader provides an io.Reader wrapper that minimizes IO reads and memory allocations.
package chunkreader

import (
	
)
ChunkReader is a io.Reader wrapper that minimizes IO reads and memory allocations. It allocates memory in chunks and will read as much as will fit in the current buffer in a single call regardless of how large a read is actually requested. The memory returned via Next is owned by the caller. This avoids the need for an additional copy. The downside of this approach is that a large buffer can be pinned in memory even if only a small slice is referenced. For example, an entire 4096 byte block could be pinned in memory by even a 1 byte slice. In these rare cases it would be advantageous to copy the bytes to another slice.
type ChunkReader struct {
	r io.Reader

	buf    []byte
	rp, wp int // buf read position and write position

	config Config
}
Config contains configuration parameters for ChunkReader.
type Config struct {
	MinBufLen int // Minimum buffer length
}
New creates and returns a new ChunkReader for r with default configuration.
func ( io.Reader) *ChunkReader {
	,  := NewConfig(, Config{})
	if  != nil {
		panic("default config can't be bad")
	}

	return 
}
NewConfig creates and a new ChunkReader for r configured by config.
func ( io.Reader,  Config) (*ChunkReader, error) {
By historical reasons Postgres currently has 8KB send buffer inside, so here we want to have at least the same size buffer. @see https://github.com/postgres/postgres/blob/249d64999615802752940e017ee5166e726bc7cd/src/backend/libpq/pqcomm.c#L134 @see https://www.postgresql.org/message-id/0cdc5485-cb3c-5e16-4a46-e3b2f7a41322%40ya.ru
		.MinBufLen = 8192
	}

	return &ChunkReader{
		r:      ,
		buf:    make([]byte, .MinBufLen),
		config: ,
	}, nil
}
Next returns buf filled with the next n bytes. The caller gains ownership of buf. It is not necessary to make a copy of buf. If an error occurs, buf will be nil.
n bytes already in buf
	if (.wp - .rp) >=  {
		 = .buf[.rp : .rp+]
		.rp += 
		return , 
	}
available space in buf is less than n
	if len(.buf) <  {
		.copyBufContents(.newBuf())
	}
buf is large enough, but need to shift filled area to start to make enough contiguous space
	 :=  - (.wp - .rp)
	if (len(.buf) - .wp) <  {
		 := .newBuf()
		.copyBufContents()
	}

	if  := .appendAtLeast();  != nil {
		return nil, 
	}

	 = .buf[.rp : .rp+]
	.rp += 
	return , nil
}

func ( *ChunkReader) ( int) error {
	,  := io.ReadAtLeast(.r, .buf[.wp:], )
	.wp += 
	return 
}

func ( *ChunkReader) ( int) []byte {
	if  < .config.MinBufLen {
		 = .config.MinBufLen
	}
	return make([]byte, )
}

func ( *ChunkReader) ( []byte) {
	.wp = copy(, .buf[.rp:.wp])
	.rp = 0
	.buf =