From bb850ddb5d9a159c55cc3b4d421b90a2c32ee52c Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 6 May 2021 17:53:54 +0200 Subject: [PATCH] PackAny(): pack []byte as string, not array of numbers --- pkg/icingadb/objectpacker/objectpacker.go | 43 +++++++++++++------ .../objectpacker/objectpacker_test.go | 10 +++++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/pkg/icingadb/objectpacker/objectpacker.go b/pkg/icingadb/objectpacker/objectpacker.go index dcd86ae8..be481ddf 100644 --- a/pkg/icingadb/objectpacker/objectpacker.go +++ b/pkg/icingadb/objectpacker/objectpacker.go @@ -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 +} diff --git a/pkg/icingadb/objectpacker/objectpacker_test.go b/pkg/icingadb/objectpacker/objectpacker_test.go index 5d36cecb..7b15ccf1 100644 --- a/pkg/icingadb/objectpacker/objectpacker_test.go +++ b/pkg/icingadb/objectpacker/objectpacker_test.go @@ -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)