// Copyright 2024 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package protolazy contains internal data structures for lazy message decoding.
package protolazyimport (piface)// IndexEntry is the structure for an index of the fields in a message of a// proto (not descending to sub-messages)typeIndexEntrystruct {FieldNumuint32// first byte of this tag/fieldStartuint32// first byte after a contiguous sequence of bytes for this tag/field, which could // include a single encoding of the field, or multiple encodings for the fieldEnduint32// True if this protobuf segment includes multiple encodings of the fieldMultipleContiguousbool}// XXX_lazyUnmarshalInfo has information about a particular lazily decoded message//// Deprecated: Do not use. This will be deleted in the near future.typeXXX_lazyUnmarshalInfostruct {// Index of fields and their positions in the protobuf for this // message. Make index be a pointer to a slice so it can be updated // atomically. The index pointer is only set once (lazily when/if // the index is first needed), and must always be SET and LOADED // ATOMICALLY.index *[]IndexEntry// The protobuf associated with this lazily decoded message. It is // only set during proto.Unmarshal(). It doesn't need to be set and // loaded atomically, since any simultaneous set (Unmarshal) and read // (during a get) would already be a race in the app code.Protobuf []byte// The flags present when Unmarshal was originally called for this particular messageunmarshalFlagspiface.UnmarshalInputFlags}// The Buffer and SetBuffer methods let v2/internal/impl interact with// XXX_lazyUnmarshalInfo via an interface, to avoid an import cycle.// Buffer returns the lazy unmarshal buffer.//// Deprecated: Do not use. This will be deleted in the near future.func ( *XXX_lazyUnmarshalInfo) () []byte {return .Protobuf}// SetBuffer sets the lazy unmarshal buffer.//// Deprecated: Do not use. This will be deleted in the near future.func ( *XXX_lazyUnmarshalInfo) ( []byte) { .Protobuf = }// SetUnmarshalFlags is called to set a copy of the original unmarshalInputFlags.// The flags should reflect how Unmarshal was called.func ( *XXX_lazyUnmarshalInfo) ( piface.UnmarshalInputFlags) { .unmarshalFlags = }// UnmarshalFlags returns the original unmarshalInputFlags.func ( *XXX_lazyUnmarshalInfo) () piface.UnmarshalInputFlags {return .unmarshalFlags}// AllowedPartial returns true if the user originally unmarshalled this message with// AllowPartial set to truefunc ( *XXX_lazyUnmarshalInfo) () bool {return (.unmarshalFlags & piface.UnmarshalCheckRequired) == 0}func ( uint32) uint32 {return >> 3}// buildIndex builds an index of the specified protobuf, return the index// array and an error.func ( []byte) ([]IndexEntry, error) { := make([]IndexEntry, 0, 16)varuint32varboolvarBufferReader = NewBufferReader()for !.Done() {varuint32varerrorvar = .Pos// INLINED: tag, err = r.DecodeVarint32() { := .Pos := .Bufif >= len() {returnnil, errOutOfBounds } elseif [] < 0x80 { .Pos++ = uint32([]) } elseif .Remaining() < 5 {varuint64 , = .DecodeVarintSlow() = uint32() } else {varuint32// we already checked the first byte = uint32([]) & 127 ++ = uint32([]) ++ |= ( & 127) << 7if < 128 {goto } = uint32([]) ++ |= ( & 127) << 14if < 128 {goto } = uint32([]) ++ |= ( & 127) << 21if < 128 {goto } = uint32([]) ++ |= ( & 127) << 28if < 128 {goto }returnnil, errOutOfBounds : .Pos = } }// DONE: tag, err = r.DecodeVarint32() := protoFieldNumber()if < { = true }// Skip the current value -- will skip over an entire group as well. // INLINED: err = r.SkipValue(tag) := & 0x7switchprotowire.Type() {caseprotowire.VarintType:// INLINED: err = r.SkipVarint() := .Posiflen(.Buf)- < 10 {// Use DecodeVarintSlow() to skip while // checking for buffer overflow, but ignore result _, = .DecodeVarintSlow()goto }if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto } ++if .Buf[] < 0x80 {goto }returnnil, errOverflow : .Pos = + 1// DONE: err = r.SkipVarint()caseprotowire.Fixed64Type: = .SkipFixed64()caseprotowire.BytesType:varuint32 , = .DecodeVarint32()if == nil { = .Skip(int()) }caseprotowire.StartGroupType: = .SkipGroup()caseprotowire.Fixed32Type: = .SkipFixed32()default: = fmt.Errorf("Unexpected wire type (%d)", ) }// DONE: err = r.SkipValue(tag) :if != nil {returnnil, }if != { = append(, IndexEntry{FieldNum: ,Start: uint32(),End: uint32(.Pos)}, ) } else { [len()-1].End = uint32(.Pos) [len()-1].MultipleContiguous = true } = }if {sort.Slice(, func(, int) bool {return [].FieldNum < [].FieldNum || ([].FieldNum == [].FieldNum && [].Start < [].Start) }) }return , nil}func ( *XXX_lazyUnmarshalInfo) ( uint32) ( int) { , , , , := .FindFieldInProto()if != nil {for , := range { += int(.End - .Start) }return }if ! {return0 }returnint( - )}func ( *XXX_lazyUnmarshalInfo) ( []byte, uint32) ([]byte, bool) { , , , , := .FindFieldInProto()if != nil {for , := range { = append(, .Protobuf[.Start:.End]...) }return , true }if ! {returnnil, false } = append(, .Protobuf[:]...)return , true}func ( *XXX_lazyUnmarshalInfo) ( []IndexEntry) {atomicStoreIndex(&.index, &)}// FindFieldInProto looks for field fieldNum in lazyUnmarshalInfo information// (including protobuf), returns startOffset/endOffset/found.func ( *XXX_lazyUnmarshalInfo) ( uint32) (, uint32, , bool, []IndexEntry) {if .Protobuf == nil {// There is no backing protobuf for this message -- it was made from a builderreturn0, 0, false, false, nil } := atomicLoadIndex(&.index)if == nil { , := buildIndex(.Protobuf)if != nil {panic(fmt.Sprintf("findFieldInfo: error building index when looking for field %d: %v", , )) }// lazy.index is a pointer to the slice returned by BuildIndex = &atomicStoreIndex(&.index, ) }returnlookupField(, )}// lookupField returns the offset at which the indicated field starts using// the index, offset immediately after field ends (including all instances of// a repeated field), and bools indicating if field was found and if there// are multiple encodings of the field in the byte range.//// To hande the uncommon case where there are repeated encodings for the same// field which are not consecutive in the protobuf (so we need to returns// multiple start/end offsets), we also return a slice multipleEntries. If// multipleEntries is non-nil, then multiple entries were found, and the// values in the slice should be used, rather than start/end/found.func ( *[]IndexEntry, uint32) (, uint32, bool, bool, []IndexEntry) {// The pointer indexp to the index was already loaded atomically. // The slice is uniquely associated with the pointer, so it doesn't // need to be loaded atomically. := *for , := range {if == .FieldNum {if < len()-1 && .FieldNum == [+1].FieldNum {// Handle the uncommon case where there are // repeated entries for the same field which // are not contiguous in the protobuf. := make([]IndexEntry, 1, 2) [0] = IndexEntry{, .Start, .End, .MultipleContiguous} ++for < len() && [].FieldNum == { = append(, IndexEntry{, [].Start, [].End, [].MultipleContiguous}) ++ }return0, 0, false, false, }return .Start, .End, true, .MultipleContiguous, nil }if < .FieldNum {return0, 0, false, false, nil } }return0, 0, false, false, nil}
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)