mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: add Type.ConvertibleTo, Value.Convert (API CHANGE)
Fixes #4047. R=iant, r CC=golang-dev https://golang.org/cl/6500065
This commit is contained in:
parent
49aa74ef7f
commit
46f379cc2c
4 changed files with 814 additions and 4 deletions
|
|
@ -302,6 +302,17 @@ func (v Value) Bytes() []byte {
|
|||
return *(*[]byte)(v.val)
|
||||
}
|
||||
|
||||
// runes returns v's underlying value.
|
||||
// It panics if v's underlying value is not a slice of runes (int32s).
|
||||
func (v Value) runes() []rune {
|
||||
v.mustBe(Slice)
|
||||
if v.typ.Elem().Kind() != Int32 {
|
||||
panic("reflect.Value.Bytes of non-rune slice")
|
||||
}
|
||||
// Slice is always bigger than a word; assume flagIndir.
|
||||
return *(*[]rune)(v.val)
|
||||
}
|
||||
|
||||
// CanAddr returns true if the value's address can be obtained with Addr.
|
||||
// Such values are called addressable. A value is addressable if it is
|
||||
// an element of a slice, an element of an addressable array,
|
||||
|
|
@ -1221,6 +1232,17 @@ func (v Value) SetBytes(x []byte) {
|
|||
*(*[]byte)(v.val) = x
|
||||
}
|
||||
|
||||
// setRunes sets v's underlying value.
|
||||
// It panics if v's underlying value is not a slice of runes (int32s).
|
||||
func (v Value) setRunes(x []rune) {
|
||||
v.mustBeAssignable()
|
||||
v.mustBe(Slice)
|
||||
if v.typ.Elem().Kind() != Int32 {
|
||||
panic("reflect.Value.setRunes of non-rune slice")
|
||||
}
|
||||
*(*[]rune)(v.val) = x
|
||||
}
|
||||
|
||||
// SetComplex sets v's underlying value to x.
|
||||
// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false.
|
||||
func (v Value) SetComplex(x complex128) {
|
||||
|
|
@ -1916,6 +1938,302 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va
|
|||
panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
|
||||
}
|
||||
|
||||
// Convert returns the value v converted to type t.
|
||||
// If the usual Go conversion rules do not allow conversion
|
||||
// of the value v to type t, Convert panics.
|
||||
func (v Value) Convert(t Type) Value {
|
||||
if v.flag&flagMethod != 0 {
|
||||
panic("reflect.Value.Convert: cannot convert method values")
|
||||
}
|
||||
op := convertOp(t.common(), v.typ)
|
||||
if op == nil {
|
||||
panic("reflect.Value.Convert: value of type " + v.typ.String() + " cannot be converted to type " + t.String())
|
||||
}
|
||||
return op(v, t)
|
||||
}
|
||||
|
||||
// convertOp returns the function to convert a value of type src
|
||||
// to a value of type dst. If the conversion is illegal, convertOp returns nil.
|
||||
func convertOp(dst, src *commonType) func(Value, Type) Value {
|
||||
switch src.Kind() {
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
switch dst.Kind() {
|
||||
case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return cvtInt
|
||||
case Float32, Float64:
|
||||
return cvtIntFloat
|
||||
case String:
|
||||
return cvtIntString
|
||||
}
|
||||
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
switch dst.Kind() {
|
||||
case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return cvtUint
|
||||
case Float32, Float64:
|
||||
return cvtUintFloat
|
||||
case String:
|
||||
return cvtUintString
|
||||
}
|
||||
|
||||
case Float32, Float64:
|
||||
switch dst.Kind() {
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
return cvtFloatInt
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return cvtFloatUint
|
||||
case Float32, Float64:
|
||||
return cvtFloat
|
||||
}
|
||||
|
||||
case Complex64, Complex128:
|
||||
switch dst.Kind() {
|
||||
case Complex64, Complex128:
|
||||
return cvtComplex
|
||||
}
|
||||
|
||||
case String:
|
||||
if dst.Kind() == Slice && dst.Elem().PkgPath() == "" {
|
||||
switch dst.Elem().Kind() {
|
||||
case Uint8:
|
||||
return cvtStringBytes
|
||||
case Int32:
|
||||
return cvtStringRunes
|
||||
}
|
||||
}
|
||||
|
||||
case Slice:
|
||||
if dst.Kind() == String && src.Elem().PkgPath() == "" {
|
||||
switch src.Elem().Kind() {
|
||||
case Uint8:
|
||||
return cvtBytesString
|
||||
case Int32:
|
||||
return cvtRunesString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dst and src have same underlying type.
|
||||
if haveIdenticalUnderlyingType(dst, src) {
|
||||
return cvtDirect
|
||||
}
|
||||
|
||||
// dst and src are unnamed pointer types with same underlying base type.
|
||||
if dst.Kind() == Ptr && dst.Name() == "" &&
|
||||
src.Kind() == Ptr && src.Name() == "" &&
|
||||
haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) {
|
||||
return cvtDirect
|
||||
}
|
||||
|
||||
if implements(dst, src) {
|
||||
if src.Kind() == Interface {
|
||||
return cvtI2I
|
||||
}
|
||||
return cvtT2I
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeInt returns a Value of type t equal to bits (possibly truncated),
|
||||
// where t is a signed or unsigned int type.
|
||||
func makeInt(f flag, bits uint64, t Type) Value {
|
||||
typ := t.common()
|
||||
if typ.size > ptrSize {
|
||||
// Assume ptrSize >= 4, so this must be uint64.
|
||||
ptr := unsafe_New(t)
|
||||
*(*uint64)(unsafe.Pointer(ptr)) = bits
|
||||
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
var w iword
|
||||
switch typ.size {
|
||||
case 1:
|
||||
*(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
|
||||
case 2:
|
||||
*(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
|
||||
case 4:
|
||||
*(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
|
||||
case 8:
|
||||
*(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
|
||||
}
|
||||
return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
|
||||
// makeFloat returns a Value of type t equal to v (possibly truncated to float32),
|
||||
// where t is a float32 or float64 type.
|
||||
func makeFloat(f flag, v float64, t Type) Value {
|
||||
typ := t.common()
|
||||
if typ.size > ptrSize {
|
||||
// Assume ptrSize >= 4, so this must be float64.
|
||||
ptr := unsafe_New(t)
|
||||
*(*float64)(unsafe.Pointer(ptr)) = v
|
||||
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
|
||||
var w iword
|
||||
switch typ.size {
|
||||
case 4:
|
||||
*(*float32)(unsafe.Pointer(&w)) = float32(v)
|
||||
case 8:
|
||||
*(*float64)(unsafe.Pointer(&w)) = v
|
||||
}
|
||||
return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
|
||||
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
|
||||
// where t is a complex64 or complex128 type.
|
||||
func makeComplex(f flag, v complex128, t Type) Value {
|
||||
typ := t.common()
|
||||
if typ.size > ptrSize {
|
||||
ptr := unsafe_New(t)
|
||||
switch typ.size {
|
||||
case 8:
|
||||
*(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
|
||||
case 16:
|
||||
*(*complex128)(unsafe.Pointer(ptr)) = v
|
||||
}
|
||||
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
|
||||
// Assume ptrSize <= 8 so this must be complex64.
|
||||
var w iword
|
||||
*(*complex64)(unsafe.Pointer(&w)) = complex64(v)
|
||||
return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
|
||||
}
|
||||
|
||||
func makeString(f flag, v string, t Type) Value {
|
||||
ret := New(t).Elem()
|
||||
ret.SetString(v)
|
||||
ret.flag = ret.flag&^flagAddr | f
|
||||
return ret
|
||||
}
|
||||
|
||||
func makeBytes(f flag, v []byte, t Type) Value {
|
||||
ret := New(t).Elem()
|
||||
ret.SetBytes(v)
|
||||
ret.flag = ret.flag&^flagAddr | f
|
||||
return ret
|
||||
}
|
||||
|
||||
func makeRunes(f flag, v []rune, t Type) Value {
|
||||
ret := New(t).Elem()
|
||||
ret.setRunes(v)
|
||||
ret.flag = ret.flag&^flagAddr | f
|
||||
return ret
|
||||
}
|
||||
|
||||
// These conversion functions are returned by convertOp
|
||||
// for classes of conversions. For example, the first function, cvtInt,
|
||||
// takes any value v of signed int type and returns the value converted
|
||||
// to type t, where t is any signed or unsigned int type.
|
||||
|
||||
// convertOp: intXX -> [u]intXX
|
||||
func cvtInt(v Value, t Type) Value {
|
||||
return makeInt(v.flag&flagRO, uint64(v.Int()), t)
|
||||
}
|
||||
|
||||
// convertOp: uintXX -> [u]intXX
|
||||
func cvtUint(v Value, t Type) Value {
|
||||
return makeInt(v.flag&flagRO, v.Uint(), t)
|
||||
}
|
||||
|
||||
// convertOp: floatXX -> intXX
|
||||
func cvtFloatInt(v Value, t Type) Value {
|
||||
return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t)
|
||||
}
|
||||
|
||||
// convertOp: floatXX -> uintXX
|
||||
func cvtFloatUint(v Value, t Type) Value {
|
||||
return makeInt(v.flag&flagRO, uint64(v.Float()), t)
|
||||
}
|
||||
|
||||
// convertOp: intXX -> floatXX
|
||||
func cvtIntFloat(v Value, t Type) Value {
|
||||
return makeFloat(v.flag&flagRO, float64(v.Int()), t)
|
||||
}
|
||||
|
||||
// convertOp: uintXX -> floatXX
|
||||
func cvtUintFloat(v Value, t Type) Value {
|
||||
return makeFloat(v.flag&flagRO, float64(v.Uint()), t)
|
||||
}
|
||||
|
||||
// convertOp: floatXX -> floatXX
|
||||
func cvtFloat(v Value, t Type) Value {
|
||||
return makeFloat(v.flag&flagRO, v.Float(), t)
|
||||
}
|
||||
|
||||
// convertOp: complexXX -> complexXX
|
||||
func cvtComplex(v Value, t Type) Value {
|
||||
return makeComplex(v.flag&flagRO, v.Complex(), t)
|
||||
}
|
||||
|
||||
// convertOp: intXX -> string
|
||||
func cvtIntString(v Value, t Type) Value {
|
||||
return makeString(v.flag&flagRO, string(v.Int()), t)
|
||||
}
|
||||
|
||||
// convertOp: uintXX -> string
|
||||
func cvtUintString(v Value, t Type) Value {
|
||||
return makeString(v.flag&flagRO, string(v.Uint()), t)
|
||||
}
|
||||
|
||||
// convertOp: []byte -> string
|
||||
func cvtBytesString(v Value, t Type) Value {
|
||||
return makeString(v.flag&flagRO, string(v.Bytes()), t)
|
||||
}
|
||||
|
||||
// convertOp: string -> []byte
|
||||
func cvtStringBytes(v Value, t Type) Value {
|
||||
return makeBytes(v.flag&flagRO, []byte(v.String()), t)
|
||||
}
|
||||
|
||||
// convertOp: []rune -> string
|
||||
func cvtRunesString(v Value, t Type) Value {
|
||||
return makeString(v.flag&flagRO, string(v.runes()), t)
|
||||
}
|
||||
|
||||
// convertOp: string -> []rune
|
||||
func cvtStringRunes(v Value, t Type) Value {
|
||||
return makeRunes(v.flag&flagRO, []rune(v.String()), t)
|
||||
}
|
||||
|
||||
// convertOp: direct copy
|
||||
func cvtDirect(v Value, typ Type) Value {
|
||||
f := v.flag
|
||||
t := typ.common()
|
||||
val := v.val
|
||||
if f&flagAddr != 0 {
|
||||
// indirect, mutable word - make a copy
|
||||
ptr := unsafe_New(t)
|
||||
memmove(ptr, val, t.size)
|
||||
val = ptr
|
||||
f &^= flagAddr
|
||||
}
|
||||
return Value{t, val, v.flag&flagRO | f}
|
||||
}
|
||||
|
||||
// convertOp: concrete -> interface
|
||||
func cvtT2I(v Value, typ Type) Value {
|
||||
target := new(interface{})
|
||||
x := valueInterface(v, false)
|
||||
if typ.NumMethod() == 0 {
|
||||
*target = x
|
||||
} else {
|
||||
ifaceE2I(typ.runtimeType(), x, unsafe.Pointer(target))
|
||||
}
|
||||
return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
|
||||
}
|
||||
|
||||
// convertOp: interface -> interface
|
||||
func cvtI2I(v Value, typ Type) Value {
|
||||
if v.IsNil() {
|
||||
ret := Zero(typ)
|
||||
ret.flag |= v.flag & flagRO
|
||||
return ret
|
||||
}
|
||||
return cvtT2I(v.Elem(), typ)
|
||||
}
|
||||
|
||||
// implemented in ../pkg/runtime
|
||||
func chancap(ch iword) int32
|
||||
func chanclose(ch iword)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue