diff options
author | Damian Gryski <[email protected]> | 2023-03-10 16:33:32 -0800 |
---|---|---|
committer | Ayke <[email protected]> | 2023-03-27 18:53:37 +0200 |
commit | 72c7adf94abbc1e0f0ce946a33b12c859942b152 (patch) | |
tree | b4b1eba419324181542ceb6ca4ef311a402df3b1 | |
parent | 13fb5aa7e798682bce72adf7d960704cc09b302a (diff) | |
download | tinygo-72c7adf94abbc1e0f0ce946a33b12c859942b152.tar.gz tinygo-72c7adf94abbc1e0f0ce946a33b12c859942b152.zip |
reflect: Convert() for integer and float types
-rw-r--r-- | src/reflect/value.go | 92 | ||||
-rw-r--r-- | src/reflect/value_test.go | 9 |
2 files changed, 100 insertions, 1 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index 384e67b12..e53110bd3 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1074,7 +1074,97 @@ func (v Value) CanConvert(t Type) bool { } func (v Value) Convert(t Type) Value { - panic("unimplemented: (reflect.Value).Convert()") + if v, ok := convertOp(v, t); ok { + return v + } + + panic("reflect.Value.Convert: value of type " + v.typecode.String() + " cannot be converted to type " + t.String()) +} + +func convertOp(src Value, typ Type) (Value, bool) { + switch src.Kind() { + case Int, Int8, Int16, Int32, Int64: + switch rtype := typ.(*rawType); rtype.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtInt(src, rtype), true + case Float32, Float64: + return cvtIntFloat(src, rtype), true + case String: + return cvtIntString(src, rtype), true + } + + case Uint, Uint8, Uint16, Uint32, Uint64: + switch rtype := typ.(*rawType); rtype.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return cvtUint(src, rtype), true + case Float32, Float64: + return cvtUintFloat(src, rtype), true + case String: + return cvtUintString(src, rtype), true + } + } + + return Value{}, false +} + +func cvtInt(v Value, t *rawType) Value { + return makeInt(v.flags, uint64(v.Int()), t) +} + +func cvtUint(v Value, t *rawType) Value { + return makeInt(v.flags, v.Uint(), t) +} + +func cvtIntFloat(v Value, t *rawType) Value { + return makeFloat(v.flags, float64(v.Int()), t) +} + +func cvtUintFloat(v Value, t *rawType) Value { + return makeFloat(v.flags, float64(v.Uint()), t) +} + +func makeInt(flags valueFlags, bits uint64, t *rawType) Value { + size := t.Size() + ptr := alloc(size, nil) + switch size { + case 1: + *(*uint8)(ptr) = uint8(bits) + case 2: + *(*uint16)(ptr) = uint16(bits) + case 4: + *(*uint32)(ptr) = uint32(bits) + case 8: + *(*uint64)(ptr) = bits + } + return Value{ + typecode: t, + value: ptr, + flags: flags | valueFlagIndirect, + } +} + +func makeFloat(flags valueFlags, v float64, t *rawType) Value { + size := t.Size() + ptr := alloc(size, nil) + switch size { + case 4: + *(*float32)(ptr) = float32(v) + case 8: + *(*float64)(ptr) = v + } + return Value{ + typecode: t, + value: ptr, + flags: flags | valueFlagIndirect, + } +} + +func cvtIntString(src Value, t *rawType) Value { + panic("cvtUintString: unimplemented") +} + +func cvtUintString(src Value, t *rawType) Value { + panic("cvtUintString: unimplemented") } //go:linkname slicePanic runtime.slicePanic diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index fd9d6aaf9..0852617c8 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -572,6 +572,15 @@ func TestAssignableTo(t *testing.T) { } } +func TestConvert(t *testing.T) { + v := ValueOf(int64(3)) + c := v.Convert(TypeOf(byte(0))) + + if c.Type().Kind() != Uint8 || c.Uint() != 3 { + t.Errorf("Conver(uint64 -> byte failed: kind=%v, value=%d", c.Type().Kind().String(), c.Uint()) + } +} + func equal[T comparable](a, b []T) bool { if len(a) != len(b) { return false |