|
- package codec
-
- import (
- "fmt"
- "io"
- )
-
- // Buffer is a reader and a writer that wraps a slice of bytes and also
- // provides API for decoding and encoding the protobuf binary format.
- //
- // Its operation is similar to that of a bytes.Buffer: writing pushes
- // data to the end of the buffer while reading pops data from the head
- // of the buffer. So the same buffer can be used to both read and write.
- type Buffer struct {
- buf []byte
- index int
-
- // tmp is used when another byte slice is needed, such as when
- // serializing messages, since we need to know the length before
- // we can write the length prefix; by caching this, including
- // after it is grown by serialization operations, we reduce the
- // number of allocations needed
- tmp []byte
-
- deterministic bool
- }
-
- // NewBuffer creates a new buffer with the given slice of bytes as the
- // buffer's initial contents.
- func NewBuffer(buf []byte) *Buffer {
- return &Buffer{buf: buf}
- }
-
- // SetDeterministic sets this buffer to encode messages deterministically. This
- // is useful for tests. But the overhead is non-zero, so it should not likely be
- // used outside of tests. When true, map fields in a message must have their
- // keys sorted before serialization to ensure deterministic output. Otherwise,
- // values in a map field will be serialized in map iteration order.
- func (cb *Buffer) SetDeterministic(deterministic bool) {
- cb.deterministic = deterministic
- }
-
- // Reset resets this buffer back to empty. Any subsequent writes/encodes
- // to the buffer will allocate a new backing slice of bytes.
- func (cb *Buffer) Reset() {
- cb.buf = []byte(nil)
- cb.index = 0
- }
-
- // Bytes returns the slice of bytes remaining in the buffer. Note that
- // this does not perform a copy: if the contents of the returned slice
- // are modified, the modifications will be visible to subsequent reads
- // via the buffer.
- func (cb *Buffer) Bytes() []byte {
- return cb.buf[cb.index:]
- }
-
- // String returns the remaining bytes in the buffer as a string.
- func (cb *Buffer) String() string {
- return string(cb.Bytes())
- }
-
- // EOF returns true if there are no more bytes remaining to read.
- func (cb *Buffer) EOF() bool {
- return cb.index >= len(cb.buf)
- }
-
- // Skip attempts to skip the given number of bytes in the input. If
- // the input has fewer bytes than the given count, false is returned
- // and the buffer is unchanged. Otherwise, the given number of bytes
- // are skipped and true is returned.
- func (cb *Buffer) Skip(count int) error {
- if count < 0 {
- return fmt.Errorf("proto: bad byte length %d", count)
- }
- newIndex := cb.index + count
- if newIndex < cb.index || newIndex > len(cb.buf) {
- return io.ErrUnexpectedEOF
- }
- cb.index = newIndex
- return nil
- }
-
- // Len returns the remaining number of bytes in the buffer.
- func (cb *Buffer) Len() int {
- return len(cb.buf) - cb.index
- }
-
- // Read implements the io.Reader interface. If there are no bytes
- // remaining in the buffer, it will return 0, io.EOF. Otherwise,
- // it reads max(len(dest), cb.Len()) bytes from input and copies
- // them into dest. It returns the number of bytes copied and a nil
- // error in this case.
- func (cb *Buffer) Read(dest []byte) (int, error) {
- if cb.index == len(cb.buf) {
- return 0, io.EOF
- }
- copied := copy(dest, cb.buf[cb.index:])
- cb.index += copied
- return copied, nil
- }
-
- var _ io.Reader = (*Buffer)(nil)
-
- // Write implements the io.Writer interface. It always returns
- // len(data), nil.
- func (cb *Buffer) Write(data []byte) (int, error) {
- cb.buf = append(cb.buf, data...)
- return len(data), nil
- }
-
- var _ io.Writer = (*Buffer)(nil)
|