github.com/hoveychen/protoreflect@v1.4.7-0.20221103114119-0b4b3385ec76/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  // Reset resets this buffer back to empty. Any subsequent writes/encodes
    44  // to the buffer will allocate a new backing slice of bytes.
    45  func (cb *Buffer) Reset() {
    46  	cb.buf = []byte(nil)
    47  	cb.index = 0
    48  }
    49  
    50  // Bytes returns the slice of bytes remaining in the buffer. Note that
    51  // this does not perform a copy: if the contents of the returned slice
    52  // are modified, the modifications will be visible to subsequent reads
    53  // via the buffer.
    54  func (cb *Buffer) Bytes() []byte {
    55  	return cb.buf[cb.index:]
    56  }
    57  
    58  // String returns the remaining bytes in the buffer as a string.
    59  func (cb *Buffer) String() string {
    60  	return string(cb.Bytes())
    61  }
    62  
    63  // EOF returns true if there are no more bytes remaining to read.
    64  func (cb *Buffer) EOF() bool {
    65  	return cb.index >= len(cb.buf)
    66  }
    67  
    68  // Skip attempts to skip the given number of bytes in the input. If
    69  // the input has fewer bytes than the given count, false is returned
    70  // and the buffer is unchanged. Otherwise, the given number of bytes
    71  // are skipped and true is returned.
    72  func (cb *Buffer) Skip(count int) error {
    73  	if count < 0 {
    74  		return fmt.Errorf("proto: bad byte length %d", count)
    75  	}
    76  	newIndex := cb.index + count
    77  	if newIndex < cb.index || newIndex > len(cb.buf) {
    78  		return io.ErrUnexpectedEOF
    79  	}
    80  	cb.index = newIndex
    81  	return nil
    82  }
    83  
    84  // Len returns the remaining number of bytes in the buffer.
    85  func (cb *Buffer) Len() int {
    86  	return len(cb.buf) - cb.index
    87  }
    88  
    89  // Read implements the io.Reader interface. If there are no bytes
    90  // remaining in the buffer, it will return 0, io.EOF. Otherwise,
    91  // it reads max(len(dest), cb.Len()) bytes from input and copies
    92  // them into dest. It returns the number of bytes copied and a nil
    93  // error in this case.
    94  func (cb *Buffer) Read(dest []byte) (int, error) {
    95  	if cb.index == len(cb.buf) {
    96  		return 0, io.EOF
    97  	}
    98  	copied := copy(dest, cb.buf[cb.index:])
    99  	cb.index += copied
   100  	return copied, nil
   101  }
   102  
   103  var _ io.Reader = (*Buffer)(nil)
   104  
   105  // Write implements the io.Writer interface. It always returns
   106  // len(data), nil.
   107  func (cb *Buffer) Write(data []byte) (int, error) {
   108  	cb.buf = append(cb.buf, data...)
   109  	return len(data), nil
   110  }
   111  
   112  var _ io.Writer = (*Buffer)(nil)