message-size-increase #3
@ -1,83 +0,0 @@
|
|||||||
package tape
|
|
||||||
|
|
||||||
import "iter"
|
|
||||||
|
|
||||||
// DecodePairs decodes message tag/value pairs from a byte slice. It returns an
|
|
||||||
// iterator over all pairs, where the first value is the tag and the second is
|
|
||||||
// the value. If data yielded by the iterator is retained, it must be copied
|
|
||||||
// first.
|
|
||||||
func DecodePairs(data []byte) (iter.Seq2[uint16, []byte], error) {
|
|
||||||
// determine section bounds
|
|
||||||
if len(data) < 2 { return nil, ErrDataTooLarge }
|
|
||||||
length16, _, _ := DecodeI16[uint16](data[0:2])
|
|
||||||
data = data[2:]
|
|
||||||
length := int(length16)
|
|
||||||
headerSize := length * 4
|
|
||||||
if len(data) < headerSize { return nil, ErrDataTooLarge }
|
|
||||||
valuesData := data[headerSize:]
|
|
||||||
|
|
||||||
// ensure the value buffer is big enough
|
|
||||||
var valuesSize int
|
|
||||||
for index := range length {
|
|
||||||
offset := index * 4
|
|
||||||
end, _, _ := DecodeI16[uint16](data[offset + 2:offset + 4])
|
|
||||||
valuesSize = int(end)
|
|
||||||
}
|
|
||||||
if valuesSize > len(valuesData) {
|
|
||||||
return nil, ErrDataTooLarge
|
|
||||||
}
|
|
||||||
|
|
||||||
// return iterator
|
|
||||||
return func(yield func(uint16, []byte) bool) {
|
|
||||||
start := uint16(0)
|
|
||||||
for index := range length {
|
|
||||||
offset := index * 4
|
|
||||||
key, _, _ := DecodeI16[uint16](data[offset + 0:offset + 2])
|
|
||||||
end, _, _ := DecodeI16[uint16](data[offset + 2:offset + 4])
|
|
||||||
// if nextValuesOffset < len(valuesData) {
|
|
||||||
if !yield(key, valuesData[start:end]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// } else {
|
|
||||||
// if !yield(key, nil) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
start = end
|
|
||||||
}
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodePairs encodes message tag/value pairs into a byte slice.
|
|
||||||
func EncodePairs(pairs map[uint16] []byte) ([]byte, error) {
|
|
||||||
// determine section bounds
|
|
||||||
headerSize := 2 + len(pairs) * 4
|
|
||||||
valuesSize := 0
|
|
||||||
for _, value := range pairs {
|
|
||||||
valuesSize += len(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate data
|
|
||||||
buffer := make([]byte, headerSize + valuesSize)
|
|
||||||
length16, ok := U16CastSafe(len(pairs))
|
|
||||||
if !ok { return nil, ErrDataTooLarge }
|
|
||||||
EncodeI16[uint16](buffer[0:2], length16)
|
|
||||||
index := 0
|
|
||||||
end := headerSize
|
|
||||||
for key, value := range pairs {
|
|
||||||
start := end
|
|
||||||
end += len(value)
|
|
||||||
tagOffset := 2 + index * 4
|
|
||||||
end16, ok := U16CastSafe(end - headerSize)
|
|
||||||
if !ok { return nil, ErrDataTooLarge }
|
|
||||||
|
|
||||||
// write tag and length
|
|
||||||
EncodeI16[uint16](buffer[tagOffset + 0:tagOffset + 2], key)
|
|
||||||
EncodeI16[uint16](buffer[tagOffset + 2:tagOffset + 4], end16)
|
|
||||||
|
|
||||||
// write value
|
|
||||||
copy(buffer[start:end], value)
|
|
||||||
index ++
|
|
||||||
}
|
|
||||||
return buffer, nil
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package tape
|
|
||||||
|
|
||||||
import "slices"
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestDecodePairs(test *testing.T) {
|
|
||||||
pairs := map[uint16] []byte {
|
|
||||||
3894: []byte("foo"),
|
|
||||||
7: []byte("br"),
|
|
||||||
}
|
|
||||||
got, err := DecodePairs([]byte {
|
|
||||||
0, 2,
|
|
||||||
0, 7, 0, 2,
|
|
||||||
15, 54, 0, 5,
|
|
||||||
98, 114,
|
|
||||||
102, 111, 111})
|
|
||||||
if err != nil { test.Fatal(err) }
|
|
||||||
length := 0
|
|
||||||
for key, value := range got {
|
|
||||||
test.Log(key, value)
|
|
||||||
if !slices.Equal(pairs[key], value) { test.Fatal("not equal") }
|
|
||||||
length ++
|
|
||||||
}
|
|
||||||
test.Log("length")
|
|
||||||
if length != len(pairs) { test.Fatal("wrong length") }
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodePairs(test *testing.T) {
|
|
||||||
pairs := map[uint16] []byte {
|
|
||||||
3894: []byte("foo"),
|
|
||||||
7: []byte("br"),
|
|
||||||
}
|
|
||||||
got, err := EncodePairs(pairs)
|
|
||||||
if err != nil { test.Fatal(err) }
|
|
||||||
test.Log(got)
|
|
||||||
valid := slices.Equal(got, []byte {
|
|
||||||
0, 2,
|
|
||||||
15, 54, 0, 3,
|
|
||||||
0, 7, 0, 5,
|
|
||||||
102, 111, 111,
|
|
||||||
98, 114}) ||
|
|
||||||
slices.Equal(got, []byte {
|
|
||||||
0, 2,
|
|
||||||
0, 7, 0, 2,
|
|
||||||
15, 54, 0, 5,
|
|
||||||
98, 114,
|
|
||||||
102, 111, 111})
|
|
||||||
if !valid { test.Fatal("not equal") }
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuzzDecodePairs(fuzz *testing.F) {
|
|
||||||
fuzz.Add([]byte {
|
|
||||||
0, 2,
|
|
||||||
0, 7, 0, 2,
|
|
||||||
15, 54, 0, 5,
|
|
||||||
98, 114,
|
|
||||||
102, 111, 111})
|
|
||||||
fuzz.Fuzz(func(t *testing.T, buffer []byte) {
|
|
||||||
// ensure it does not panic :P
|
|
||||||
DecodePairs(buffer)
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user