diff options
author | Damian Gryski <[email protected]> | 2023-03-10 23:00:12 -0800 |
---|---|---|
committer | Ayke <[email protected]> | 2023-03-27 18:53:37 +0200 |
commit | 0b6bb12e9e97bd7e0709339dbc5f19094813736e (patch) | |
tree | d7b1754e8f2b43729ec4aea70c8580e5aac99642 | |
parent | 72c7adf94abbc1e0f0ce946a33b12c859942b152 (diff) | |
download | tinygo-0b6bb12e9e97bd7e0709339dbc5f19094813736e.tar.gz tinygo-0b6bb12e9e97bd7e0709339dbc5f19094813736e.zip |
reflect: add Convert() for string -> []byte and []byte -> string
-rw-r--r-- | src/reflect/value.go | 58 | ||||
-rw-r--r-- | src/reflect/value_test.go | 8 | ||||
-rw-r--r-- | src/runtime/string.go | 16 |
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. |