blob: 09f8849edebb95133bb736d43c94a06747cd6f93 [file] [log] [blame]
khenaidooefff76e2021-12-15 16:51:30 -05001package codec
2
3import (
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.
14type 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.
30func 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.
39func (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.
45func (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.
51func (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.
60func (cb *Buffer) Bytes() []byte {
61 return cb.buf[cb.index:]
62}
63
64// String returns the remaining bytes in the buffer as a string.
65func (cb *Buffer) String() string {
66 return string(cb.Bytes())
67}
68
69// EOF returns true if there are no more bytes remaining to read.
70func (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.
78func (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.
91func (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.
100func (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
109var _ io.Reader = (*Buffer)(nil)
110
111// Write implements the io.Writer interface. It always returns
112// len(data), nil.
113func (cb *Buffer) Write(data []byte) (int, error) {
114 cb.buf = append(cb.buf, data...)
115 return len(data), nil
116}
117
118var _ io.Writer = (*Buffer)(nil)