| 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) |