Commit 46f379cc authored by Russ Cox's avatar Russ Cox

reflect: add Type.ConvertibleTo, Value.Convert (API CHANGE)

Fixes #4047.

R=iant, r
CC=golang-dev
https://golang.org/cl/6500065
parent 49aa74ef
This diff is collapsed.
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflect
// MakeRO returns a copy of v with the read-only flag set.
func MakeRO(v Value) Value {
v.flag |= flagRO
return v
}
// IsRO reports whether v's read-only flag is set.
func IsRO(v Value) bool {
return v.flag&flagRO != 0
}
...@@ -92,6 +92,9 @@ type Type interface { ...@@ -92,6 +92,9 @@ type Type interface {
// AssignableTo returns true if a value of the type is assignable to type u. // AssignableTo returns true if a value of the type is assignable to type u.
AssignableTo(u Type) bool AssignableTo(u Type) bool
// ConvertibleTo returns true if a value of the type is convertible to type u.
ConvertibleTo(u Type) bool
// Methods applicable only to some types, depending on Kind. // Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are: // The methods allowed for each kind are:
// //
...@@ -1096,6 +1099,14 @@ func (t *commonType) AssignableTo(u Type) bool { ...@@ -1096,6 +1099,14 @@ func (t *commonType) AssignableTo(u Type) bool {
return directlyAssignable(uu, t) || implements(uu, t) return directlyAssignable(uu, t) || implements(uu, t)
} }
func (t *commonType) ConvertibleTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.(*commonType)
return convertOp(uu, t) != nil
}
// implements returns true if the type V implements the interface type T. // implements returns true if the type V implements the interface type T.
func implements(T, V *commonType) bool { func implements(T, V *commonType) bool {
if T.Kind() != Interface { if T.Kind() != Interface {
...@@ -1167,10 +1178,28 @@ func directlyAssignable(T, V *commonType) bool { ...@@ -1167,10 +1178,28 @@ func directlyAssignable(T, V *commonType) bool {
return false return false
} }
// x's type T and V have identical underlying types. // x's type T and V must have identical underlying types.
// Since at least one is unnamed, only the composite types return haveIdenticalUnderlyingType(T, V)
// need to be considered. }
switch T.Kind() {
func haveIdenticalUnderlyingType(T, V *commonType) bool {
if T == V {
return true
}
kind := T.Kind()
if kind != V.Kind() {
return false
}
// Non-composite types of equal kind have same underlying type
// (the predefined instance of the type).
if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
return true
}
// Composite types.
switch kind {
case Array: case Array:
return T.Elem() == V.Elem() && T.Len() == V.Len() return T.Elem() == V.Elem() && T.Len() == V.Len()
......
...@@ -302,6 +302,17 @@ func (v Value) Bytes() []byte { ...@@ -302,6 +302,17 @@ func (v Value) Bytes() []byte {
return *(*[]byte)(v.val) 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. // 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 // Such values are called addressable. A value is addressable if it is
// an element of a slice, an element of an addressable array, // an element of a slice, an element of an addressable array,
...@@ -1221,6 +1232,17 @@ func (v Value) SetBytes(x []byte) { ...@@ -1221,6 +1232,17 @@ func (v Value) SetBytes(x []byte) {
*(*[]byte)(v.val) = x *(*[]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. // SetComplex sets v's underlying value to x.
// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false. // It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false.
func (v Value) SetComplex(x complex128) { func (v Value) SetComplex(x complex128) {
...@@ -1916,6 +1938,302 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va ...@@ -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()) 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 // implemented in ../pkg/runtime
func chancap(ch iword) int32 func chancap(ch iword) int32
func chanclose(ch iword) func chanclose(ch iword)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment