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 15package proptools 16 17import "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. 22func TypeEqual(s1, s2 interface{}) bool { 23 return typeEqual(reflect.ValueOf(s1), reflect.ValueOf(s2)) 24} 25 26func 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