io: optimize BinWriter.WriteArray()

Replace reflect.MethodByName with a simple interface cast.
This commit is contained in:
Evgenii Stratonikov 2019-12-06 18:15:33 +03:00
parent 1784a14148
commit f01fc1cc29
3 changed files with 13 additions and 17 deletions

View file

@ -39,33 +39,26 @@ func (w *BinWriter) WriteBE(v interface{}) {
func (w *BinWriter) WriteArray(arr interface{}) {
switch val := reflect.ValueOf(arr); val.Kind() {
case reflect.Slice, reflect.Array:
typ := val.Type().Elem()
method, ok := typ.MethodByName("EncodeBinary")
if !ok || !isEncodeBinaryMethod(method) {
panic(typ.String() + " does not have EncodeBinary(*BinWriter)")
}
if w.Err != nil {
return
}
typ := val.Type().Elem()
w.WriteVarUint(uint64(val.Len()))
for i := 0; i < val.Len(); i++ {
method := val.Index(i).MethodByName("EncodeBinary")
method.Call([]reflect.Value{reflect.ValueOf(w)})
el, ok := val.Index(i).Interface().(encodable)
if !ok {
panic(typ.String() + "is not encodable")
}
el.EncodeBinary(w)
}
default:
panic("not an array")
}
}
func isEncodeBinaryMethod(method reflect.Method) bool {
t := method.Type
return t != nil &&
t.NumIn() == 2 && t.In(1) == reflect.TypeOf((*BinWriter)(nil)) &&
t.NumOut() == 0
}
// WriteVarUint writes a uint64 into the underlying writer using variable-length encoding.
func (w *BinWriter) WriteVarUint(val uint64) {
if w.Err != nil {

View file

@ -267,8 +267,7 @@ func TestBinWriter_WriteArray(t *testing.T) {
require.Equal(t, w.Bytes(), []byte(nil))
w.Reset()
w.Err = errors.New("error")
require.Panics(t, func() { w.WriteArray([]int{}) })
require.Panics(t, func() { w.WriteArray([]int{1}) })
w.Reset()
w.Err = errors.New("error")

View file

@ -14,3 +14,7 @@ type Serializable interface {
type decodable interface {
DecodeBinary(*BinReader)
}
type encodable interface {
EncodeBinary(*BinWriter)
}