1 // Copyright 2015 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proptools 16 17 import "reflect" 18 19 // TypeEqual takes two property structs, and returns true if they are of equal type, any embedded 20 // pointers to structs or interfaces having matching nilitude, and any interface{} values in any 21 // embedded structs, pointers to structs, or interfaces are also of equal type. 22 func TypeEqual(s1, s2 interface{}) bool { 23 return typeEqual(reflect.ValueOf(s1), reflect.ValueOf(s2)) 24 } 25 26 func typeEqual(v1, v2 reflect.Value) bool { 27 if v1.Type() != v2.Type() { 28 return false 29 } 30 31 if v1.Kind() == reflect.Interface { 32 if v1.IsNil() != v2.IsNil() { 33 return false 34 } 35 if v1.IsNil() { 36 return true 37 } 38 v1 = v1.Elem() 39 v2 = v2.Elem() 40 if v1.Type() != v2.Type() { 41 return false 42 } 43 } 44 45 if v1.Kind() == reflect.Ptr { 46 if v1.Type().Elem().Kind() != reflect.Struct { 47 return true 48 } 49 if v1.IsNil() != v2.IsNil() { 50 return false 51 } 52 if v1.IsNil() { 53 return true 54 } 55 v1 = v1.Elem() 56 v2 = v2.Elem() 57 } 58 59 if v1.Kind() != reflect.Struct { 60 return true 61 } 62 63 for i := 0; i < v1.NumField(); i++ { 64 v1 := v1.Field(i) 65 v2 := v2.Field(i) 66 67 switch kind := v1.Kind(); kind { 68 case reflect.Interface, reflect.Ptr, reflect.Struct: 69 if !typeEqual(v1, v2) { 70 return false 71 } 72 } 73 } 74 75 return true 76 } 77