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