aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDamian Gryski <[email protected]>2023-03-10 23:00:12 -0800
committerAyke <[email protected]>2023-03-27 18:53:37 +0200
commit0b6bb12e9e97bd7e0709339dbc5f19094813736e (patch)
treed7b1754e8f2b43729ec4aea70c8580e5aac99642
parent72c7adf94abbc1e0f0ce946a33b12c859942b152 (diff)
downloadtinygo-0b6bb12e9e97bd7e0709339dbc5f19094813736e.tar.gz
tinygo-0b6bb12e9e97bd7e0709339dbc5f19094813736e.zip
reflect: add Convert() for string -> []byte and []byte -> string
-rw-r--r--src/reflect/value.go58
-rw-r--r--src/reflect/value_test.go8
-rw-r--r--src/runtime/string.go16
3 files changed, 82 insertions, 0 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go
index e53110bd3..76ad7718e 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1102,6 +1102,32 @@ func convertOp(src Value, typ Type) (Value, bool) {
case String:
return cvtUintString(src, rtype), true
}
+
+ case Slice:
+ if typ.Kind() == String && !src.typecode.elem().isNamed() {
+ rtype := typ.(*rawType)
+
+ switch src.Type().Elem().Kind() {
+ case Uint8:
+ return cvtBytesString(src, rtype), true
+ case Int32:
+ return cvtRunesString(src, rtype), true
+ }
+ }
+
+ // TODO(dgryski): Implement other cases
+
+ case String:
+ rtype := typ.(*rawType)
+ if typ.Kind() == Slice && !rtype.elem().isNamed() {
+ switch typ.Elem().Kind() {
+ case Uint8:
+ return cvtStringBytes(src, rtype), true
+ case Int32:
+ return cvtStringRunes(src, rtype), true
+ }
+ }
+
}
return Value{}, false
@@ -1123,6 +1149,30 @@ func cvtUintFloat(v Value, t *rawType) Value {
return makeFloat(v.flags, float64(v.Uint()), t)
}
+//go:linkname stringToBytes runtime.stringToBytesTyped
+func stringToBytes(x string) []byte
+
+func cvtStringBytes(v Value, t *rawType) Value {
+ b := stringToBytes(*(*string)(v.value))
+ return Value{
+ typecode: t,
+ value: unsafe.Pointer(&b),
+ flags: v.flags,
+ }
+}
+
+//go:linkname stringFromBytes runtime.stringFromBytesTyped
+func stringFromBytes(x []byte) string
+
+func cvtBytesString(v Value, t *rawType) Value {
+ s := stringFromBytes(*(*[]byte)(v.value))
+ return Value{
+ typecode: t,
+ value: unsafe.Pointer(&s),
+ flags: v.flags,
+ }
+}
+
func makeInt(flags valueFlags, bits uint64, t *rawType) Value {
size := t.Size()
ptr := alloc(size, nil)
@@ -1167,6 +1217,14 @@ func cvtUintString(src Value, t *rawType) Value {
panic("cvtUintString: unimplemented")
}
+func cvtStringRunes(src Value, t *rawType) Value {
+ panic("cvsStringRunes: unimplemented")
+}
+
+func cvtRunesString(src Value, t *rawType) Value {
+ panic("cvsRunesString: unimplemented")
+}
+
//go:linkname slicePanic runtime.slicePanic
func slicePanic()
diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go
index 0852617c8..e463823ef 100644
--- a/src/reflect/value_test.go
+++ b/src/reflect/value_test.go
@@ -579,6 +579,14 @@ func TestConvert(t *testing.T) {
if c.Type().Kind() != Uint8 || c.Uint() != 3 {
t.Errorf("Conver(uint64 -> byte failed: kind=%v, value=%d", c.Type().Kind().String(), c.Uint())
}
+
+ v = ValueOf("hello")
+ c = v.Convert(TypeOf([]byte("")))
+
+ if c.Type().Kind() != Slice || c.Type().Elem().Kind() != Uint8 && c.Len() != 5 && string(c.Bytes()) != "hello" {
+ t.Errorf("Conver(string -> []byte")
+ }
+
}
func equal[T comparable](a, b []T) bool {
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 13bfcd0ed..b08b96f4a 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -77,6 +77,16 @@ func stringFromBytes(x struct {
return _string{ptr: (*byte)(buf), length: x.len}
}
+func stringFromBytesTyped(x []byte) string {
+ slice := *(*struct {
+ ptr *byte
+ len uintptr
+ cap uintptr
+ })(unsafe.Pointer(&x))
+ s := stringFromBytes(slice)
+ return *(*string)(unsafe.Pointer(&s))
+}
+
// Convert a string to a []byte slice.
func stringToBytes(x _string) (slice struct {
ptr *byte
@@ -91,6 +101,12 @@ func stringToBytes(x _string) (slice struct {
return
}
+func stringToBytesTyped(x string) []byte {
+ s := *(*_string)(unsafe.Pointer(&x))
+ slice := stringToBytes(s)
+ return *(*[]byte)(unsafe.Pointer(&slice))
+}
+
// Convert a []rune slice to a string.
func stringFromRunes(runeSlice []rune) (s _string) {
// Count the number of characters that will be in the string.