github.com/jhump/protoreflect@v1.16.0/internal/codec/buffer.go (about)

     1  package codec
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  )
     7  
     8  // Buffer is a reader and a writer that wraps a slice of bytes and also
     9  // provides API for decoding and encoding the protobuf binary format.
    10  //
    11  // Its operation is similar to that of a bytes.Buffer: writing pushes
    12  // data to the end of the buffer while reading pops data from the head
    13  // of the buffer. So the same buffer can be used to both read and write.
    14  type Buffer struct {
    15  	buf   []byte
    16  	index int
    17  
    18  	// tmp is used when another byte slice is needed, such as when
    19  	// serializing messages, since we need to know the length before
    20  	// we can write the length prefix; by caching this, including
    21  	// after it is grown by serialization operations, we reduce the
    22  	// number of allocations needed
    23  	tmp []byte
    24  
    25  	deterministic bool
    26  }
    27  
    28  // NewBuffer creates a new buffer with the given slice of bytes as the
    29  // buffer's initial contents.
    30  func NewBuffer(buf []byte) *Buffer {
    31  	return &Buffer{buf: buf}
    32  }
    33  
    34  // SetDeterministic sets this buffer to encode messages deterministically. This
    35  // is useful for tests. But the overhead is non-zero, so it should not likely be
    36  // used outside of tests. When true, map fields in a message must have their
    37  // keys sorted before serialization to ensure deterministic output. Otherwise,
    38  // values in a map field will be serialized in map iteration order.
    39  func (cb *Buffer) SetDeterministic(deterministic bool) {
    40  	cb.deterministic = deterministic
    41  }
    42  
    43  // IsDeterministic returns whether or not this buffer is configured to encode
    44  // messages deterministically.
    45  func (cb *Buffer) IsDeterministic() bool {
    46  	return cb.deterministic
    47  }
    48  
    49  // Reset resets this buffer back to empty. Any subsequent writes/encodes
    50  // to the buffer will allocate a new backing slice of bytes.
    51  func (cb *Buffer) Reset() {
    52  	cb.buf = []byte(nil)
    53  	cb.index = 0
    54  }
    55  
    56  // Bytes returns the slice of bytes remaining in the buffer. Note that
    57  // this does not perform a copy: if the contents of the returned slice
    58  // are modified, the modifications will be visible to subsequent reads
    59  // via the buffer.
    60  func (cb *Buffer) Bytes() []byte {
    61  	return cb.buf[cb.index:]
    62  }
    63  
    64  // String returns the remaining bytes in the buffer as a string.
    65  func (cb *Buffer) String() string {
    66  	return string(cb.Bytes())
    67  }
    68  
    69  // EOF returns true if there are no more bytes remaining to read.
    70  func (cb *Buffer) EOF() bool {
    71  	return cb.index >= len(cb.buf)
    72  }
    73  
    74  // Skip attempts to skip the given number of bytes in the input. If
    75  // the input has fewer bytes than the given count, io.ErrUnexpectedEOF
    76  // is returned and the buffer is unchanged. Otherwise, the given number
    77  // of bytes are skipped and nil is returned.
    78  func (cb *Buffer) Skip(count int) error {
    79  	if count < 0 {
    80  		return fmt.Errorf("proto: bad byte length %d", count)
    81  	}
    82  	newIndex := cb.index + count
    83  	if newIndex < cb.index || newIndex > len(cb.buf) {
    84  		return io.ErrUnexpectedEOF
    85  	}
    86  	cb.index = newIndex
    87  	return nil
    88  }
    89  
    90  // Len returns the remaining number of bytes in the buffer.
    91  func (cb *Buffer) Len() int {
    92  	return len(cb.buf) - cb.index
    93  }
    94  
    95  // Read implements the io.Reader interface. If there are no bytes
    96  // remaining in the buffer, it will return 0, io.EOF. Otherwise,
    97  // it reads max(len(dest), cb.Len()) bytes from input and copies
    98  // them into dest. It returns the number of bytes copied and a nil
    99  // error in this case.
   100  func (cb *Buffer) Read(dest []byte) (int, error) {
   101  	if cb.index == len(cb.buf) {
   102  		return 0, io.EOF
   103  	}
   104  	copied := copy(dest, cb.buf[cb.index:])
   105  	cb.index += copied
   106  	return copied, nil
   107  }
   108  
   109  var _ io.Reader = (*Buffer)(nil)
   110  
   111  // Write implements the io.Writer interface. It always returns
   112  // len(data), nil.
   113  func (cb *Buffer) Write(data []byte) (int, error) {
   114  	cb.buf = append(cb.buf, data...)
   115  	return len(data), nil
   116  }
   117  
   118  var _ io.Writer = (*Buffer)(nil)