binary-decode.go
func (cdc *Codec) decodeReflectBinaryStruct(bz []byte, info *TypeInfo, rv reflect.Value, _ FieldOptions, bare bool) (n int, err error) {
	if !rv.CanAddr() {
		panic("rv not addressable")
	}
	if printLog {
		fmt.Println("(d) decodeReflectBinaryStruct")
		defer func() {
			fmt.Printf("(d) -> err: %v\n", err)
		}()
	}
	_n := 0 // nolint: ineffassign

	// NOTE: The "Struct" typ3 doesn't get read here.
	// It's already implied, either by struct-key or list-element-type-byte.

	if !bare {
		// Read byte-length prefixed byteslice.
		var buf, _n = []byte(nil), int(0)
		buf, _n, err = DecodeByteSlice(bz)
		if slide(&bz, nil, _n) && err != nil {
			return
		}
		// This is a trick for debuggability -- we slide on &n more later.
		n += UvarintSize(uint64(len(buf)))
		bz = buf
	}

	switch info.Type {

	case timeType:
		// Special case: time.Time
		var t time.Time
		t, _n, err = DecodeTime(bz)
		if slide(&bz, &n, _n) && err != nil {
			return
		}
		rv.Set(reflect.ValueOf(t))

	default:
		// Track the last seen field number.
		var lastFieldNum uint32
		// Read each field.
		for _, field := range info.Fields {
			// Get field rv and info.
			var frv = rv.Field(field.Index)
			var finfo *TypeInfo
			finfo, err = cdc.getTypeInfo_wlock(field.Type)
			if err != nil {
				return
			}

			// We're done if we've consumed all the bytes.
			if len(bz) == 0 {
				frv.Set(defaultValue(frv.Type()))
				continue
			}

			if field.UnpackedList {
				// This is a list that was encoded unpacked, e.g.
				// with repeated field entries for each list item.
				_n, err = cdc.decodeReflectBinary(bz, finfo, frv, field.FieldOptions, true)
				if slide(&bz, &n, _n) && err != nil {
					return
				}
			} else {
				// Read field key (number and type).
				var fnum, typ = uint32(0), Typ3(0x00)
				fnum, typ, _n, err = decodeFieldNumberAndTyp3(bz)
				if field.BinFieldNum < fnum {
					// Set zero field value.
					frv.Set(defaultValue(frv.Type()))
					continue
					// Do not slide, we will read it again.
				}
				if fnum <= lastFieldNum {
					err = fmt.Errorf("encountered fieldnNum: %v, but we have already seen fnum: %v\nbytes:%X",
						fnum, lastFieldNum, bz)
					return
				}
				lastFieldNum = fnum
				if slide(&bz, &n, _n) && err != nil {
					return
				}

				// Validate fnum and typ.
				// NOTE: In the future, we'll support upgradeability.
				// So in the future, this may not match,
				// so we will need to remove this sanity check.
				if field.BinFieldNum != fnum {
					err = errors.New(fmt.Sprintf("expected field # %v of %v, got %v",
						field.BinFieldNum, info.Type, fnum))
					return
				}
				typWanted := typeToTyp3(finfo.Type, field.FieldOptions)
				if typ != typWanted {
					err = errors.New(fmt.Sprintf("expected field type %v for # %v of %v, got %v",
						typWanted, fnum, info.Type, typ))
					return
				}
				// Decode field into frv.
				_n, err = cdc.decodeReflectBinary(bz, finfo, frv, field.FieldOptions, false)
				if slide(&bz, &n, _n) && err != nil {
					return
				}
			}
		}

		// Consume any remaining fields.
		var _n, fnum = 0, uint32(0)
		var typ3 Typ3
		for len(bz) > 0 {
			fnum, typ3, _n, err = decodeFieldNumberAndTyp3(bz)
			if slide(&bz, &n, _n) && err != nil {
				return
			}
			if fnum <= lastFieldNum {
				err = fmt.Errorf("encountered fieldnNum: %v, but we have already seen fnum: %v\nbytes:%X",
					fnum, lastFieldNum, bz)
				return
			}
			lastFieldNum = fnum

			_n, err = consumeAny(typ3, bz)
			if slide(&bz, &n, _n) && err != nil {
				return
			}
		}
	}
	return
}
func (cdc *Codec) decodeReflectBinaryStruct(bz []byte, info *TypeInfo, rv reflect.Value, _ FieldOptions, bare bool) (n int, err error) {
	if !rv.CanAddr() {
		panic("rv not addressable")
	}
	if printLog {
		fmt.Println("(d) decodeReflectBinaryStruct")
		defer func() {
			fmt.Printf("(d) -> err: %v\n", err)
		}()
	}
	_n := 0 // nolint: ineffassign

	// NOTE: The "Struct" typ3 doesn't get read here.
	// It's already implied, either by struct-key or list-element-type-byte.

	if !bare {
		// Read byte-length prefixed byteslice.
		var buf, _n = []byte(nil), int(0)
		buf, _n, err = DecodeByteSlice(bz)
		if slide(&bz, nil, _n) && err != nil {
			return
		}
		// This is a trick for debuggability -- we slide on &n more later.
		n += UvarintSize(uint64(len(buf)))
		bz = buf
	}

	switch info.Type {

	case timeType:
		// Special case: time.Time
		var t time.Time
		t, _n, err = DecodeTime(bz)
		if slide(&bz, &n, _n) && err != nil {
			return
		}
		rv.Set(reflect.ValueOf(t))

	default:
		// Track the last seen field number.
		var lastFieldNum uint32
		// Read each field.
		for _, field := range info.Fields {
			// Get field rv and info.
			var frv = rv.Field(field.Index)
			var finfo *TypeInfo
			finfo, err = cdc.getTypeInfo_wlock(field.Type)
			if err != nil {
				return
			}

			// We're done if we've consumed all the bytes.
			if len(bz) == 0 {
				frv.Set(defaultValue(frv.Type()))
				continue
			}

			if field.UnpackedList {
				// This is a list that was encoded unpacked, e.g.
				// with repeated field entries for each list item.
				_n, err = cdc.decodeReflectBinary(bz, finfo, frv, field.FieldOptions, true)
				if slide(&bz, &n, _n) && err != nil {
					return
				}
			} else {
				// Read field key (number and type).
				var fnum, typ = uint32(0), Typ3(0x00)
				fnum, typ, _n, err = decodeFieldNumberAndTyp3(bz)
				if field.BinFieldNum < fnum {
					// Set zero field value.
					frv.Set(defaultValue(frv.Type()))
					continue
					// Do not slide, we will read it again.
				}
				if fnum <= lastFieldNum {
					err = fmt.Errorf("encountered fieldnNum: %v, but we have already seen fnum: %v\nbytes:%X",
						fnum, lastFieldNum, bz)
					return
				}
				lastFieldNum = fnum
				if slide(&bz, &n, _n) && err != nil {
					return
				}

				// Validate fnum and typ.
				// NOTE: In the future, we'll support upgradeability.
				// So in the future, this may not match,
				// so we will need to remove this sanity check.
				if field.BinFieldNum != fnum {
					err = errors.New(fmt.Sprintf("expected field # %v of %v, got %v",
						field.BinFieldNum, info.Type, fnum))
					return
				}
				typWanted := typeToTyp3(finfo.Type, field.FieldOptions)
				if typ != typWanted {
					err = errors.New(fmt.Sprintf("expected field type %v for # %v of %v, got %v",
						typWanted, fnum, info.Type, typ))
					return
				}
				// Decode field into frv.
				_n, err = cdc.decodeReflectBinary(bz, finfo, frv, field.FieldOptions, false)
				if slide(&bz, &n, _n) && err != nil {
					return
				}
			}
		}

		// Consume any remaining fields.
		var _n, fnum = 0, uint32(0)
		var typ3 Typ3
		for len(bz) > 0 {
			fnum, typ3, _n, err = decodeFieldNumberAndTyp3(bz)
			if slide(&bz, &n, _n) && err != nil {
				return
			}
			if fnum <= lastFieldNum {
				err = fmt.Errorf("encountered fieldnNum: %v, but we have already seen fnum: %v\nbytes:%X",
					fnum, lastFieldNum, bz)
				return
			}
			lastFieldNum = fnum

			_n, err = consumeAny(typ3, bz)
			if slide(&bz, &n, _n) && err != nil {
				return
			}
		}
	}
	return
}
// CONTRACT: rv.CanAddr() is true.