diff options
Diffstat (limited to 'vendor/github.com/jhump/protoreflect/internal/codec')
3 files changed, 611 insertions, 0 deletions
diff --git a/vendor/github.com/jhump/protoreflect/internal/codec/buffer.go b/vendor/github.com/jhump/protoreflect/internal/codec/buffer.go new file mode 100644 index 0000000..09f8849 --- /dev/null +++ b/vendor/github.com/jhump/protoreflect/internal/codec/buffer.go @@ -0,0 +1,118 @@ +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 +} + +// IsDeterministic returns whether or not this buffer is configured to encode +// messages deterministically. +func (cb *Buffer) IsDeterministic() bool { + return cb.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, io.ErrUnexpectedEOF +// is returned and the buffer is unchanged. Otherwise, the given number +// of bytes are skipped and nil 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) diff --git a/vendor/github.com/jhump/protoreflect/internal/codec/decode.go b/vendor/github.com/jhump/protoreflect/internal/codec/decode.go new file mode 100644 index 0000000..a25f680 --- /dev/null +++ b/vendor/github.com/jhump/protoreflect/internal/codec/decode.go @@ -0,0 +1,346 @@ +package codec + +import ( + "errors" + "fmt" + "io" + "math" + + "github.com/golang/protobuf/proto" +) + +// ErrOverflow is returned when an integer is too large to be represented. +var ErrOverflow = errors.New("proto: integer overflow") + +// ErrBadWireType is returned when decoding a wire-type from a buffer that +// is not valid. +var ErrBadWireType = errors.New("proto: bad wiretype") + +func (cb *Buffer) decodeVarintSlow() (x uint64, err error) { + i := cb.index + l := len(cb.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := cb.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + cb.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = ErrOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (cb *Buffer) DecodeVarint() (uint64, error) { + i := cb.index + buf := cb.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + cb.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return cb.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x := uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, ErrOverflow + +done: + cb.index = i + return x, nil +} + +// DecodeTagAndWireType decodes a field tag and wire type from input. +// This reads a varint and then extracts the two fields from the varint +// value read. +func (cb *Buffer) DecodeTagAndWireType() (tag int32, wireType int8, err error) { + var v uint64 + v, err = cb.DecodeVarint() + if err != nil { + return + } + // low 7 bits is wire type + wireType = int8(v & 7) + // rest is int32 tag number + v = v >> 3 + if v > math.MaxInt32 { + err = fmt.Errorf("tag number out of range: %d", v) + return + } + tag = int32(v) + return +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (cb *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := cb.index + 8 + if i < 0 || i > len(cb.buf) { + err = io.ErrUnexpectedEOF + return + } + cb.index = i + + x = uint64(cb.buf[i-8]) + x |= uint64(cb.buf[i-7]) << 8 + x |= uint64(cb.buf[i-6]) << 16 + x |= uint64(cb.buf[i-5]) << 24 + x |= uint64(cb.buf[i-4]) << 32 + x |= uint64(cb.buf[i-3]) << 40 + x |= uint64(cb.buf[i-2]) << 48 + x |= uint64(cb.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (cb *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := cb.index + 4 + if i < 0 || i > len(cb.buf) { + err = io.ErrUnexpectedEOF + return + } + cb.index = i + + x = uint64(cb.buf[i-4]) + x |= uint64(cb.buf[i-3]) << 8 + x |= uint64(cb.buf[i-2]) << 16 + x |= uint64(cb.buf[i-1]) << 24 + return +} + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (cb *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := cb.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := cb.index + nb + if end < cb.index || end > len(cb.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + buf = cb.buf[cb.index:end] + cb.index = end + return + } + + buf = make([]byte, nb) + copy(buf, cb.buf[cb.index:]) + cb.index = end + return +} + +// ReadGroup reads the input until a "group end" tag is found +// and returns the data up to that point. Subsequent reads from +// the buffer will read data after the group end tag. If alloc +// is true, the data is copied to a new slice before being returned. +// Otherwise, the returned slice is a view into the buffer's +// underlying byte slice. +// +// This function correctly handles nested groups: if a "group start" +// tag is found, then that group's end tag will be included in the +// returned data. +func (cb *Buffer) ReadGroup(alloc bool) ([]byte, error) { + var groupEnd, dataEnd int + groupEnd, dataEnd, err := cb.findGroupEnd() + if err != nil { + return nil, err + } + var results []byte + if !alloc { + results = cb.buf[cb.index:dataEnd] + } else { + results = make([]byte, dataEnd-cb.index) + copy(results, cb.buf[cb.index:]) + } + cb.index = groupEnd + return results, nil +} + +// SkipGroup is like ReadGroup, except that it discards the +// data and just advances the buffer to point to the input +// right *after* the "group end" tag. +func (cb *Buffer) SkipGroup() error { + groupEnd, _, err := cb.findGroupEnd() + if err != nil { + return err + } + cb.index = groupEnd + return nil +} + +// SkipField attempts to skip the value of a field with the given wire +// type. When consuming a protobuf-encoded stream, it can be called immediately +// after DecodeTagAndWireType to discard the subsequent data for the field. +func (cb *Buffer) SkipField(wireType int8) error { + switch wireType { + case proto.WireFixed32: + if err := cb.Skip(4); err != nil { + return err + } + case proto.WireFixed64: + if err := cb.Skip(8); err != nil { + return err + } + case proto.WireVarint: + // skip varint by finding last byte (has high bit unset) + i := cb.index + limit := i + 10 // varint cannot be >10 bytes + for { + if i >= limit { + return ErrOverflow + } + if i >= len(cb.buf) { + return io.ErrUnexpectedEOF + } + if cb.buf[i]&0x80 == 0 { + break + } + i++ + } + // TODO: This would only overflow if buffer length was MaxInt and we + // read the last byte. This is not a real/feasible concern on 64-bit + // systems. Something to worry about for 32-bit systems? Do we care? + cb.index = i + 1 + case proto.WireBytes: + l, err := cb.DecodeVarint() + if err != nil { + return err + } + if err := cb.Skip(int(l)); err != nil { + return err + } + case proto.WireStartGroup: + if err := cb.SkipGroup(); err != nil { + return err + } + default: + return ErrBadWireType + } + return nil +} + +func (cb *Buffer) findGroupEnd() (groupEnd int, dataEnd int, err error) { + start := cb.index + defer func() { + cb.index = start + }() + for { + fieldStart := cb.index + // read a field tag + _, wireType, err := cb.DecodeTagAndWireType() + if err != nil { + return 0, 0, err + } + if wireType == proto.WireEndGroup { + return cb.index, fieldStart, nil + } + // skip past the field's data + if err := cb.SkipField(wireType); err != nil { + return 0, 0, err + } + } +} diff --git a/vendor/github.com/jhump/protoreflect/internal/codec/encode.go b/vendor/github.com/jhump/protoreflect/internal/codec/encode.go new file mode 100644 index 0000000..524f1bc --- /dev/null +++ b/vendor/github.com/jhump/protoreflect/internal/codec/encode.go @@ -0,0 +1,147 @@ +package codec + +import ( + "github.com/golang/protobuf/proto" +) + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (cb *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + cb.buf = append(cb.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + cb.buf = append(cb.buf, uint8(x)) + return nil +} + +// EncodeTagAndWireType encodes the given field tag and wire type to the +// buffer. This combines the two values and then writes them as a varint. +func (cb *Buffer) EncodeTagAndWireType(tag int32, wireType int8) error { + v := uint64((int64(tag) << 3) | int64(wireType)) + return cb.EncodeVarint(v) +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (cb *Buffer) EncodeFixed64(x uint64) error { + cb.buf = append(cb.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (cb *Buffer) EncodeFixed32(x uint64) error { + cb.buf = append(cb.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (cb *Buffer) EncodeRawBytes(b []byte) error { + if err := cb.EncodeVarint(uint64(len(b))); err != nil { + return err + } + cb.buf = append(cb.buf, b...) + return nil +} + +// EncodeMessage writes the given message to the buffer. +func (cb *Buffer) EncodeMessage(pm proto.Message) error { + bytes, err := marshalMessage(cb.buf, pm, cb.deterministic) + if err != nil { + return err + } + cb.buf = bytes + return nil +} + +// EncodeDelimitedMessage writes the given message to the buffer with a +// varint-encoded length prefix (the delimiter). +func (cb *Buffer) EncodeDelimitedMessage(pm proto.Message) error { + bytes, err := marshalMessage(cb.tmp, pm, cb.deterministic) + if err != nil { + return err + } + // save truncated buffer if it was grown (so we can re-use it and + // curtail future allocations) + if cap(bytes) > cap(cb.tmp) { + cb.tmp = bytes[:0] + } + return cb.EncodeRawBytes(bytes) +} + +func marshalMessage(b []byte, pm proto.Message, deterministic bool) ([]byte, error) { + // We try to use the most efficient way to marshal to existing slice. + + if deterministic { + // see if the message has custom deterministic methods, preferring an + // "append" method over one that must always re-allocate + madm, ok := pm.(interface { + MarshalAppendDeterministic(b []byte) ([]byte, error) + }) + if ok { + return madm.MarshalAppendDeterministic(b) + } + + mdm, ok := pm.(interface { + MarshalDeterministic() ([]byte, error) + }) + if ok { + bytes, err := mdm.MarshalDeterministic() + if err != nil { + return nil, err + } + if len(b) == 0 { + return bytes, nil + } + return append(b, bytes...), nil + } + + var buf proto.Buffer + buf.SetDeterministic(true) + if err := buf.Marshal(pm); err != nil { + return nil, err + } + bytes := buf.Bytes() + if len(b) == 0 { + return bytes, nil + } + return append(b, bytes...), nil + } + + mam, ok := pm.(interface { + // see if we can append the message, vs. having to re-allocate + MarshalAppend(b []byte) ([]byte, error) + }) + if ok { + return mam.MarshalAppend(b) + } + + // lowest common denominator + bytes, err := proto.Marshal(pm) + if err != nil { + return nil, err + } + if len(b) == 0 { + return bytes, nil + } + return append(b, bytes...), nil +} |
