PackAny(): pack []byte as string, not array of numbers

This commit is contained in:
Alexander A. Klimov 2021-05-06 17:53:54 +02:00
parent a5d446bc76
commit bb850ddb5d
2 changed files with 41 additions and 12 deletions

View file

@ -19,7 +19,7 @@ func PackAny(in interface{}, out io.Writer) error {
// packValue does the actual job of packAny and just exists for recursion w/o unneccessary reflect.ValueOf calls.
func packValue(in reflect.Value, out io.Writer) error {
switch in.Kind() {
switch kind := in.Kind(); kind {
case reflect.Invalid: // nil
_, err := out.Write([]byte{0})
return err
@ -38,6 +38,21 @@ func packValue(in reflect.Value, out io.Writer) error {
case reflect.Float32, reflect.Float64:
return packFloat64(in.Float(), out)
case reflect.Array, reflect.Slice:
if typ := in.Type(); typ.Elem().Kind() == reflect.Uint8 {
if kind == reflect.Array {
if !in.CanAddr() {
vNewElem := reflect.New(typ).Elem()
vNewElem.Set(in)
in = vNewElem
}
in = in.Slice(0, in.Len())
}
// Pack []byte as string, not array of numbers.
return packString(in.Interface().([]uint8), out)
}
if _, err := out.Write([]byte{5}); err != nil {
return err
}
@ -107,17 +122,7 @@ func packValue(in reflect.Value, out io.Writer) error {
return packValue(in.Elem(), out)
}
case reflect.String:
if _, err := out.Write([]byte{4}); err != nil {
return err
}
b := []byte(in.String())
if err := binary.Write(out, binary.BigEndian, uint64(len(b))); err != nil {
return err
}
_, err := out.Write(b)
return err
return packString([]byte(in.String()), out)
default:
panic("bad type: " + in.Kind().String())
}
@ -131,3 +136,17 @@ func packFloat64(in float64, out io.Writer) error {
return binary.Write(out, binary.BigEndian, in)
}
// packString deduplicates string packing of multiple locations in packValue.
func packString(in []byte, out io.Writer) error {
if _, err := out.Write([]byte{4}); err != nil {
return err
}
if err := binary.Write(out, binary.BigEndian, uint64(len(in))); err != nil {
return err
}
_, err := out.Write(in)
return err
}

View file

@ -121,6 +121,16 @@ func TestPackAny(t *testing.T) {
assertPackAny(t, "a", []byte{4, 0, 0, 0, 0, 0, 0, 0, 1, 'a'})
assertPackAny(t, "ä", []byte{4, 0, 0, 0, 0, 0, 0, 0, 2, 0xc3, 0xa4})
{
var binary [256]byte
for i := range binary {
binary[i] = byte(i)
}
assertPackAny(t, binary, append([]byte{4, 0, 0, 0, 0, 0, 0, 1, 0}, binary[:]...))
assertPackAny(t, binary[:], append([]byte{4, 0, 0, 0, 0, 0, 0, 1, 0}, binary[:]...))
}
assertPackAnyPanic(t, complex64(0+0i), 0)
assertPackAnyPanic(t, 0+0i, 0)
assertPackAnyPanic(t, make(chan struct{}, 0), 0)