mirror of
https://github.com/golang/go
synced 2024-11-22 20:04:47 -07:00
encoding/binary: make type error more specific
Right now it says 'invalid type S' for a struct type S. Instead, say which type inside the struct is the problem. Fixes #4825. R=golang-dev, iant CC=golang-dev https://golang.org/cl/7301102
This commit is contained in:
parent
d47cc872b5
commit
2b9787c2f3
@ -167,9 +167,9 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
|
|||||||
default:
|
default:
|
||||||
return errors.New("binary.Read: invalid type " + d.Type().String())
|
return errors.New("binary.Read: invalid type " + d.Type().String())
|
||||||
}
|
}
|
||||||
size := dataSize(v)
|
size, err := dataSize(v)
|
||||||
if size < 0 {
|
if err != nil {
|
||||||
return errors.New("binary.Read: invalid type " + v.Type().String())
|
return errors.New("binary.Read: " + err.Error())
|
||||||
}
|
}
|
||||||
d := &decoder{order: order, buf: make([]byte, size)}
|
d := &decoder{order: order, buf: make([]byte, size)}
|
||||||
if _, err := io.ReadFull(r, d.buf); err != nil {
|
if _, err := io.ReadFull(r, d.buf); err != nil {
|
||||||
@ -247,64 +247,68 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
|
|||||||
|
|
||||||
// Fallback to reflect-based encoding.
|
// Fallback to reflect-based encoding.
|
||||||
v := reflect.Indirect(reflect.ValueOf(data))
|
v := reflect.Indirect(reflect.ValueOf(data))
|
||||||
size := dataSize(v)
|
size, err := dataSize(v)
|
||||||
if size < 0 {
|
if err != nil {
|
||||||
return errors.New("binary.Write: invalid type " + v.Type().String())
|
return errors.New("binary.Write: " + err.Error())
|
||||||
}
|
}
|
||||||
buf := make([]byte, size)
|
buf := make([]byte, size)
|
||||||
e := &encoder{order: order, buf: buf}
|
e := &encoder{order: order, buf: buf}
|
||||||
e.value(v)
|
e.value(v)
|
||||||
_, err := w.Write(buf)
|
_, err = w.Write(buf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns how many bytes Write would generate to encode the value v, which
|
// Size returns how many bytes Write would generate to encode the value v, which
|
||||||
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
|
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
|
||||||
func Size(v interface{}) int {
|
func Size(v interface{}) int {
|
||||||
return dataSize(reflect.Indirect(reflect.ValueOf(v)))
|
n, err := dataSize(reflect.Indirect(reflect.ValueOf(v)))
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
|
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
|
||||||
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
|
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
|
||||||
// it returns the length of the slice times the element size and does not count the memory
|
// it returns the length of the slice times the element size and does not count the memory
|
||||||
// occupied by the header.
|
// occupied by the header.
|
||||||
func dataSize(v reflect.Value) int {
|
func dataSize(v reflect.Value) (int, error) {
|
||||||
if v.Kind() == reflect.Slice {
|
if v.Kind() == reflect.Slice {
|
||||||
elem := sizeof(v.Type().Elem())
|
elem, err := sizeof(v.Type().Elem())
|
||||||
if elem < 0 {
|
if err != nil {
|
||||||
return -1
|
return 0, err
|
||||||
}
|
}
|
||||||
return v.Len() * elem
|
return v.Len() * elem, nil
|
||||||
}
|
}
|
||||||
return sizeof(v.Type())
|
return sizeof(v.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeof(t reflect.Type) int {
|
func sizeof(t reflect.Type) (int, error) {
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
n := sizeof(t.Elem())
|
n, err := sizeof(t.Elem())
|
||||||
if n < 0 {
|
if err != nil {
|
||||||
return -1
|
return 0, err
|
||||||
}
|
}
|
||||||
return t.Len() * n
|
return t.Len() * n, nil
|
||||||
|
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
sum := 0
|
sum := 0
|
||||||
for i, n := 0, t.NumField(); i < n; i++ {
|
for i, n := 0, t.NumField(); i < n; i++ {
|
||||||
s := sizeof(t.Field(i).Type)
|
s, err := sizeof(t.Field(i).Type)
|
||||||
if s < 0 {
|
if err != nil {
|
||||||
return -1
|
return 0, err
|
||||||
}
|
}
|
||||||
sum += s
|
sum += s
|
||||||
}
|
}
|
||||||
return sum
|
return sum, nil
|
||||||
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
|
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
|
||||||
return int(t.Size())
|
return int(t.Size()), nil
|
||||||
}
|
}
|
||||||
return -1
|
return 0, errors.New("invalid type " + t.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
type coder struct {
|
type coder struct {
|
||||||
@ -514,11 +518,12 @@ func (e *encoder) value(v reflect.Value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) skip(v reflect.Value) {
|
func (d *decoder) skip(v reflect.Value) {
|
||||||
d.buf = d.buf[dataSize(v):]
|
n, _ := dataSize(v)
|
||||||
|
d.buf = d.buf[n:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) skip(v reflect.Value) {
|
func (e *encoder) skip(v reflect.Value) {
|
||||||
n := dataSize(v)
|
n, _ := dataSize(v)
|
||||||
for i := range e.buf[0:n] {
|
for i := range e.buf[0:n] {
|
||||||
e.buf[i] = 0
|
e.buf[i] = 0
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,8 +150,14 @@ func TestWriteT(t *testing.T) {
|
|||||||
|
|
||||||
tv := reflect.Indirect(reflect.ValueOf(ts))
|
tv := reflect.Indirect(reflect.ValueOf(ts))
|
||||||
for i, n := 0, tv.NumField(); i < n; i++ {
|
for i, n := 0, tv.NumField(); i < n; i++ {
|
||||||
|
typ := tv.Field(i).Type().String()
|
||||||
|
if typ == "[4]int" {
|
||||||
|
typ = "int" // the problem is int, not the [4]
|
||||||
|
}
|
||||||
if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
|
if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
|
||||||
t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
|
t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
|
||||||
|
} else if !strings.Contains(err.Error(), typ) {
|
||||||
|
t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +245,7 @@ func BenchmarkReadStruct(b *testing.B) {
|
|||||||
bsr := &byteSliceReader{}
|
bsr := &byteSliceReader{}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
Write(&buf, BigEndian, &s)
|
Write(&buf, BigEndian, &s)
|
||||||
n := dataSize(reflect.ValueOf(s))
|
n, _ := dataSize(reflect.ValueOf(s))
|
||||||
b.SetBytes(int64(n))
|
b.SetBytes(int64(n))
|
||||||
t := s
|
t := s
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
Loading…
Reference in New Issue
Block a user