// Copyright 2015-2016 trivago GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package treflect import ( "fmt" "reflect" "unsafe" ) // GetMissingMethods checks if a given object implements all methods of a // given interface. It returns the interface coverage [0..1] as well as an array // of error messages. If the interface is correctly implemented the coverage is // 1 and the error message array is empty. func GetMissingMethods(objType reflect.Type, ifaceType reflect.Type) (float32, []string) { missing := []string{} if objType.Implements(ifaceType) { return 1.0, missing } methodCount := ifaceType.NumMethod() for mIdx := 0; mIdx < methodCount; mIdx++ { ifaceMethod := ifaceType.Method(mIdx) objMethod, exists := objType.MethodByName(ifaceMethod.Name) signatureMismatch := false switch { case !exists: missing = append(missing, fmt.Sprintf("Missing: \"%s\" %v", ifaceMethod.Name, ifaceMethod.Type)) continue // ### continue, error found ### case ifaceMethod.Type.NumOut() != objMethod.Type.NumOut(): signatureMismatch = true case ifaceMethod.Type.NumIn()+1 != objMethod.Type.NumIn(): signatureMismatch = true default: for oIdx := 0; !signatureMismatch && oIdx < ifaceMethod.Type.NumOut(); oIdx++ { signatureMismatch = ifaceMethod.Type.Out(oIdx) != objMethod.Type.Out(oIdx) } for iIdx := 0; !signatureMismatch && iIdx < ifaceMethod.Type.NumIn(); iIdx++ { signatureMismatch = ifaceMethod.Type.In(iIdx) != objMethod.Type.In(iIdx+1) } } if signatureMismatch { missing = append(missing, fmt.Sprintf("Invalid: \"%s\" %v is not %v", ifaceMethod.Name, objMethod.Type, ifaceMethod.Type)) } } return float32(methodCount-len(missing)) / float32(methodCount), missing } // Int64 converts any signed number type to an int64. // The second parameter is returned as false if a non-number type was given. func Int64(v interface{}) (int64, bool) { switch reflect.TypeOf(v).Kind() { case reflect.Int: return int64(v.(int)), true case reflect.Int8: return int64(v.(int8)), true case reflect.Int16: return int64(v.(int16)), true case reflect.Int32: return int64(v.(int32)), true case reflect.Int64: return v.(int64), true case reflect.Float32: return int64(v.(float32)), true case reflect.Float64: return int64(v.(float64)), true } fmt.Printf("%t\n%#v\n%#v\n", v, v, reflect.TypeOf(v).Kind()) return 0, false } // Uint64 converts any unsigned number type to an uint64. // The second parameter is returned as false if a non-number type was given. func Uint64(v interface{}) (uint64, bool) { switch reflect.TypeOf(v).Kind() { case reflect.Uint: return uint64(v.(uint)), true case reflect.Uint8: return uint64(v.(uint8)), true case reflect.Uint16: return uint64(v.(uint16)), true case reflect.Uint32: return uint64(v.(uint32)), true case reflect.Uint64: return v.(uint64), true } return 0, false } // Float32 converts any number type to an float32. // The second parameter is returned as false if a non-number type was given. func Float32(v interface{}) (float32, bool) { switch reflect.TypeOf(v).Kind() { case reflect.Int: return float32(v.(int)), true case reflect.Uint: return float32(v.(uint)), true case reflect.Int8: return float32(v.(int8)), true case reflect.Uint8: return float32(v.(uint8)), true case reflect.Int16: return float32(v.(int16)), true case reflect.Uint16: return float32(v.(uint16)), true case reflect.Int32: return float32(v.(int32)), true case reflect.Uint32: return float32(v.(uint32)), true case reflect.Int64: return float32(v.(int64)), true case reflect.Uint64: return float32(v.(uint64)), true case reflect.Float32: return v.(float32), true case reflect.Float64: return float32(v.(float64)), true } return 0, false } // Float64 converts any number type to an float64. // The second parameter is returned as false if a non-number type was given. func Float64(v interface{}) (float64, bool) { switch reflect.TypeOf(v).Kind() { case reflect.Int: return float64(v.(int)), true case reflect.Uint: return float64(v.(uint)), true case reflect.Int8: return float64(v.(int8)), true case reflect.Uint8: return float64(v.(uint8)), true case reflect.Int16: return float64(v.(int16)), true case reflect.Uint16: return float64(v.(uint16)), true case reflect.Int32: return float64(v.(int32)), true case reflect.Uint32: return float64(v.(uint32)), true case reflect.Int64: return float64(v.(int64)), true case reflect.Uint64: return float64(v.(uint64)), true case reflect.Float32: return float64(v.(float32)), true case reflect.Float64: return v.(float64), true } return 0, false } // RemovePtrFromType will return the type of t and strips away any pointer(s) // in front of the actual type. func RemovePtrFromType(t interface{}) reflect.Type { var v reflect.Type if rt, isType := t.(reflect.Type); isType { v = rt } else { v = reflect.TypeOf(t) } for v.Kind() == reflect.Ptr { v = v.Elem() } return v } // RemovePtrFromValue will return the value of t and strips away any pointer(s) // in front of the actual type. func RemovePtrFromValue(t interface{}) reflect.Value { var v reflect.Value if rv, isValue := t.(reflect.Value); isValue { v = rv } else { v = reflect.ValueOf(t) } for v.Type().Kind() == reflect.Ptr { v = v.Elem() } return v } // UnsafeCopy will copy data from src to dst while ignoring type information. // Both types need to be of the same size and dst and src have to be pointers. // UnsafeCopy will panic if these requirements are not met. func UnsafeCopy(dst, src interface{}) { dstValue := reflect.ValueOf(dst) srcValue := reflect.ValueOf(src) UnsafeCopyValue(dstValue, srcValue) } // UnsafeCopyValue will copy data from src to dst while ignoring type // information. Both types need to be of the same size or this function will // panic. Also both types must support dereferencing via reflect.Elem() func UnsafeCopyValue(dstValue reflect.Value, srcValue reflect.Value) { dstType := dstValue.Elem().Type() srcType := srcValue.Type() var srcPtr uintptr if srcValue.Kind() != reflect.Ptr { // If we don't get a pointer to our source data we need to forcefully // retrieve it by accessing the interface pointer. This is ok as we // only read from it. iface := srcValue.Interface() srcPtr = reflect.ValueOf(&iface).Elem().InterfaceData()[1] // Pointer to data } else { srcType = srcValue.Elem().Type() srcPtr = srcValue.Pointer() } if dstType.Size() != srcType.Size() { panic("Type size mismatch between " + dstType.String() + " and " + srcType.String()) } dstAsSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ Data: dstValue.Pointer(), Len: int(dstType.Size()), Cap: int(dstType.Size()), })) srcAsSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ Data: srcPtr, Len: int(srcType.Size()), Cap: int(srcType.Size()), })) copy(dstAsSlice, srcAsSlice) } // SetMemberByName sets member name of the given pointer-to-struct to the data // passed to this function. The member may be private, too. func SetMemberByName(ptrToStruct interface{}, name string, data interface{}) { structVal := reflect.Indirect(reflect.ValueOf(ptrToStruct)) member := structVal.FieldByName(name) SetValue(member, data) } // SetMemberByIndex sets member idx of the given pointer-to-struct to the data // passed to this function. The member may be private, too. func SetMemberByIndex(ptrToStruct interface{}, idx int, data interface{}) { structVal := reflect.Indirect(reflect.ValueOf(ptrToStruct)) member := structVal.Field(idx) SetValue(member, data) } // SetValue sets an addressable value to the data passed to this function. // In contrast to golangs reflect package this will also work with private // variables. Please note that this function may not support all types, yet. func SetValue(member reflect.Value, data interface{}) { if member.CanSet() { member.Set(reflect.ValueOf(data).Convert(member.Type())) return // ### return, easy way ### } if !member.CanAddr() { panic("SetValue requires addressable member type") } ptrToMember := unsafe.Pointer(member.UnsafeAddr()) dataValue := reflect.ValueOf(data) switch member.Kind() { case reflect.Bool: *(*bool)(ptrToMember) = dataValue.Bool() case reflect.Uint: *(*uint)(ptrToMember) = uint(dataValue.Uint()) case reflect.Uint8: *(*uint8)(ptrToMember) = uint8(dataValue.Uint()) case reflect.Uint16: *(*uint16)(ptrToMember) = uint16(dataValue.Uint()) case reflect.Uint32: *(*uint32)(ptrToMember) = uint32(dataValue.Uint()) case reflect.Uint64: *(*uint64)(ptrToMember) = dataValue.Uint() case reflect.Int: *(*int)(ptrToMember) = int(dataValue.Int()) case reflect.Int8: *(*int8)(ptrToMember) = int8(dataValue.Int()) case reflect.Int16: *(*int16)(ptrToMember) = int16(dataValue.Int()) case reflect.Int32: *(*int32)(ptrToMember) = int32(dataValue.Int()) case reflect.Int64: *(*int64)(ptrToMember) = dataValue.Int() case reflect.Float32: *(*float32)(ptrToMember) = float32(dataValue.Float()) case reflect.Float64: *(*float64)(ptrToMember) = dataValue.Float() case reflect.Complex64: *(*complex64)(ptrToMember) = complex64(dataValue.Complex()) case reflect.Complex128: *(*complex128)(ptrToMember) = dataValue.Complex() case reflect.String: *(*string)(ptrToMember) = dataValue.String() case reflect.Map, reflect.Chan: // Exploit the fact that "map" is actually "*runtime.hmap" and force // overwrite that pointer in the passed struct. // Same foes for "chan" which is actually "*runtime.hchan". // Note: Assigning a map or channel to another variable does NOT copy // the contents so copying the pointer follows go's standard behavior. dataAsPtr := unsafe.Pointer(dataValue.Pointer()) *(**uintptr)(ptrToMember) = (*uintptr)(dataAsPtr) case reflect.Interface: // Interfaces are basically two pointers, see runtime.iface. // We want to modify exactly that data, which is returned by // the InterfaceData() method. if dataValue.Kind() != reflect.Interface { // A type reference was passed. In order to overwrite the memory // Representation of an interface we need to generate it first. // Reflect does not allow us to do that unless we use the // InterfaceData method which exposes the internal representation // of an interface. interfaceData := reflect.ValueOf(&data).Elem().InterfaceData() dataValue = reflect.ValueOf(interfaceData) } fallthrough default: // Complex types are assigned memcpy style. // Note: This should not break the garbage collector although we cannot // be 100% sure on this. UnsafeCopyValue(member.Addr(), dataValue) } }