reflect: add Convert() for string -> []byte and []byte -> string

Этот коммит содержится в:
Damian Gryski 2023-03-10 23:00:12 -08:00 коммит произвёл Ayke
родитель 72c7adf94a
коммит 0b6bb12e9e
3 изменённых файлов: 82 добавлений и 0 удалений

Просмотреть файл

@ -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()

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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.