tape: Assorted changes i forgor
This commit is contained in:
parent
84b96ed8f3
commit
7df18f7d26
@ -8,6 +8,17 @@ package tape
|
||||
|
||||
// TODO: test all of these smaller functions individually
|
||||
|
||||
// For an explanation as to why this package always treats LBA/SBA as strings,
|
||||
// refer to https://go.dev/blog/strings:
|
||||
//
|
||||
// It’s important to state right up front that a string holds arbitrary
|
||||
// bytes. It is not required to hold Unicode text, UTF-8 text, or any other
|
||||
// predefined format. As far as the content of a string is concerned, it is
|
||||
// exactly equivalent to a slice of bytes.
|
||||
//
|
||||
// Arbitrary byte slices and blobs won't be as common of a use case as text
|
||||
// data, and if you need that anyway you can just cast it to a byte slice.
|
||||
|
||||
import "fmt"
|
||||
import "reflect"
|
||||
|
||||
@ -142,7 +153,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
|
||||
switch tag.WithoutCN() {
|
||||
case SI:
|
||||
// SI: (none)
|
||||
setInt(destination, uint64(tag.CN()))
|
||||
setUint(destination, uint64(tag.CN()), 1)
|
||||
case LI:
|
||||
// LI: <value: IntN>
|
||||
nn, err := decodeAndSetUint(decoder, destination, tag.CN() + 1)
|
||||
@ -164,7 +175,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
|
||||
buffer := make([]byte, length)
|
||||
nn, err := decoder.Read(buffer)
|
||||
n += nn; if err != nil { return n, err }
|
||||
setByteArray(destination, buffer)
|
||||
setString(destination, string(buffer))
|
||||
case LBA:
|
||||
// LBA: <length: UN> <data: U8>*
|
||||
length, nn, err := decoder.ReadUintN(tag.CN() + 1)
|
||||
@ -175,7 +186,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
|
||||
buffer := make([]byte, length)
|
||||
nn, err = decoder.Read(buffer)
|
||||
n += nn; if err != nil { return n, err }
|
||||
setByteArray(destination, buffer)
|
||||
setString(destination, string(buffer))
|
||||
case OTA:
|
||||
// OTA: <length: UN> <elementTag: tape.Tag> <values>*
|
||||
length, nn, err := decoder.ReadUintN(tag.CN() + 1)
|
||||
@ -325,6 +336,10 @@ func encodeAnyMap(encoder *Encoder, value any, tag Tag) (n int, err error) {
|
||||
}
|
||||
|
||||
func canSet(destination reflect.Type, tag Tag) error {
|
||||
// anything can be assigned to `any`
|
||||
if isTypeAny(destination) {
|
||||
return nil
|
||||
}
|
||||
switch tag.WithoutCN() {
|
||||
case SI, LI, LSI:
|
||||
switch destination.Kind() {
|
||||
@ -362,17 +377,43 @@ func canSet(destination reflect.Type, tag Tag) error {
|
||||
}
|
||||
|
||||
// setInt expects a settable destination.
|
||||
func setInt[T int64 | uint64](destination reflect.Value, value T) {
|
||||
func setInt(destination reflect.Value, value int64, bytes int) {
|
||||
switch {
|
||||
case destination.CanInt():
|
||||
destination.Set(reflect.ValueOf(int64(value)).Convert(destination.Type()))
|
||||
case destination.CanUint():
|
||||
destination.Set(reflect.ValueOf(value).Convert(destination.Type()))
|
||||
case isTypeAny(destination.Type()):
|
||||
switch {
|
||||
case bytes > 4: destination.Set(reflect.ValueOf(int64(value)))
|
||||
case bytes > 2: destination.Set(reflect.ValueOf(int32(value)))
|
||||
case bytes > 1: destination.Set(reflect.ValueOf(int16(value)))
|
||||
default: destination.Set(reflect.ValueOf(int8(value)))
|
||||
}
|
||||
default:
|
||||
panic("setInt called on an unsupported type")
|
||||
}
|
||||
}
|
||||
|
||||
// setUint expects a settable destination.
|
||||
func setUint(destination reflect.Value, value uint64, bytes int) {
|
||||
switch {
|
||||
case destination.CanInt():
|
||||
destination.Set(reflect.ValueOf(int64(value)).Convert(destination.Type()))
|
||||
case destination.CanUint():
|
||||
destination.Set(reflect.ValueOf(value).Convert(destination.Type()))
|
||||
case isTypeAny(destination.Type()):
|
||||
switch {
|
||||
case bytes > 4: destination.Set(reflect.ValueOf(uint64(value)))
|
||||
case bytes > 2: destination.Set(reflect.ValueOf(uint32(value)))
|
||||
case bytes > 1: destination.Set(reflect.ValueOf(uint16(value)))
|
||||
default: destination.Set(reflect.ValueOf(uint8(value)))
|
||||
}
|
||||
default:
|
||||
panic("setUint called on an unsupported type")
|
||||
}
|
||||
}
|
||||
|
||||
// setFloat expects a settable destination.
|
||||
func setFloat(destination reflect.Value, value float64) {
|
||||
destination.Set(reflect.ValueOf(value).Convert(destination.Type()))
|
||||
@ -387,7 +428,7 @@ func setByteArray(destination reflect.Value, value []byte) {
|
||||
func decodeAndSetInt(decoder *Decoder, destination reflect.Value, bytes int) (n int, err error) {
|
||||
value, nn, err := decoder.ReadIntN(bytes)
|
||||
n += nn; if err != nil { return n, err }
|
||||
setInt(destination, value)
|
||||
setInt(destination, value, bytes)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@ -395,7 +436,7 @@ func decodeAndSetInt(decoder *Decoder, destination reflect.Value, bytes int) (n
|
||||
func decodeAndSetUint(decoder *Decoder, destination reflect.Value, bytes int) (n int, err error) {
|
||||
value, nn, err := decoder.ReadUintN(bytes)
|
||||
n += nn; if err != nil { return n, err }
|
||||
setInt(destination, value)
|
||||
setUint(destination, value, bytes)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@ -452,8 +493,8 @@ func typeOf(decoder *Decoder, tag Tag) (reflect.Type, error) {
|
||||
case 7: return reflect.TypeOf(float64(0)), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown CN %d for FP", tag.CN())
|
||||
case SBA: return reflect.SliceOf(reflect.TypeOf(byte(0))), nil
|
||||
case LBA: return reflect.SliceOf(reflect.TypeOf(byte(0))), nil
|
||||
case SBA: return reflect.TypeOf(""), nil
|
||||
case LBA: return reflect.TypeOf(""), nil
|
||||
case OTA:
|
||||
elemTag, dimension, err := peekSlice(decoder, tag)
|
||||
if err != nil { return nil, err }
|
||||
@ -469,6 +510,12 @@ func typeOf(decoder *Decoder, tag Tag) (reflect.Type, error) {
|
||||
return nil, fmt.Errorf("unknown TN %d", tag.TN())
|
||||
}
|
||||
|
||||
// isTypeAny returns whether the given reflect.Type is an interface with no
|
||||
// methods.
|
||||
func isTypeAny(typ reflect.Type) bool {
|
||||
return typ.Kind() == reflect.Interface && typ.NumMethod() == 0
|
||||
}
|
||||
|
||||
// peekSlice returns the element tag and dimension count of the OTA currently
|
||||
// being decoded. It does not use up the decoder, it only peeks.
|
||||
func peekSlice(decoder *Decoder, tag Tag) (Tag, int, error) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user