diff options
Diffstat (limited to 'src/reflect/value.go')
-rw-r--r-- | src/reflect/value.go | 72 |
1 files changed, 62 insertions, 10 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index d1f8cb2f7..78453be34 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -689,6 +689,25 @@ func (v Value) Cap() int { } } +//go:linkname mapclear runtime.hashmapClear +func mapclear(p unsafe.Pointer) + +// Clear clears the contents of a map or zeros the contents of a slice +// +// It panics if v's Kind is not Map or Slice. +func (v Value) Clear() { + switch v.typecode.Kind() { + case Map: + mapclear(v.pointer()) + case Slice: + hdr := (*sliceHeader)(v.value) + elemSize := v.typecode.underlying().elem().Size() + memzero(hdr.data, elemSize*hdr.len) + default: + panic(&ValueError{Method: "Clear", Kind: v.Kind()}) + } +} + // NumField returns the number of fields of this struct. It panics for other // value types. func (v Value) NumField() int { @@ -888,6 +907,9 @@ func (v Value) Index(i int) Value { } func (v Value) NumMethod() int { + if v.typecode == nil { + panic(&ValueError{Method: "reflect.Value.NumMethod", Kind: Invalid}) + } return v.typecode.NumMethod() } @@ -1062,7 +1084,7 @@ func (v Value) Set(x Value) { v.checkAddressable() v.checkRO() if !x.typecode.AssignableTo(v.typecode) { - panic("reflect: cannot set") + panic("reflect.Value.Set: value of type " + x.typecode.String() + " cannot be assigned to type " + v.typecode.String()) } if v.typecode.Kind() == Interface && x.typecode.Kind() != Interface { @@ -1240,7 +1262,9 @@ func (v Value) OverflowUint(x uint64) bool { } func (v Value) CanConvert(t Type) bool { - panic("unimplemented: (reflect.Value).CanConvert()") + // TODO: Optimize this to not actually perform a conversion + _, ok := convertOp(v, t) + return ok } func (v Value) Convert(t Type) Value { @@ -1262,6 +1286,15 @@ func convertOp(src Value, typ Type) (Value, bool) { }, true } + if rtype := typ.(*rawType); rtype.Kind() == Interface && rtype.NumMethod() == 0 { + iface := composeInterface(unsafe.Pointer(src.typecode), src.value) + return Value{ + typecode: rtype, + value: unsafe.Pointer(&iface), + flags: valueFlagExported, + }, true + } + switch src.Kind() { case Int, Int8, Int16, Int32, Int64: switch rtype := typ.(*rawType); rtype.Kind() { @@ -1302,14 +1335,33 @@ func convertOp(src Value, typ Type) (Value, bool) { */ 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 + switch rtype := typ.(*rawType); rtype.Kind() { + case Array: + if src.typecode.elem() == rtype.elem() && rtype.Len() <= src.Len() { + return Value{ + typecode: rtype, + value: (*sliceHeader)(src.value).data, + flags: src.flags | valueFlagIndirect, + }, true + } + case Pointer: + if rtype.Elem().Kind() == Array { + if src.typecode.elem() == rtype.elem().elem() && rtype.elem().Len() <= src.Len() { + return Value{ + typecode: rtype, + value: (*sliceHeader)(src.value).data, + flags: src.flags & (valueFlagExported | valueFlagRO), + }, true + } + } + case String: + if !src.typecode.elem().isNamed() { + switch src.Type().Elem().Kind() { + case Uint8: + return cvtBytesString(src, rtype), true + case Int32: + return cvtRunesString(src, rtype), true + } } } |