any-type #20

Merged
sashakoshka merged 18 commits from any-type into main 2025-10-12 11:03:57 -06:00
Showing only changes of commit 56c376cd4e - Show all commits

View File

@ -101,6 +101,7 @@ func EncodeAny(encoder *Encoder, value any, tag Tag) (n int, err error) {
// DecodeAnyInto decodes data and places it into destination, which must be a
// pointer to a supported type. See [EncodeAny] for a list of supported types.
// The head of the decoder must be at the start of the payload.
func DecodeAnyInto(decoder *Decoder, destination any, tag Tag) (n int, err error) {
reflectDestination := reflect.ValueOf(destination)
if reflectDestination.Kind() != reflect.Pointer {
@ -110,7 +111,8 @@ func DecodeAnyInto(decoder *Decoder, destination any, tag Tag) (n int, err error
}
// DecodeAny is like [DecodeAnyInto], but it automatically creates the
// destination from the tag and data.
// 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)
if err != nil { return nil, n, err }
@ -128,7 +130,8 @@ var unknownSlicePlaceholderType = reflect.TypeOf(unknownSlicePlaceholder { })
// decodeAny is internal to [DecodeAny]. It takes in an addressable
// [reflect.Value] as the destination. If the decoded value cannot fit in the
// destination, it skims over the payload, leaves the destination empty, and
// returns without an error.
// returns without an error. The head of the decoder must be at the start of the
// payload.
func decodeAny(decoder *Decoder, destination reflect.Value, tag Tag) (n int, err error) {
n, err = decodeAnyOrError(decoder, destination, tag)
if _, ok := err.(errCantAssign); ok {
@ -145,7 +148,7 @@ func decodeAny(decoder *Decoder, destination reflect.Value, tag Tag) (n int, err
// destination, it decodes nothing and returns an error of type errCantAssign,
// except for the case of a mismatched OTA element tag, wherein it will skim
// over the rest of the payload, leave the destination empty, and return without
// an error.
// an error. The head of the decoder must be at the start of the payload.
func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n int, err error) {
err = canSet(destination.Type(), tag)
if err != nil { return n, err }
@ -189,6 +192,13 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
setString(destination, string(buffer))
case OTA:
// OTA: <length: UN> <elementTag: tape.Tag> <values>*
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()
}
length, nn, err := decoder.ReadUintN(tag.CN() + 1)
n += nn; if err != nil { return n, err }
if length > uint64(MaxStructureLength) {
@ -356,6 +366,7 @@ func canSet(destination reflect.Type, tag Tag) error {
return errCantAssignf("cannot assign float to %v", destination)
}
case SBA, LBA:
if destination.Kind() == reflect.String { return nil }
if destination.Kind() != reflect.Slice {
return errCantAssignf("cannot assign byte array to %v", destination)
}
@ -463,7 +474,8 @@ func decodeAndSetFloat(decoder *Decoder, destination reflect.Value, bytes int) (
}
// skeletonValue returns a pointer value. In order for it to be set, it must be
// dereferenced using Elem().
// dereferenced using Elem(). The head of the decoder must be at the start of
// the payload.
func skeletonValue(decoder *Decoder, tag Tag) (reflect.Value, error) {
typ, err := typeOf(decoder, tag)
if err != nil { return reflect.Value { }, err }
@ -471,7 +483,8 @@ 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 decoder, it only peeks. The head of the decoder must be at the start of
// the payload.
func typeOf(decoder *Decoder, tag Tag) (reflect.Type, error) {
switch tag.WithoutCN() {
case SI: