io: redo GetVarSize for Serializable things

Use writes to a fake io.Writer that counts the bytes. Allows us to kill Size()
methods as useless and duplicating lots of functionality.
This commit is contained in:
Roman Khimov 2019-09-16 15:58:26 +03:00
parent 0da9fe6946
commit 56c72b5c67
2 changed files with 30 additions and 3 deletions

View file

@ -17,6 +17,20 @@ var (
i64 int64 i64 int64
) )
// This structure is used to calculate the wire size of the serializable
// structure. It's an io.Writer that doesn't do any real writes, but instead
// just counts the number of bytes to be written.
type counterWriter struct {
counter int
}
// Write implements the io.Writer interface
func (cw *counterWriter) Write(p []byte) (int, error) {
n := len(p)
cw.counter += n
return n, nil
}
// GetVarIntSize returns the size in number of bytes of a variable integer // GetVarIntSize returns the size in number of bytes of a variable integer
// (reference: GetVarSize(int value), https://github.com/neo-project/neo/blob/master/neo/IO/Helper.cs) // (reference: GetVarSize(int value), https://github.com/neo-project/neo/blob/master/neo/IO/Helper.cs)
func GetVarIntSize(value int) int { func GetVarIntSize(value int) int {
@ -59,6 +73,18 @@ func GetVarSize(value interface{}) int {
reflect.Uint32, reflect.Uint32,
reflect.Uint64: reflect.Uint64:
return GetVarIntSize(int(v.Uint())) return GetVarIntSize(int(v.Uint()))
case reflect.Ptr:
vser, ok := v.Interface().(Serializable)
if !ok {
panic(fmt.Sprintf("unable to calculate GetVarSize for a non-Serializable pointer"))
}
cw := counterWriter{}
w := NewBinWriterFromIO(&cw)
err := vser.EncodeBinary(w)
if err != nil {
panic(fmt.Sprintf("error serializing %s: %s", reflect.TypeOf(value), err.Error()))
}
return cw.counter
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
valueLength := v.Len() valueLength := v.Len()
valueSize := 0 valueSize := 0
@ -67,8 +93,7 @@ func GetVarSize(value interface{}) int {
switch reflect.ValueOf(value).Index(0).Interface().(type) { switch reflect.ValueOf(value).Index(0).Interface().(type) {
case Serializable: case Serializable:
for i := 0; i < valueLength; i++ { for i := 0; i < valueLength; i++ {
elem := v.Index(i).Interface().(Serializable) valueSize += GetVarSize(v.Index(i).Interface())
valueSize += elem.Size()
} }
case uint8, int8: case uint8, int8:
valueSize = valueLength valueSize = valueLength

View file

@ -10,13 +10,15 @@ import (
// Mock structure to test getting size of an array of serializable things // Mock structure to test getting size of an array of serializable things
type smthSerializable struct { type smthSerializable struct {
some [42]byte
} }
func (*smthSerializable) DecodeBinary(*BinReader) error { func (*smthSerializable) DecodeBinary(*BinReader) error {
return nil return nil
} }
func (*smthSerializable) EncodeBinary(*BinWriter) error { func (ss *smthSerializable) EncodeBinary(bw *BinWriter) error {
bw.WriteLE(ss.some)
return nil return nil
} }