Compare commits

...

4 Commits

7 changed files with 27 additions and 6 deletions

View File

@ -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.

View File

@ -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()

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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
}