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)