func init() { typ := reflect.TypeOf(composite{}) alg := reflect.ValueOf(typ).Elem().FieldByName("alg").Elem() // Pretty certain that doing this voids your warranty. // This overwrites the typeAlg of either alg_NOEQ64 (on 32-bit platforms) // or alg_NOEQ128 (on 64-bit platforms), which means that all unhashable // types that were using this typeAlg are now suddenly hashable and will // attempt to use our equal/hash functions, which will lead to undefined // behaviors. But then these types shouldn't have been hashable in the // first place, so no one should have attempted to use them as keys in a // map. The compiler will emit an error if it catches someone trying to // do this, but if they do it through a map that uses an interface type as // the key, then the compiler can't catch it. // To prevent this we could instead override the alg pointer in the type, // but it's in a read-only data section in the binary (it's put there by // dcommontype() in gc/reflect.go), so changing it is also not without // perils. Basically: Here Be Dragons. areflect.ForceExport(alg.FieldByName("hash")).Set(reflect.ValueOf(hash)) areflect.ForceExport(alg.FieldByName("equal")).Set(reflect.ValueOf(equal)) }
func prettyPrintWithType(v reflect.Value, done ptrSet, depth int, showType bool) string { if depth < 0 { return "<max_depth>" } switch v.Kind() { case reflect.Invalid: return "nil" case reflect.Bool: return fmt.Sprintf("%t", v.Bool()) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64, reflect.Int, reflect.Uint, reflect.Uintptr, reflect.Complex64, reflect.Complex128: i := areflect.ForceExport(v).Interface() if showType { return fmt.Sprintf("%s(%v)", v.Type().Name(), i) } return fmt.Sprintf("%v", i) case reflect.String: return fmt.Sprintf("%q", v.String()) case reflect.Ptr: return "*" + prettyPrintWithType(v.Elem(), done, depth-1, showType) case reflect.Interface: return prettyPrintWithType(v.Elem(), done, depth-1, showType) case reflect.Map: var r []byte r = append(r, []byte(v.Type().String())...) r = append(r, '{') var elems mapEntries for _, k := range v.MapKeys() { elem := &mapEntry{ k: prettyPrint(k, done, depth-1), v: prettyPrint(v.MapIndex(k), done, depth-1), } elems.entries = append(elems.entries, elem) } sort.Sort(&elems) for i, e := range elems.entries { if i > 0 { r = append(r, []byte(", ")...) } r = append(r, []byte(e.k)...) r = append(r, ':') r = append(r, []byte(e.v)...) } r = append(r, '}') return string(r) case reflect.Struct: // Circular dependency? if v.CanAddr() { ptr := v.UnsafeAddr() if _, ok := done[ptr]; ok { return fmt.Sprintf("%s{<circular dependency>}", v.Type().String()) } done[ptr] = struct{}{} } var r []byte r = append(r, []byte(v.Type().String())...) r = append(r, '{') for i := 0; i < v.NumField(); i++ { if i > 0 { r = append(r, []byte(", ")...) } sf := v.Type().Field(i) r = append(r, sf.Name...) r = append(r, ':') r = append(r, prettyPrint(v.Field(i), done, depth-1)...) } r = append(r, '}') return string(r) case reflect.Chan: var ptr, bufsize string if v.Pointer() == 0 { ptr = "nil" } else { ptr = fmt.Sprintf("0x%x", v.Pointer()) } if v.Cap() > 0 { bufsize = fmt.Sprintf("[%d]", v.Cap()) } return fmt.Sprintf("(%s)(%s)%s", v.Type().String(), ptr, bufsize) case reflect.Func: return "func(...)" case reflect.Array, reflect.Slice: l := v.Len() var r []byte if v.Type().Elem().Kind() == reflect.Uint8 && v.Kind() != reflect.Array { b := areflect.ForceExport(v).Interface().([]byte) r = append(r, []byte(`[]byte(`)...) if b == nil { r = append(r, []byte("nil")...) } else { r = append(r, []byte(fmt.Sprintf("%q", b))...) } r = append(r, ')') return string(r) } r = append(r, []byte(v.Type().String())...) r = append(r, '{') for i := 0; i < l; i++ { if i > 0 { r = append(r, []byte(", ")...) } r = append(r, prettyPrintWithType(v.Index(i), done, depth-1, false)...) } r = append(r, '}') return string(r) case reflect.UnsafePointer: var ptr string if v.Pointer() == 0 { ptr = "nil" } else { ptr = fmt.Sprintf("0x%x", v.Pointer()) } if showType { ptr = fmt.Sprintf("(unsafe.Pointer)(%s)", ptr) } return ptr default: panic(fmt.Errorf("Unhandled kind of reflect.Value: %v", v.Kind())) } }
func diffImpl(a, b interface{}, seen map[edge]struct{}) string { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) // Check if nil if !av.IsValid() { if !bv.IsValid() { return "" // Both are "nil" with no type } return fmt.Sprintf("expected nil but got a %T: %#v", b, b) } else if !bv.IsValid() { return fmt.Sprintf("expected a %T (%#v) but got nil", a, a) } if av.Type() != bv.Type() { return fmt.Sprintf("expected a %T but got a %T", a, b) } switch a := a.(type) { case string, bool, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128, int, uint, uintptr: if a != b { typ := reflect.TypeOf(a).Name() return fmt.Sprintf("%s(%v) != %s(%v)", typ, a, typ, b) } return "" case []byte: if !bytes.Equal(a, b.([]byte)) { return fmt.Sprintf("[]byte(%q) != []byte(%q)", a, b) } } if ac, ok := a.(diffable); ok { return ac.Diff(b.(diffable)) } if ac, ok := a.(key.Comparable); ok { if ac.Equal(b.(key.Comparable)) { return "" } return fmt.Sprintf("Comparable types are different: %s vs %s", PrettyPrint(a), PrettyPrint(b)) } switch av.Kind() { case reflect.Array, reflect.Slice: l := av.Len() if l != bv.Len() { return fmt.Sprintf("Expected an array of size %d but got %d", l, bv.Len()) } for i := 0; i < l; i++ { diff := diffImpl(av.Index(i).Interface(), bv.Index(i).Interface(), seen) if len(diff) > 0 { return fmt.Sprintf("In arrays, values are different at index %d: %s", i, diff) } } case reflect.Map: if c, d := isNilCheck(av, bv); c { return d } if av.Len() != bv.Len() { return fmt.Sprintf("Maps have different size: %d != %d (%s)", av.Len(), bv.Len(), diffMapKeys(av, bv)) } for _, ka := range av.MapKeys() { ae := av.MapIndex(ka) if k := ka.Kind(); k == reflect.Ptr || k == reflect.Interface { return diffComplexKeyMap(av, bv, seen) } be := bv.MapIndex(ka) if !be.IsValid() { return fmt.Sprintf( "key %s in map is missing in the actual map", prettyPrint(ka, ptrSet{}, prettyPrintDepth)) } if !ae.CanInterface() { return fmt.Sprintf( "for key %s in map, value can't become an interface: %s", prettyPrint(ka, ptrSet{}, prettyPrintDepth), prettyPrint(ae, ptrSet{}, prettyPrintDepth)) } if !be.CanInterface() { return fmt.Sprintf( "for key %s in map, value can't become an interface: %s", prettyPrint(ka, ptrSet{}, prettyPrintDepth), prettyPrint(be, ptrSet{}, prettyPrintDepth)) } if diff := diffImpl(ae.Interface(), be.Interface(), seen); len(diff) > 0 { return fmt.Sprintf( "for key %s in map, values are different: %s", prettyPrint(ka, ptrSet{}, prettyPrintDepth), diff) } } case reflect.Ptr, reflect.Interface: if c, d := isNilCheck(av, bv); c { return d } av = av.Elem() bv = bv.Elem() if av.CanAddr() && bv.CanAddr() { e := edge{from: av.UnsafeAddr(), to: bv.UnsafeAddr()} // Detect and prevent cycles. if seen == nil { seen = make(map[edge]struct{}) } else if _, ok := seen[e]; ok { return "" } seen[e] = struct{}{} } return diffImpl(av.Interface(), bv.Interface(), seen) case reflect.Struct: typ := av.Type() for i, n := 0, av.NumField(); i < n; i++ { if typ.Field(i).Tag.Get("deepequal") == "ignore" { continue } af := areflect.ForceExport(av.Field(i)) bf := areflect.ForceExport(bv.Field(i)) if diff := diffImpl(af.Interface(), bf.Interface(), seen); len(diff) > 0 { return fmt.Sprintf("attributes %q are different: %s", av.Type().Field(i).Name, diff) } } // The following cases are here to handle named types (aka type aliases). case reflect.String: if as, bs := av.String(), bv.String(); as != bs { return fmt.Sprintf("%s(%q) != %s(%q)", av.Type().Name(), as, bv.Type().Name(), bs) } case reflect.Bool: if ab, bb := av.Bool(), bv.Bool(); ab != bb { return fmt.Sprintf("%s(%t) != %s(%t)", av.Type().Name(), ab, bv.Type().Name(), bb) } case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if ai, bi := av.Uint(), bv.Uint(); ai != bi { return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if ai, bi := av.Int(), bv.Int(); ai != bi { return fmt.Sprintf("%s(%d) != %s(%d)", av.Type().Name(), ai, bv.Type().Name(), bi) } case reflect.Float32, reflect.Float64: if af, bf := av.Float(), bv.Float(); af != bf { return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), af, bv.Type().Name(), bf) } case reflect.Complex64, reflect.Complex128: if ac, bc := av.Complex(), bv.Complex(); ac != bc { return fmt.Sprintf("%s(%f) != %s(%f)", av.Type().Name(), ac, bv.Type().Name(), bc) } default: return fmt.Sprintf("Unknown or unsupported type: %T: %#v", a, a) } return "" }
func genericDeepEqual(a, b interface{}, seen map[edge]struct{}) bool { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) if avalid, bvalid := av.IsValid(), bv.IsValid(); !avalid || !bvalid { return avalid == bvalid } if bv.Type() != av.Type() { return false } switch av.Kind() { case reflect.Ptr: if av.IsNil() || bv.IsNil() { return a == b } av = av.Elem() bv = bv.Elem() if av.CanAddr() && bv.CanAddr() { e := edge{from: av.UnsafeAddr(), to: bv.UnsafeAddr()} // Detect and prevent cycles. if seen == nil { seen = make(map[edge]struct{}) } else if _, ok := seen[e]; ok { return true } seen[e] = struct{}{} } return deepEqual(av.Interface(), bv.Interface(), seen) case reflect.Slice, reflect.Array: l := av.Len() if l != bv.Len() { return false } for i := 0; i < l; i++ { if !deepEqual(av.Index(i).Interface(), bv.Index(i).Interface(), seen) { return false } } return true case reflect.Map: if av.IsNil() != bv.IsNil() { return false } if av.Len() != bv.Len() { return false } if av.Pointer() == bv.Pointer() { return true } for _, k := range av.MapKeys() { // Upon finding the first key that's a pointer, we bail out and do // a O(N^2) comparison. if kk := k.Kind(); kk == reflect.Ptr || kk == reflect.Interface { ok, _, _ := complexKeyMapEqual(av, bv, seen) return ok } ea := av.MapIndex(k) eb := bv.MapIndex(k) if !eb.IsValid() { return false } if !deepEqual(ea.Interface(), eb.Interface(), seen) { return false } } return true case reflect.Struct: typ := av.Type() if typ.Implements(comparableType) { return av.Interface().(key.Comparable).Equal(bv.Interface()) } for i, n := 0, av.NumField(); i < n; i++ { if typ.Field(i).Tag.Get("deepequal") == "ignore" { continue } af := areflect.ForceExport(av.Field(i)) bf := areflect.ForceExport(bv.Field(i)) if !deepEqual(af.Interface(), bf.Interface(), seen) { return false } } return true default: // Other the basic types. return a == b } }