reflect: Add Value.IsZero() method
Add Value.IsZero() with tests, largely copied from the Go source code. The tests were altered to remove the parts calling `Zero()` as that is still unimplemented in tinygo, and to remove a test that tries to catch a panic which is not supported on wasi. A new case for `UnsafePointer` in `Value.IsNil()` was required for unsafe.Pointer tests to pass. Link: https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/reflect/value.go;l=1568 Link: https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/reflect/all_test.go;l=1322 Co-authored-by: Cam Hutchison <camh@xdna.net>
Этот коммит содержится в:
родитель
a329f56ec2
коммит
c759e6fc2d
2 изменённых файлов: 148 добавлений и 1 удалений
|
@ -5,9 +5,13 @@
|
||||||
package reflect_test
|
package reflect_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
. "reflect"
|
. "reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Basic struct {
|
type Basic struct {
|
||||||
|
@ -184,5 +188,107 @@ func TestDeepEqualComplexStructInequality(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
a int
|
||||||
|
b float64
|
||||||
|
c string
|
||||||
|
d *int
|
||||||
|
}
|
||||||
|
|
||||||
|
var _i = 7
|
||||||
|
|
||||||
|
func TestIsZero(t *testing.T) {
|
||||||
|
for i, tt := range []struct {
|
||||||
|
x interface{}
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// Booleans
|
||||||
|
{true, false},
|
||||||
|
{false, true},
|
||||||
|
// Numeric types
|
||||||
|
{int(0), true},
|
||||||
|
{int(1), false},
|
||||||
|
{int8(0), true},
|
||||||
|
{int8(1), false},
|
||||||
|
{int16(0), true},
|
||||||
|
{int16(1), false},
|
||||||
|
{int32(0), true},
|
||||||
|
{int32(1), false},
|
||||||
|
{int64(0), true},
|
||||||
|
{int64(1), false},
|
||||||
|
{uint(0), true},
|
||||||
|
{uint(1), false},
|
||||||
|
{uint8(0), true},
|
||||||
|
{uint8(1), false},
|
||||||
|
{uint16(0), true},
|
||||||
|
{uint16(1), false},
|
||||||
|
{uint32(0), true},
|
||||||
|
{uint32(1), false},
|
||||||
|
{uint64(0), true},
|
||||||
|
{uint64(1), false},
|
||||||
|
{float32(0), true},
|
||||||
|
{float32(1.2), false},
|
||||||
|
{float64(0), true},
|
||||||
|
{float64(1.2), false},
|
||||||
|
{math.Copysign(0, -1), false},
|
||||||
|
{complex64(0), true},
|
||||||
|
{complex64(1.2), false},
|
||||||
|
{complex128(0), true},
|
||||||
|
{complex128(1.2), false},
|
||||||
|
{complex(math.Copysign(0, -1), 0), false},
|
||||||
|
{complex(0, math.Copysign(0, -1)), false},
|
||||||
|
{complex(math.Copysign(0, -1), math.Copysign(0, -1)), false},
|
||||||
|
{uintptr(0), true},
|
||||||
|
{uintptr(128), false},
|
||||||
|
// Array
|
||||||
|
{[5]string{"", "", "", "", ""}, true},
|
||||||
|
{[5]string{}, true},
|
||||||
|
{[5]string{"", "", "", "a", ""}, false},
|
||||||
|
// Chan
|
||||||
|
{(chan string)(nil), true},
|
||||||
|
{make(chan string), false},
|
||||||
|
{time.After(1), false},
|
||||||
|
// Func
|
||||||
|
{(func())(nil), true},
|
||||||
|
{New, false},
|
||||||
|
// Interface
|
||||||
|
{New(TypeOf(new(error)).Elem()).Elem(), true},
|
||||||
|
{(io.Reader)(strings.NewReader("")), false},
|
||||||
|
// Map
|
||||||
|
{(map[string]string)(nil), true},
|
||||||
|
{map[string]string{}, false},
|
||||||
|
{make(map[string]string), false},
|
||||||
|
// Pointer
|
||||||
|
{(*func())(nil), true},
|
||||||
|
{(*int)(nil), true},
|
||||||
|
{new(int), false},
|
||||||
|
// Slice
|
||||||
|
{[]string{}, false},
|
||||||
|
{([]string)(nil), true},
|
||||||
|
{make([]string, 0), false},
|
||||||
|
// Strings
|
||||||
|
{"", true},
|
||||||
|
{"not-zero", false},
|
||||||
|
// Structs
|
||||||
|
{T{}, true},
|
||||||
|
{T{123, 456.75, "hello", &_i}, false},
|
||||||
|
// UnsafePointer
|
||||||
|
{(unsafe.Pointer)(nil), true},
|
||||||
|
{(unsafe.Pointer)(new(int)), false},
|
||||||
|
} {
|
||||||
|
var x Value
|
||||||
|
if v, ok := tt.x.(Value); ok {
|
||||||
|
x = v
|
||||||
|
} else {
|
||||||
|
x = ValueOf(tt.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := x.IsZero()
|
||||||
|
if b != tt.want {
|
||||||
|
t.Errorf("%d: IsZero((%s)(%+v)) = %t, want %t", i, x.Kind(), tt.x, b, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MyBytes []byte
|
type MyBytes []byte
|
||||||
type MyByte byte
|
type MyByte byte
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,6 +92,46 @@ func (v Value) Type() Type {
|
||||||
return v.typecode
|
return v.typecode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsZero reports whether v is the zero value for its type.
|
||||||
|
// It panics if the argument is invalid.
|
||||||
|
func (v Value) IsZero() bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case Int, Int8, Int16, Int32, Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case Float32, Float64:
|
||||||
|
return math.Float64bits(v.Float()) == 0
|
||||||
|
case Complex64, Complex128:
|
||||||
|
c := v.Complex()
|
||||||
|
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
|
||||||
|
case Array:
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
if !v.Index(i).IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer:
|
||||||
|
return v.IsNil()
|
||||||
|
case String:
|
||||||
|
return v.Len() == 0
|
||||||
|
case Struct:
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
if !v.Field(i).IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
// This should never happens, but will act as a safeguard for
|
||||||
|
// later, as a default value doesn't makes sense here.
|
||||||
|
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Internal function only, do not use.
|
// Internal function only, do not use.
|
||||||
//
|
//
|
||||||
// RawType returns the raw, underlying type code. It is used in the runtime
|
// RawType returns the raw, underlying type code. It is used in the runtime
|
||||||
|
@ -107,7 +148,7 @@ func (v Value) Kind() Kind {
|
||||||
// is not a channel, map, pointer, function, slice, or interface.
|
// is not a channel, map, pointer, function, slice, or interface.
|
||||||
func (v Value) IsNil() bool {
|
func (v Value) IsNil() bool {
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case Chan, Map, Ptr:
|
case Chan, Map, Ptr, UnsafePointer:
|
||||||
return v.pointer() == nil
|
return v.pointer() == nil
|
||||||
case Func:
|
case Func:
|
||||||
if v.value == nil {
|
if v.value == nil {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче