tape: Change how slice skeletons are generated, support nested OTAs
This commit is contained in:
parent
4930215166
commit
81ac10508b
137
tape/dynamic.go
137
tape/dynamic.go
@ -9,6 +9,8 @@ package tape
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
import "reflect"
|
import "reflect"
|
||||||
|
|
||||||
|
var dummyMap map[uint16] any
|
||||||
|
|
||||||
// EncodeAny encodes an "any" value. Returns an error if the underlying type is
|
// EncodeAny encodes an "any" value. Returns an error if the underlying type is
|
||||||
// unsupported. Supported types are:
|
// unsupported. Supported types are:
|
||||||
//
|
//
|
||||||
@ -121,31 +123,20 @@ func decodeAny(decoder *Decoder, destination reflect.Value, tag Tag) (n int, err
|
|||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
oneTag, nn, err := decoder.ReadTag()
|
oneTag, nn, err := decoder.ReadTag()
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
var slice reflect.Value
|
if destination.Kind() != reflect.Slice {
|
||||||
needSet := false
|
|
||||||
if destination.Kind() == reflect.Struct && destination.Type() == unknownSlicePlaceholderType {
|
|
||||||
needSet = true
|
|
||||||
slice, err = skeletonValueSlice(oneTag, int(length))
|
|
||||||
if err != nil { return n, err }
|
|
||||||
slice = slice.Elem()
|
|
||||||
} else {
|
|
||||||
slice = destination
|
|
||||||
if slice.Kind() != reflect.Slice {
|
|
||||||
return n, errWrongDestinationType("slice")
|
return n, errWrongDestinationType("slice")
|
||||||
}
|
}
|
||||||
slice.SetLen(int(length))
|
if destination.Cap() < int(length) {
|
||||||
|
destination.Grow(destination.Cap() - int(length))
|
||||||
}
|
}
|
||||||
|
destination.SetLen(int(length))
|
||||||
for index := range length {
|
for index := range length {
|
||||||
nn, err := decodeAny(decoder, slice.Index(int(index)), oneTag)
|
nn, err := decodeAny(decoder, destination.Index(int(index)), oneTag)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
}
|
}
|
||||||
if needSet {
|
|
||||||
destination.Set(slice)
|
|
||||||
}
|
|
||||||
case KTV:
|
case KTV:
|
||||||
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
|
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
|
||||||
table := destination
|
table := destination
|
||||||
var dummyMap map[uint16] any
|
|
||||||
if table.Type() != reflect.TypeOf(dummyMap) {
|
if table.Type() != reflect.TypeOf(dummyMap) {
|
||||||
return n, errWrongDestinationType("map[uint16] any")
|
return n, errWrongDestinationType("map[uint16] any")
|
||||||
}
|
}
|
||||||
@ -305,65 +296,89 @@ func decodeAndSetFloat(decoder *Decoder, destination reflect.Value, bytes int) (
|
|||||||
// skeletonValue returns a pointer value. In order for it to be set, it must be
|
// skeletonValue returns a pointer value. In order for it to be set, it must be
|
||||||
// dereferenced using Elem().
|
// dereferenced using Elem().
|
||||||
func skeletonValue(decoder *Decoder, tag Tag) (reflect.Value, error) {
|
func skeletonValue(decoder *Decoder, tag Tag) (reflect.Value, error) {
|
||||||
|
typ, err := typeOf(decoder, tag)
|
||||||
|
if err != nil { return reflect.Value { }, err }
|
||||||
|
return reflect.New(typ), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeOf returns the type of the current tag being decoded. It does not use up
|
||||||
|
// the decoder, it only peeks.
|
||||||
|
func typeOf(decoder *Decoder, tag Tag) (reflect.Type, error) {
|
||||||
switch tag.WithoutCN() {
|
switch tag.WithoutCN() {
|
||||||
case SI:
|
case SI:
|
||||||
value := uint8(0)
|
return reflect.TypeOf(uint8(0)), nil
|
||||||
return reflect.ValueOf(&value), nil
|
|
||||||
case LI:
|
case LI:
|
||||||
switch tag.CN() {
|
switch tag.CN() {
|
||||||
case 0: value := uint8(0); return reflect.ValueOf(&value), nil
|
case 0: return reflect.TypeOf(uint8(0)), nil
|
||||||
case 1: value := uint16(0); return reflect.ValueOf(&value), nil
|
case 1: return reflect.TypeOf(uint16(0)), nil
|
||||||
case 3: value := uint32(0); return reflect.ValueOf(&value), nil
|
case 3: return reflect.TypeOf(uint32(0)), nil
|
||||||
case 7: value := uint64(0); return reflect.ValueOf(&value), nil
|
case 7: return reflect.TypeOf(uint64(0)), nil
|
||||||
}
|
}
|
||||||
return reflect.Value { }, fmt.Errorf("unknown CN %d for LI", tag.CN())
|
return nil, fmt.Errorf("unknown CN %d for LI", tag.CN())
|
||||||
case FP:
|
case FP:
|
||||||
switch tag.CN() {
|
switch tag.CN() {
|
||||||
case 3: value := float32(0); return reflect.ValueOf(&value), nil
|
case 3: return reflect.TypeOf(float32(0)), nil
|
||||||
case 7: value := float64(0); return reflect.ValueOf(&value), nil
|
case 7: return reflect.TypeOf(float64(0)), nil
|
||||||
}
|
}
|
||||||
return reflect.Value { }, fmt.Errorf("unknown CN %d for FP", tag.CN())
|
return nil, fmt.Errorf("unknown CN %d for FP", tag.CN())
|
||||||
case SBA: value := []byte { }; return reflect.ValueOf(&value), nil
|
case SBA: return reflect.SliceOf(reflect.TypeOf(byte(0))), nil
|
||||||
case LBA: value := []byte { }; return reflect.ValueOf(&value), nil
|
case LBA: return reflect.SliceOf(reflect.TypeOf(byte(0))), nil
|
||||||
case OTA: return skeletonValueSlice(decoder, tag)
|
case OTA:
|
||||||
case KTV: value := map[uint16] any { }; return reflect.ValueOf(&value), nil
|
elemTag, dimension, err := peekSlice(decoder, tag)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
if elemTag.Is(OTA) { panic("peekSlice cannot return OTA") }
|
||||||
|
typ, err := typeOf(decoder, elemTag)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
for _ = range dimension {
|
||||||
|
typ = reflect.SliceOf(typ)
|
||||||
}
|
}
|
||||||
return reflect.Value { }, fmt.Errorf("unknown TN %d", tag.TN())
|
return typ, nil
|
||||||
|
case KTV: return reflect.TypeOf(dummyMap), nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unknown TN %d", tag.TN())
|
||||||
}
|
}
|
||||||
|
|
||||||
// skeletonValueSlice returns a pointer value. In order for it to be set, it
|
// peekSlice returns the element tag and dimension count of the OTA currently
|
||||||
// must be dereferenced using Elem().
|
// being decoded. It does not use up the decoder, it only peeks.
|
||||||
func skeletonValueSlice(decoder *Decoder, tag Tag) (reflect.Value, error) {
|
func peekSlice(decoder *Decoder, tag Tag) (Tag, int, error) {
|
||||||
// TODO
|
offset := 0
|
||||||
|
dimension := 0
|
||||||
|
for {
|
||||||
|
elem, populated, n, err := peekSliceOnce(decoder, tag, offset)
|
||||||
|
if err != nil { return 0, 0, err }
|
||||||
|
offset += n
|
||||||
|
dimension += 1
|
||||||
|
if elem.Is(OTA) {
|
||||||
|
if !populated {
|
||||||
|
return LBA, dimension + 1, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return elem, dimension, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: delete fucntion below
|
// peekSliceOnce returns the element tag of the OTA located offset bytes ahead
|
||||||
|
// of the current position. It does not use up the decoder, it only peeks. The n
|
||||||
|
// return value denotes how far away from 0 it peeked. If the OTA has more than
|
||||||
|
// zero items, populated will be set to true.
|
||||||
|
func peekSliceOnce(decoder *Decoder, tag Tag, offset int) (elem Tag, populated bool, n int, err error) {
|
||||||
|
lengthStart := offset
|
||||||
|
lengthEnd := lengthStart + tag.CN() + 1
|
||||||
|
elemTagStart := lengthEnd
|
||||||
|
elemTagEnd := elemTagStart + 1
|
||||||
|
|
||||||
// skeletonValueSlice returns a pointer value. In order for it to be set, it
|
headerBytes, err := decoder.Peek(elemTagEnd)
|
||||||
// must be dereferenced using Elem().
|
if err != nil { return 0, false, 0, err }
|
||||||
func skeletonValueSlice(tag Tag, length int) (reflect.Value, error) {
|
|
||||||
switch tag.WithoutCN() {
|
elem = Tag(headerBytes[len(headerBytes)])
|
||||||
case SI:
|
for index := lengthStart; index < lengthEnd; index += 1 {
|
||||||
value := make([]uint8, length)
|
if headerBytes[index] > 0 {
|
||||||
return reflect.ValueOf(&value), nil
|
populated = true
|
||||||
case LI:
|
break
|
||||||
switch tag.CN() {
|
|
||||||
case 0: value := make([]uint8, length); return reflect.ValueOf(&value), nil
|
|
||||||
case 1: value := make([]uint16, length); return reflect.ValueOf(&value), nil
|
|
||||||
case 3: value := make([]uint32, length); return reflect.ValueOf(&value), nil
|
|
||||||
case 7: value := make([]uint64, length); return reflect.ValueOf(&value), nil
|
|
||||||
}
|
}
|
||||||
return reflect.Value { }, fmt.Errorf("unknown CN %d for LI OTA", tag.CN())
|
|
||||||
case FP:
|
|
||||||
switch tag.CN() {
|
|
||||||
case 3: value := make([]float32, length); return reflect.ValueOf(&value), nil
|
|
||||||
case 7: value := make([]float64, length); return reflect.ValueOf(&value), nil
|
|
||||||
}
|
}
|
||||||
return reflect.Value { }, fmt.Errorf("unknown CN %d for FP OTA", tag.CN())
|
n = elemTagEnd
|
||||||
case SBA: value := make([][]byte, length); return reflect.ValueOf(&value), nil
|
|
||||||
case LBA: value := make([][]byte, length); return reflect.ValueOf(&value), nil
|
return
|
||||||
case OTA: value := make([]any, length); return reflect.ValueOf(&value), nil
|
|
||||||
case KTV: value := make([]map[uint16] any, length); return reflect.ValueOf(&value), nil
|
|
||||||
}
|
|
||||||
return reflect.Value { }, fmt.Errorf("unknown TN %d", tag.TN())
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user