2022-10-03 06:46:32 +00:00
package pool
import (
"bytes"
"io"
"sync"
)
2023-02-06 03:32:59 +00:00
// BufferFactory is a factory for creating and reusing bytes.Buffers.
// BufferFactory tries to be safer than using a sync.Pool directly by ensuring that the buffer is not returned twice.
2022-10-03 06:46:32 +00:00
type BufferFactory struct {
pool * sync . Pool
}
2023-02-06 03:32:59 +00:00
// NewBufferFactory creates a new BufferFactory that creates new buffers on demand.
2022-10-03 06:46:32 +00:00
func NewBufferFactory ( ) BufferFactory {
return BufferFactory {
pool : & sync . Pool {
New : func ( ) any { return new ( bytes . Buffer ) } ,
} ,
}
}
2023-02-06 03:32:59 +00:00
// NewSizedBufferFactory creates a new BufferFactory that creates new buffers of the given size on demand.
2023-01-19 00:13:44 +00:00
func NewSizedBufferFactory ( size int ) BufferFactory {
return BufferFactory {
pool : & sync . Pool {
New : func ( ) any { return bytes . NewBuffer ( make ( [ ] byte , size ) ) } ,
} ,
}
}
2023-02-06 03:32:59 +00:00
// Put returns the buffer to the pool. It returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( cf BufferFactory ) Put ( buf * Buffer ) error {
var err = ErrBufferReturned
buf . o . Do ( func ( ) {
_ = buf . Reset ( )
cf . pool . Put ( buf . Buffer )
buf . Buffer = nil
err = nil
} )
return err
}
2023-02-06 03:32:59 +00:00
// MustPut is the same as Put but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( cf BufferFactory ) MustPut ( buf * Buffer ) {
if err := cf . Put ( buf ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// Get returns a buffer from the pool.
2022-10-03 06:46:32 +00:00
func ( cf BufferFactory ) Get ( ) * Buffer {
return & Buffer {
cf . pool . Get ( ) . ( * bytes . Buffer ) ,
& sync . Once { } ,
}
}
2023-02-06 03:32:59 +00:00
// Buffer is a wrapper around bytes.Buffer that can only be returned to a pool once.
2022-10-03 06:46:32 +00:00
type Buffer struct {
* bytes . Buffer
o * sync . Once
}
2023-02-06 03:32:59 +00:00
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
// The slice is valid for use only until the next buffer modification (that is,
// only until the next call to a method like Read, Write, Reset, or Truncate).
// The slice aliases the buffer content at least until the next buffer modification,
// so immediate changes to the slice will affect the result of future reads.
//
// *This is from the bytes.Buffer docs.*
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Bytes ( ) [ ] byte {
if c . Buffer == nil {
return nil
}
return c . Buffer . Bytes ( )
}
2023-02-06 03:32:59 +00:00
// MustBytes is the same as Bytes but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustBytes ( ) [ ] byte {
if c . Buffer == nil {
panic ( ErrBufferReturned )
}
return c . Buffer . Bytes ( )
}
2023-02-06 03:32:59 +00:00
// String returns the contents of the unread portion of the buffer
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
//
// To build strings more efficiently, see the strings.Builder type.
//
// *This is from the bytes.Buffer docs.*
2022-10-03 06:46:32 +00:00
func ( c Buffer ) String ( ) string {
if c . Buffer == nil {
return ""
}
return c . Buffer . String ( )
}
2023-02-06 03:32:59 +00:00
// MustString is the same as String but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustString ( ) string {
if c . Buffer == nil {
panic ( ErrBufferReturned )
}
return c . Buffer . String ( )
}
2023-02-06 03:32:59 +00:00
// Reset resets the buffer to be empty,
// but it retains the underlying storage for use by future writes.
// Reset is the same as Truncate(0).
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Reset ( ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
c . Buffer . Reset ( )
return nil
}
2023-02-06 03:32:59 +00:00
// MustReset is the same as Reset but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustReset ( ) {
if err := c . Reset ( ) ; err != nil {
panic ( err )
}
c . Buffer . Reset ( )
}
2023-02-06 03:32:59 +00:00
// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns 0 if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Len ( ) int {
if c . Buffer == nil {
return 0
}
return c . Buffer . Len ( )
}
2023-02-06 03:32:59 +00:00
// MustLen is the same as Len but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustLen ( ) int {
if c . Buffer == nil {
panic ( ErrBufferReturned )
}
return c . Buffer . Len ( )
}
2023-02-06 03:32:59 +00:00
// Write appends the contents of p to the buffer, growing the buffer as
// needed. The return value n is the length of p; err is always nil. If the
// buffer becomes too large, Write will panic with ErrTooLarge.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Write ( p [ ] byte ) ( int , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . Write ( p )
}
2023-02-06 03:32:59 +00:00
// MustWrite is the same as Write but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustWrite ( p [ ] byte ) {
if _ , err := c . Write ( p ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
// buffer, returning its length and an error, which is always nil but is
// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
// if it becomes too large, WriteRune will panic with ErrTooLarge.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) WriteRune ( r rune ) ( int , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . WriteRune ( r )
}
2023-02-06 03:32:59 +00:00
// MustWriteRune is the same as WriteRune but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustWriteRune ( r rune ) {
if _ , err := c . WriteRune ( r ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
// The returned error is always nil, but is included to match bufio.Writer's
// WriteByte. If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) WriteByte ( cyte byte ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
return c . Buffer . WriteByte ( cyte )
}
2023-02-06 03:32:59 +00:00
// MustWriteByte is the same as WriteByte but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustWriteByte ( cyte byte ) {
if err := c . WriteByte ( cyte ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// WriteString appends the contents of s to the buffer, growing the buffer as
// needed. The return value n is the length of s; err is always nil. If the
// buffer becomes too large, WriteString will panic with ErrTooLarge.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) WriteString ( str string ) ( int , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . WriteString ( str )
}
2022-11-22 21:33:08 +00:00
// Grow grows the buffer's capacity, if necessary, to guarantee space for another n bytes. After Grow(n), at least n bytes can be written to the buffer without another allocation. If n is negative, Grow will panic. If the buffer can't grow it will panic with ErrTooLarge.
// If the buffer has already been returned to the pool, Grow will return ErrBufferReturned.
2023-02-06 03:32:59 +00:00
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Grow ( n int ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
c . Buffer . Grow ( n )
return nil
}
2023-02-06 03:32:59 +00:00
// Cap returns the capacity of the buffer's underlying byte slice, that is, the
// total space allocated for the buffer's data.
//
// *This is from the bytes.Buffer docs.*
// If the buffer has already been returned to the pool, Cap will return 0.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Cap ( ) int {
if c . Buffer == nil {
return 0
}
return c . Buffer . Cap ( )
}
2023-02-06 03:32:59 +00:00
// Truncate discards all but the first n unread bytes from the buffer
// but continues to use the same allocated storage.
// It panics if n is negative or greater than the length of the buffer.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Truncate ( n int ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
c . Buffer . Truncate ( n )
return nil
}
2023-02-06 03:32:59 +00:00
// MustTruncate is the same as Truncate but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustTruncate ( n int ) {
if err := c . Truncate ( n ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) ReadFrom ( r io . Reader ) ( int64 , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . ReadFrom ( r )
}
2023-02-06 03:32:59 +00:00
// MustReadFrom is the same as ReadFrom but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustReadFrom ( r io . Reader ) {
if _ , err := c . ReadFrom ( r ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// WriteTo writes data to w until the buffer is drained or an error occurs.
// The return value n is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) WriteTo ( w io . Writer ) ( int64 , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . WriteTo ( w )
}
2023-02-06 03:32:59 +00:00
// MustWriteTo is the same as WriteTo but panics if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) MustWriteTo ( w io . Writer ) {
if _ , err := c . WriteTo ( w ) ; err != nil {
panic ( err )
}
}
2023-02-06 03:32:59 +00:00
// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained. The return value n is the number of bytes read. If the
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Read ( p [ ] byte ) ( int , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . Read ( p )
}
2023-02-06 03:32:59 +00:00
// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error io.EOF.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) ReadByte ( ) ( byte , error ) {
if c . Buffer == nil {
return 0 , ErrBufferReturned
}
return c . Buffer . ReadByte ( )
}
2023-02-06 03:32:59 +00:00
// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) ReadRune ( ) ( rune , int , error ) {
if c . Buffer == nil {
return 0 , 0 , ErrBufferReturned
}
return c . Buffer . ReadRune ( )
}
2023-02-06 03:32:59 +00:00
// UnreadByte unreads the last byte returned by the most recent successful
// read operation that read at least one byte. If a write has happened since
// the last read, if the last read returned an error, or if the read read zero
// bytes, UnreadByte returns an error.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) UnreadByte ( ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
return c . Buffer . UnreadByte ( )
}
2023-02-06 03:32:59 +00:00
// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a successful ReadRune, UnreadRune returns an error. (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) UnreadRune ( ) error {
if c . Buffer == nil {
return ErrBufferReturned
}
return c . Buffer . UnreadRune ( )
}
2023-02-06 03:32:59 +00:00
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns an error if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) ReadBytes ( delim byte ) ( [ ] byte , error ) {
if c . Buffer == nil {
return nil , ErrBufferReturned
}
return c . Buffer . ReadBytes ( delim )
}
2023-02-06 03:32:59 +00:00
// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
//
// *This is from the bytes.Buffer docs.*
// This wrapper returns nil if the buffer has already been returned to the pool.
2022-10-03 06:46:32 +00:00
func ( c Buffer ) Next ( n int ) [ ] byte {
if c . Buffer == nil {
return nil
}
return c . Buffer . Next ( n )
}