diff --git a/tape/dynamic.go b/tape/dynamic.go index 52f833d..120eb50 100644 --- a/tape/dynamic.go +++ b/tape/dynamic.go @@ -114,7 +114,7 @@ func DecodeAnyInto(decoder *Decoder, destination any, tag Tag) (n int, err error // destination from the tag and data. The head of the decoder must be at the // start of the payload. func DecodeAny(decoder *Decoder, tag Tag) (value any, n int, err error) { - destination, err := skeletonValue(decoder, tag) + destination, err := skeletonPointer(decoder, tag) if err != nil { return nil, n, err } nn, err := DecodeAnyInto(decoder, destination, tag) n += nn; if err != nil { return nil, n, err } @@ -192,12 +192,12 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i setString(destination, string(buffer)) case OTA: // OTA: * + oldDestination := destination if isTypeAny(destination.Type()) { // need a skeleton value if we are assigning to any. value, err := skeletonValue(decoder, tag) if err != nil { return n, err } - destination.Set(value) - destination = value.Elem() + destination = value } length, nn, err := decoder.ReadUintN(tag.CN() + 1) n += nn; if err != nil { return n, err } @@ -232,6 +232,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i return n, err } } + oldDestination.Set(destination) case KTV: // KTV: ( )* length, nn, err := decoder.ReadUintN(tag.CN() + 1) @@ -245,7 +246,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i n += nn; if err != nil { return n, err } itemTag, nn, err := decoder.ReadTag() n += nn; if err != nil { return n, err } - value, err := skeletonValue(decoder, itemTag) + value, err := skeletonPointer(decoder, itemTag) if err != nil { return n, err } nn, err = decodeAny(decoder, value.Elem(), itemTag) n += nn; if err != nil { return n, err } @@ -473,10 +474,18 @@ func decodeAndSetFloat(decoder *Decoder, destination reflect.Value, bytes int) ( return n, errCantAssignf("unsupported bit width float%d", bytes * 8) } -// skeletonValue returns a pointer value. In order for it to be set, it must be -// dereferenced using Elem(). The head of the decoder must be at the start of -// the payload. +// skeletonValue returns an addressable value. It can be set directly. The head +// of the decoder must be at the start of the payload when calling. func skeletonValue(decoder *Decoder, tag Tag) (reflect.Value, error) { + ptr, err := skeletonPointer(decoder, tag) + if err != nil { return reflect.Value { }, err } + return ptr.Elem(), nil +} + +// skeletonPointer returns a pointer value. In order for it to be set, it must +// be dereferenced using Elem(). The head of the decoder must be at the start of +// the payload when calling. +func skeletonPointer(decoder *Decoder, tag Tag) (reflect.Value, error) { typ, err := typeOf(decoder, tag) if err != nil { return reflect.Value { }, err } return reflect.New(typ), nil @@ -484,7 +493,7 @@ func skeletonValue(decoder *Decoder, tag Tag) (reflect.Value, error) { // typeOf returns the type of the current tag being decoded. It does not use up // the decoder, it only peeks. The head of the decoder must be at the start of -// the payload. +// the payload when calling. func typeOf(decoder *Decoder, tag Tag) (reflect.Type, error) { switch tag.WithoutCN() { case SI: