Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
419c3651bf | |||
8dac25035f | |||
b7bdaba694 | |||
45dfdb255e |
@ -30,6 +30,7 @@ PDL allows defining a protocol using HOPP and TAPE.
|
||||
| []\<TYPE\> | OTA | * | Array of any type[^1]
|
||||
| Table | KTV | * | Table with undefined schema
|
||||
| {...} | KTV | * | Table with defined schema
|
||||
| Any | * | * | Value of an undefined type
|
||||
|
||||
[^1]: Excluding SI and SBA. I5 and U5 cannot be used in an array, but String and
|
||||
Buffer are simply forced to use their "long" variant.
|
||||
|
@ -627,7 +627,7 @@ func (this *Generator) generateDecodeValue(typ Type, typeName, valueSource, tagS
|
||||
case TypeTable:
|
||||
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
|
||||
nn, err := this.iprintf(
|
||||
"nn, err = tape.DecodeAny(decoder, %s, %s)\n",
|
||||
"nn, err = tape.DecodeAnyInto(decoder, %s, %s)\n",
|
||||
valueSource, tagSource)
|
||||
n += nn; if err != nil { return n, err }
|
||||
nn, err = this.generateErrorCheck()
|
||||
|
@ -116,6 +116,7 @@ func (this *parser) parseType() (Type, error) {
|
||||
case "String": return TypeString { }, this.Next()
|
||||
case "Buffer": return TypeBuffer { }, this.Next()
|
||||
case "Table": return TypeTable { }, this.Next()
|
||||
case "Any": return TypeAny { }, this.Next()
|
||||
}
|
||||
return this.parseTypeNamed()
|
||||
case TokenLBracket:
|
||||
|
@ -31,6 +31,7 @@ func TestParse(test *testing.T) {
|
||||
0x0002: Field { Name: "Followers", Type: TypeInt { Bits: 32 } },
|
||||
},
|
||||
}
|
||||
correct.Types["Anything"] = TypeAny { }
|
||||
test.Log("CORRECT:", &correct)
|
||||
|
||||
got, err := ParseReader("test.pdl", strings.NewReader(`
|
||||
@ -48,6 +49,8 @@ func TestParse(test *testing.T) {
|
||||
0001 Bio String,
|
||||
0002 Followers U32,
|
||||
}
|
||||
|
||||
Anything Any
|
||||
`))
|
||||
if err != nil { test.Fatal(parse.Format(err)) }
|
||||
test.Log("GOT: ", got)
|
||||
|
@ -99,6 +99,12 @@ func (typ TypeNamed) String() string {
|
||||
return typ.Name
|
||||
}
|
||||
|
||||
type TypeAny struct { }
|
||||
|
||||
func (typ TypeAny) String() string {
|
||||
return "Any"
|
||||
}
|
||||
|
||||
func HashType(typ Type) [16]byte {
|
||||
// TODO: if we ever want to make the compiler more efficient, this would
|
||||
// be a good place to start, complex string concatenation in a hot path
|
||||
|
@ -86,9 +86,9 @@ func EncodeAny(encoder *Encoder, value any, tag Tag) (n int, err error) {
|
||||
return n, fmt.Errorf("cannot encode type %T", value)
|
||||
}
|
||||
|
||||
// DecodeAny decodes data and places it into destination, which must be a
|
||||
// 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.
|
||||
func DecodeAny(decoder *Decoder, destination any, tag Tag) (n int, err error) {
|
||||
func DecodeAnyInto(decoder *Decoder, destination any, tag Tag) (n int, err error) {
|
||||
reflectDestination := reflect.ValueOf(destination)
|
||||
if reflectDestination.Kind() != reflect.Pointer {
|
||||
return n, fmt.Errorf("expected pointer destination, not %v", destination)
|
||||
@ -96,6 +96,16 @@ func DecodeAny(decoder *Decoder, destination any, tag Tag) (n int, err error) {
|
||||
return decodeAny(decoder, reflectDestination.Elem(), tag)
|
||||
}
|
||||
|
||||
// DecodeAny is like [DecodeAnyInto], but it automatically creates the
|
||||
// destination from the tag and data.
|
||||
func DecodeAny(decoder *Decoder, tag Tag) (value any, n int, err error) {
|
||||
destination, err := skeletonValue(decoder, tag)
|
||||
if err != nil { return nil, n, err }
|
||||
nn, err := DecodeAnyInto(decoder, destination, tag)
|
||||
n += nn; if err != nil { return nil, n, err }
|
||||
return destination, n, err
|
||||
}
|
||||
|
||||
// unknownSlicePlaceholder is inserted by skeletonValue and informs the program
|
||||
// that the destination for the slice needs to be generated based on the item
|
||||
// tag in the OTA.
|
||||
|
@ -104,7 +104,7 @@ func TestDecodeWrongType(test *testing.T) {
|
||||
// integers should only assign to other integers
|
||||
if index > 8 {
|
||||
cas := func(destination any) {
|
||||
n, err := DecodeAny(NewDecoder(bytes.NewBuffer(data[1:])), destination, Tag(data[0]))
|
||||
n, err := DecodeAnyInto(NewDecoder(bytes.NewBuffer(data[1:])), destination, Tag(data[0]))
|
||||
if err != nil { test.Fatalf("error: %v | n: %d", err, n) }
|
||||
reflectValue := reflect.ValueOf(destination).Elem()
|
||||
if reflectValue.CanInt() {
|
||||
@ -138,7 +138,7 @@ func TestDecodeWrongType(test *testing.T) {
|
||||
{ var dest uint64; cas(&dest) }
|
||||
}
|
||||
arrayCase := func(destination any) {
|
||||
n, err := DecodeAny(NewDecoder(bytes.NewBuffer(data[1:])), destination, Tag(data[0]))
|
||||
n, err := DecodeAnyInto(NewDecoder(bytes.NewBuffer(data[1:])), destination, Tag(data[0]))
|
||||
if err != nil { test.Fatalf("error: %v | n: %d", err, n) }
|
||||
reflectDestination := reflect.ValueOf(destination)
|
||||
reflectValue := reflectDestination.Elem()
|
||||
@ -256,7 +256,7 @@ func decAny(data []byte) (Tag, any, int, error) {
|
||||
destination := map[uint16] any { }
|
||||
tag, err := TagAny(destination)
|
||||
if err != nil { return 0, nil, 0, err }
|
||||
n, err := DecodeAny(NewDecoder(bytes.NewBuffer(data)), &destination, tag)
|
||||
n, err := DecodeAnyInto(NewDecoder(bytes.NewBuffer(data)), &destination, tag)
|
||||
if err != nil { return 0, nil, n, err }
|
||||
return tag, destination, n, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user