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)