| 
									
										
										
										
											2025-01-14 13:10:39 +00:00
										 |  |  | // 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 impl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/bits" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/encoding/protowire" | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/internal/errors" | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/internal/protolazy" | 
					
						
							|  |  |  | 	"google.golang.org/protobuf/reflect/protoreflect" | 
					
						
							|  |  |  | 	preg "google.golang.org/protobuf/reflect/protoregistry" | 
					
						
							|  |  |  | 	piface "google.golang.org/protobuf/runtime/protoiface" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var enableLazy int32 = func() int32 { | 
					
						
							|  |  |  | 	if os.Getenv("GOPROTODEBUG") == "nolazy" { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1 | 
					
						
							|  |  |  | }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // EnableLazyUnmarshal enables lazy unmarshaling. | 
					
						
							|  |  |  | func EnableLazyUnmarshal(enable bool) { | 
					
						
							|  |  |  | 	if enable { | 
					
						
							|  |  |  | 		atomic.StoreInt32(&enableLazy, 1) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	atomic.StoreInt32(&enableLazy, 0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LazyEnabled reports whether lazy unmarshalling is currently enabled. | 
					
						
							|  |  |  | func LazyEnabled() bool { | 
					
						
							|  |  |  | 	return atomic.LoadInt32(&enableLazy) != 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UnmarshalField unmarshals a field in a message. | 
					
						
							|  |  |  | func UnmarshalField(m interface{}, num protowire.Number) { | 
					
						
							|  |  |  | 	switch m := m.(type) { | 
					
						
							|  |  |  | 	case *messageState: | 
					
						
							|  |  |  | 		m.messageInfo().lazyUnmarshal(m.pointer(), num) | 
					
						
							|  |  |  | 	case *messageReflectWrapper: | 
					
						
							|  |  |  | 		m.messageInfo().lazyUnmarshal(m.pointer(), num) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("unsupported wrapper type %T", m)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) lazyUnmarshal(p pointer, num protoreflect.FieldNumber) { | 
					
						
							|  |  |  | 	var f *coderFieldInfo | 
					
						
							|  |  |  | 	if int(num) < len(mi.denseCoderFields) { | 
					
						
							|  |  |  | 		f = mi.denseCoderFields[num] | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		f = mi.coderFields[num] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if f == nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("lazyUnmarshal: field info for %v.%v", mi.Desc.FullName(), num)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lazy := *p.Apply(mi.lazyOffset).LazyInfoPtr() | 
					
						
							|  |  |  | 	start, end, found, _, multipleEntries := lazy.FindFieldInProto(uint32(num)) | 
					
						
							|  |  |  | 	if !found && multipleEntries == nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("lazyUnmarshal: can't find field data for %v.%v", mi.Desc.FullName(), num)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// The actual pointer in the message can not be set until the whole struct is filled in, otherwise we will have races. | 
					
						
							|  |  |  | 	// Create another pointer and set it atomically, if we won the race and the pointer in the original message is still nil. | 
					
						
							|  |  |  | 	fp := pointerOfValue(reflect.New(f.ft)) | 
					
						
							|  |  |  | 	if multipleEntries != nil { | 
					
						
							|  |  |  | 		for _, entry := range multipleEntries { | 
					
						
							|  |  |  | 			mi.unmarshalField(lazy.Buffer()[entry.Start:entry.End], fp, f, lazy, lazy.UnmarshalFlags()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		mi.unmarshalField(lazy.Buffer()[start:end], fp, f, lazy, lazy.UnmarshalFlags()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	p.Apply(f.offset).AtomicSetPointerIfNil(fp.Elem()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) unmarshalField(b []byte, p pointer, f *coderFieldInfo, lazyInfo *protolazy.XXX_lazyUnmarshalInfo, flags piface.UnmarshalInputFlags) error { | 
					
						
							|  |  |  | 	opts := lazyUnmarshalOptions | 
					
						
							|  |  |  | 	opts.flags |= flags | 
					
						
							|  |  |  | 	for len(b) > 0 { | 
					
						
							|  |  |  | 		// Parse the tag (field number and wire type). | 
					
						
							|  |  |  | 		var tag uint64 | 
					
						
							|  |  |  | 		if b[0] < 0x80 { | 
					
						
							|  |  |  | 			tag = uint64(b[0]) | 
					
						
							|  |  |  | 			b = b[1:] | 
					
						
							|  |  |  | 		} else if len(b) >= 2 && b[1] < 128 { | 
					
						
							|  |  |  | 			tag = uint64(b[0]&0x7f) + uint64(b[1])<<7 | 
					
						
							|  |  |  | 			b = b[2:] | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var n int | 
					
						
							|  |  |  | 			tag, n = protowire.ConsumeVarint(b) | 
					
						
							|  |  |  | 			if n < 0 { | 
					
						
							|  |  |  | 				return errors.New("invalid wire data") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			b = b[n:] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var num protowire.Number | 
					
						
							|  |  |  | 		if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) { | 
					
						
							|  |  |  | 			return errors.New("invalid wire data") | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			num = protowire.Number(n) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		wtyp := protowire.Type(tag & 7) | 
					
						
							|  |  |  | 		if num == f.num { | 
					
						
							|  |  |  | 			o, err := f.funcs.unmarshal(b, p, wtyp, f, opts) | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				b = b[o.n:] | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err != errUnknown { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		n := protowire.ConsumeFieldValue(num, wtyp, b) | 
					
						
							|  |  |  | 		if n < 0 { | 
					
						
							|  |  |  | 			return errors.New("invalid wire data") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (mi *MessageInfo) skipField(b []byte, f *coderFieldInfo, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, _ ValidationStatus) { | 
					
						
							|  |  |  | 	fmi := f.validation.mi | 
					
						
							|  |  |  | 	if fmi == nil { | 
					
						
							|  |  |  | 		fd := mi.Desc.Fields().ByNumber(f.num) | 
					
						
							| 
									
										
										
										
											2025-03-10 09:23:45 +00:00
										 |  |  | 		if fd == nil { | 
					
						
							| 
									
										
										
										
											2025-01-14 13:10:39 +00:00
										 |  |  | 			return out, ValidationUnknown | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		messageName := fd.Message().FullName() | 
					
						
							|  |  |  | 		messageType, err := preg.GlobalTypes.FindMessageByName(messageName) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return out, ValidationUnknown | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var ok bool | 
					
						
							|  |  |  | 		fmi, ok = messageType.(*MessageInfo) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return out, ValidationUnknown | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmi.init() | 
					
						
							|  |  |  | 	switch f.validation.typ { | 
					
						
							|  |  |  | 	case validationTypeMessage: | 
					
						
							|  |  |  | 		if wtyp != protowire.BytesType { | 
					
						
							|  |  |  | 			return out, ValidationWrongWireType | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		v, n := protowire.ConsumeBytes(b) | 
					
						
							|  |  |  | 		if n < 0 { | 
					
						
							|  |  |  | 			return out, ValidationInvalid | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		out, st := fmi.validate(v, 0, opts) | 
					
						
							|  |  |  | 		out.n = n | 
					
						
							|  |  |  | 		return out, st | 
					
						
							|  |  |  | 	case validationTypeGroup: | 
					
						
							|  |  |  | 		if wtyp != protowire.StartGroupType { | 
					
						
							|  |  |  | 			return out, ValidationWrongWireType | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		out, st := fmi.validate(b, f.num, opts) | 
					
						
							|  |  |  | 		return out, st | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return out, ValidationUnknown | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // unmarshalPointerLazy is similar to unmarshalPointerEager, but it | 
					
						
							|  |  |  | // specifically handles lazy unmarshalling.  it expects lazyOffset and | 
					
						
							|  |  |  | // presenceOffset to both be valid. | 
					
						
							|  |  |  | func (mi *MessageInfo) unmarshalPointerLazy(b []byte, p pointer, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) { | 
					
						
							|  |  |  | 	initialized := true | 
					
						
							|  |  |  | 	var requiredMask uint64 | 
					
						
							|  |  |  | 	var lazy **protolazy.XXX_lazyUnmarshalInfo | 
					
						
							|  |  |  | 	var presence presence | 
					
						
							|  |  |  | 	var lazyIndex []protolazy.IndexEntry | 
					
						
							|  |  |  | 	var lastNum protowire.Number | 
					
						
							|  |  |  | 	outOfOrder := false | 
					
						
							|  |  |  | 	lazyDecode := false | 
					
						
							|  |  |  | 	presence = p.Apply(mi.presenceOffset).PresenceInfo() | 
					
						
							|  |  |  | 	lazy = p.Apply(mi.lazyOffset).LazyInfoPtr() | 
					
						
							|  |  |  | 	if !presence.AnyPresent(mi.presenceSize) { | 
					
						
							|  |  |  | 		if opts.CanBeLazy() { | 
					
						
							|  |  |  | 			// If the message contains existing data, we need to merge into it. | 
					
						
							|  |  |  | 			// Lazy unmarshaling doesn't merge, so only enable it when the | 
					
						
							|  |  |  | 			// message is empty (has no presence bitmap). | 
					
						
							|  |  |  | 			lazyDecode = true | 
					
						
							|  |  |  | 			if *lazy == nil { | 
					
						
							|  |  |  | 				*lazy = &protolazy.XXX_lazyUnmarshalInfo{} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			(*lazy).SetUnmarshalFlags(opts.flags) | 
					
						
							|  |  |  | 			if !opts.AliasBuffer() { | 
					
						
							|  |  |  | 				// Make a copy of the buffer for lazy unmarshaling. | 
					
						
							|  |  |  | 				// Set the AliasBuffer flag so recursive unmarshal | 
					
						
							|  |  |  | 				// operations reuse the copy. | 
					
						
							|  |  |  | 				b = append([]byte{}, b...) | 
					
						
							|  |  |  | 				opts.flags |= piface.UnmarshalAliasBuffer | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			(*lazy).SetBuffer(b) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Track special handling of lazy fields. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// In the common case, all fields are lazyValidateOnly (and lazyFields remains nil). | 
					
						
							|  |  |  | 	// In the event that validation for a field fails, this map tracks handling of the field. | 
					
						
							|  |  |  | 	type lazyAction uint8 | 
					
						
							|  |  |  | 	const ( | 
					
						
							|  |  |  | 		lazyValidateOnly   lazyAction = iota // validate the field only | 
					
						
							|  |  |  | 		lazyUnmarshalNow                     // eagerly unmarshal the field | 
					
						
							|  |  |  | 		lazyUnmarshalLater                   // unmarshal the field after the message is fully processed | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	var lazyFields map[*coderFieldInfo]lazyAction | 
					
						
							|  |  |  | 	var exts *map[int32]ExtensionField | 
					
						
							|  |  |  | 	start := len(b) | 
					
						
							|  |  |  | 	pos := 0 | 
					
						
							|  |  |  | 	for len(b) > 0 { | 
					
						
							|  |  |  | 		// Parse the tag (field number and wire type). | 
					
						
							|  |  |  | 		var tag uint64 | 
					
						
							|  |  |  | 		if b[0] < 0x80 { | 
					
						
							|  |  |  | 			tag = uint64(b[0]) | 
					
						
							|  |  |  | 			b = b[1:] | 
					
						
							|  |  |  | 		} else if len(b) >= 2 && b[1] < 128 { | 
					
						
							|  |  |  | 			tag = uint64(b[0]&0x7f) + uint64(b[1])<<7 | 
					
						
							|  |  |  | 			b = b[2:] | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var n int | 
					
						
							|  |  |  | 			tag, n = protowire.ConsumeVarint(b) | 
					
						
							|  |  |  | 			if n < 0 { | 
					
						
							|  |  |  | 				return out, errDecode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			b = b[n:] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var num protowire.Number | 
					
						
							|  |  |  | 		if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) { | 
					
						
							|  |  |  | 			return out, errors.New("invalid field number") | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			num = protowire.Number(n) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		wtyp := protowire.Type(tag & 7) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if wtyp == protowire.EndGroupType { | 
					
						
							|  |  |  | 			if num != groupTag { | 
					
						
							|  |  |  | 				return out, errors.New("mismatching end group marker") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			groupTag = 0 | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var f *coderFieldInfo | 
					
						
							|  |  |  | 		if int(num) < len(mi.denseCoderFields) { | 
					
						
							|  |  |  | 			f = mi.denseCoderFields[num] | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			f = mi.coderFields[num] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var n int | 
					
						
							|  |  |  | 		err := errUnknown | 
					
						
							|  |  |  | 		discardUnknown := false | 
					
						
							|  |  |  | 	Field: | 
					
						
							|  |  |  | 		switch { | 
					
						
							|  |  |  | 		case f != nil: | 
					
						
							|  |  |  | 			if f.funcs.unmarshal == nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if f.isLazy && lazyDecode { | 
					
						
							|  |  |  | 				switch { | 
					
						
							|  |  |  | 				case lazyFields == nil || lazyFields[f] == lazyValidateOnly: | 
					
						
							|  |  |  | 					// Attempt to validate this field and leave it for later lazy unmarshaling. | 
					
						
							|  |  |  | 					o, valid := mi.skipField(b, f, wtyp, opts) | 
					
						
							|  |  |  | 					switch valid { | 
					
						
							|  |  |  | 					case ValidationValid: | 
					
						
							|  |  |  | 						// Skip over the valid field and continue. | 
					
						
							|  |  |  | 						err = nil | 
					
						
							|  |  |  | 						presence.SetPresentUnatomic(f.presenceIndex, mi.presenceSize) | 
					
						
							|  |  |  | 						requiredMask |= f.validation.requiredBit | 
					
						
							|  |  |  | 						if !o.initialized { | 
					
						
							|  |  |  | 							initialized = false | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						n = o.n | 
					
						
							|  |  |  | 						break Field | 
					
						
							|  |  |  | 					case ValidationInvalid: | 
					
						
							|  |  |  | 						return out, errors.New("invalid proto wire format") | 
					
						
							|  |  |  | 					case ValidationWrongWireType: | 
					
						
							|  |  |  | 						break Field | 
					
						
							|  |  |  | 					case ValidationUnknown: | 
					
						
							|  |  |  | 						if lazyFields == nil { | 
					
						
							|  |  |  | 							lazyFields = make(map[*coderFieldInfo]lazyAction) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if presence.Present(f.presenceIndex) { | 
					
						
							|  |  |  | 							// We were unable to determine if the field is valid or not, | 
					
						
							|  |  |  | 							// and we've already skipped over at least one instance of this | 
					
						
							|  |  |  | 							// field. Clear the presence bit (so if we stop decoding early, | 
					
						
							|  |  |  | 							// we don't leave a partially-initialized field around) and flag | 
					
						
							|  |  |  | 							// the field for unmarshaling before we return. | 
					
						
							|  |  |  | 							presence.ClearPresent(f.presenceIndex) | 
					
						
							|  |  |  | 							lazyFields[f] = lazyUnmarshalLater | 
					
						
							|  |  |  | 							discardUnknown = true | 
					
						
							|  |  |  | 							break Field | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							// We were unable to determine if the field is valid or not, | 
					
						
							|  |  |  | 							// but this is the first time we've seen it. Flag it as needing | 
					
						
							|  |  |  | 							// eager unmarshaling and fall through to the eager unmarshal case below. | 
					
						
							|  |  |  | 							lazyFields[f] = lazyUnmarshalNow | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				case lazyFields[f] == lazyUnmarshalLater: | 
					
						
							|  |  |  | 					// This field will be unmarshaled in a separate pass below. | 
					
						
							|  |  |  | 					// Skip over it here. | 
					
						
							|  |  |  | 					discardUnknown = true | 
					
						
							|  |  |  | 					break Field | 
					
						
							|  |  |  | 				default: | 
					
						
							|  |  |  | 					// Eagerly unmarshal the field. | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if f.isLazy && !lazyDecode && presence.Present(f.presenceIndex) { | 
					
						
							|  |  |  | 				if p.Apply(f.offset).AtomicGetPointer().IsNil() { | 
					
						
							|  |  |  | 					mi.lazyUnmarshal(p, f.num) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var o unmarshalOutput | 
					
						
							|  |  |  | 			o, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, f, opts) | 
					
						
							|  |  |  | 			n = o.n | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			requiredMask |= f.validation.requiredBit | 
					
						
							|  |  |  | 			if f.funcs.isInit != nil && !o.initialized { | 
					
						
							|  |  |  | 				initialized = false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if f.presenceIndex != noPresence { | 
					
						
							|  |  |  | 				presence.SetPresentUnatomic(f.presenceIndex, mi.presenceSize) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			// Possible extension. | 
					
						
							|  |  |  | 			if exts == nil && mi.extensionOffset.IsValid() { | 
					
						
							|  |  |  | 				exts = p.Apply(mi.extensionOffset).Extensions() | 
					
						
							|  |  |  | 				if *exts == nil { | 
					
						
							|  |  |  | 					*exts = make(map[int32]ExtensionField) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if exts == nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var o unmarshalOutput | 
					
						
							|  |  |  | 			o, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			n = o.n | 
					
						
							|  |  |  | 			if !o.initialized { | 
					
						
							|  |  |  | 				initialized = false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if err != errUnknown { | 
					
						
							|  |  |  | 				return out, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			n = protowire.ConsumeFieldValue(num, wtyp, b) | 
					
						
							|  |  |  | 			if n < 0 { | 
					
						
							|  |  |  | 				return out, errDecode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !discardUnknown && !opts.DiscardUnknown() && mi.unknownOffset.IsValid() { | 
					
						
							|  |  |  | 				u := mi.mutableUnknownBytes(p) | 
					
						
							|  |  |  | 				*u = protowire.AppendTag(*u, num, wtyp) | 
					
						
							|  |  |  | 				*u = append(*u, b[:n]...) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		b = b[n:] | 
					
						
							|  |  |  | 		end := start - len(b) | 
					
						
							|  |  |  | 		if lazyDecode && f != nil && f.isLazy { | 
					
						
							|  |  |  | 			if num != lastNum { | 
					
						
							|  |  |  | 				lazyIndex = append(lazyIndex, protolazy.IndexEntry{ | 
					
						
							|  |  |  | 					FieldNum: uint32(num), | 
					
						
							|  |  |  | 					Start:    uint32(pos), | 
					
						
							|  |  |  | 					End:      uint32(end), | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				i := len(lazyIndex) - 1 | 
					
						
							|  |  |  | 				lazyIndex[i].End = uint32(end) | 
					
						
							|  |  |  | 				lazyIndex[i].MultipleContiguous = true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if num < lastNum { | 
					
						
							|  |  |  | 			outOfOrder = true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		pos = end | 
					
						
							|  |  |  | 		lastNum = num | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if groupTag != 0 { | 
					
						
							|  |  |  | 		return out, errors.New("missing end group marker") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lazyFields != nil { | 
					
						
							|  |  |  | 		// Some fields failed validation, and now need to be unmarshaled. | 
					
						
							|  |  |  | 		for f, action := range lazyFields { | 
					
						
							|  |  |  | 			if action != lazyUnmarshalLater { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			initialized = false | 
					
						
							|  |  |  | 			if *lazy == nil { | 
					
						
							|  |  |  | 				*lazy = &protolazy.XXX_lazyUnmarshalInfo{} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err := mi.unmarshalField((*lazy).Buffer(), p.Apply(f.offset), f, *lazy, opts.flags); err != nil { | 
					
						
							|  |  |  | 				return out, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			presence.SetPresentUnatomic(f.presenceIndex, mi.presenceSize) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if lazyDecode { | 
					
						
							|  |  |  | 		if outOfOrder { | 
					
						
							|  |  |  | 			sort.Slice(lazyIndex, func(i, j int) bool { | 
					
						
							|  |  |  | 				return lazyIndex[i].FieldNum < lazyIndex[j].FieldNum || | 
					
						
							|  |  |  | 					(lazyIndex[i].FieldNum == lazyIndex[j].FieldNum && | 
					
						
							|  |  |  | 						lazyIndex[i].Start < lazyIndex[j].Start) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if *lazy == nil { | 
					
						
							|  |  |  | 			*lazy = &protolazy.XXX_lazyUnmarshalInfo{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		(*lazy).SetIndex(lazyIndex) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if mi.numRequiredFields > 0 && bits.OnesCount64(requiredMask) != int(mi.numRequiredFields) { | 
					
						
							|  |  |  | 		initialized = false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if initialized { | 
					
						
							|  |  |  | 		out.initialized = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	out.n = start - len(b) | 
					
						
							|  |  |  | 	return out, nil | 
					
						
							|  |  |  | } |