aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDamian Gryski <[email protected]>2023-03-10 16:33:32 -0800
committerAyke <[email protected]>2023-03-27 18:53:37 +0200
commit72c7adf94abbc1e0f0ce946a33b12c859942b152 (patch)
treeb4b1eba419324181542ceb6ca4ef311a402df3b1
parent13fb5aa7e798682bce72adf7d960704cc09b302a (diff)
downloadtinygo-72c7adf94abbc1e0f0ce946a33b12c859942b152.tar.gz
tinygo-72c7adf94abbc1e0f0ce946a33b12c859942b152.zip
reflect: Convert() for integer and float types
-rw-r--r--src/reflect/value.go92
-rw-r--r--src/reflect/value_test.go9
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