istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/util/reflect.go (about) 1 // Copyright Istio Authors 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 util 16 17 import ( 18 "fmt" 19 "reflect" 20 ) 21 22 // kindOf returns the reflection Kind that represents the dynamic type of value. 23 // If value is a nil interface value, kindOf returns reflect.Invalid. 24 func kindOf(value any) reflect.Kind { 25 if value == nil { 26 return reflect.Invalid 27 } 28 return reflect.TypeOf(value).Kind() 29 } 30 31 // IsString reports whether value is a string type. 32 func IsString(value any) bool { 33 return kindOf(value) == reflect.String 34 } 35 36 // IsPtr reports whether value is a ptr type. 37 func IsPtr(value any) bool { 38 return kindOf(value) == reflect.Ptr 39 } 40 41 // IsMap reports whether value is a map type. 42 func IsMap(value any) bool { 43 return kindOf(value) == reflect.Map 44 } 45 46 // IsMapPtr reports whether v is a map ptr type. 47 func IsMapPtr(v any) bool { 48 t := reflect.TypeOf(v) 49 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Map 50 } 51 52 // IsSlice reports whether value is a slice type. 53 func IsSlice(value any) bool { 54 return kindOf(value) == reflect.Slice 55 } 56 57 // IsStruct reports whether value is a struct type 58 func IsStruct(value any) bool { 59 return kindOf(value) == reflect.Struct 60 } 61 62 // IsSlicePtr reports whether v is a slice ptr type. 63 func IsSlicePtr(v any) bool { 64 return kindOf(v) == reflect.Ptr && reflect.TypeOf(v).Elem().Kind() == reflect.Slice 65 } 66 67 // IsSliceInterfacePtr reports whether v is a slice ptr type. 68 func IsSliceInterfacePtr(v any) bool { 69 // Must use ValueOf because Elem().Elem() type resolves dynamically. 70 vv := reflect.ValueOf(v) 71 return vv.Kind() == reflect.Ptr && vv.Elem().Kind() == reflect.Interface && vv.Elem().Elem().Kind() == reflect.Slice 72 } 73 74 // IsTypeStructPtr reports whether v is a struct ptr type. 75 func IsTypeStructPtr(t reflect.Type) bool { 76 if t == reflect.TypeOf(nil) { 77 return false 78 } 79 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct 80 } 81 82 // IsTypeSlicePtr reports whether v is a slice ptr type. 83 func IsTypeSlicePtr(t reflect.Type) bool { 84 if t == reflect.TypeOf(nil) { 85 return false 86 } 87 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Slice 88 } 89 90 // IsTypeMap reports whether v is a map type. 91 func IsTypeMap(t reflect.Type) bool { 92 if t == reflect.TypeOf(nil) { 93 return false 94 } 95 return t.Kind() == reflect.Map 96 } 97 98 // IsTypeInterface reports whether v is an interface. 99 func IsTypeInterface(t reflect.Type) bool { 100 if t == reflect.TypeOf(nil) { 101 return false 102 } 103 return t.Kind() == reflect.Interface 104 } 105 106 // IsTypeSliceOfInterface reports whether v is a slice of interface. 107 func IsTypeSliceOfInterface(t reflect.Type) bool { 108 if t == reflect.TypeOf(nil) { 109 return false 110 } 111 return t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Interface 112 } 113 114 // IsNilOrInvalidValue reports whether v is nil or reflect.Zero. 115 func IsNilOrInvalidValue(v reflect.Value) bool { 116 return !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) || IsValueNil(v.Interface()) 117 } 118 119 // IsValueNil returns true if either value is nil, or has dynamic type {ptr, 120 // map, slice} with value nil. 121 func IsValueNil(value any) bool { 122 if value == nil { 123 return true 124 } 125 switch kindOf(value) { 126 case reflect.Slice, reflect.Ptr, reflect.Map: 127 return reflect.ValueOf(value).IsNil() 128 } 129 return false 130 } 131 132 // IsValueNilOrDefault returns true if either IsValueNil(value) or the default 133 // value for the type. 134 func IsValueNilOrDefault(value any) bool { 135 if IsValueNil(value) { 136 return true 137 } 138 if !IsValueScalar(reflect.ValueOf(value)) { 139 // Default value is nil for non-scalar types. 140 return false 141 } 142 return value == reflect.New(reflect.TypeOf(value)).Elem().Interface() 143 } 144 145 // IsValuePtr reports whether v is a ptr type. 146 func IsValuePtr(v reflect.Value) bool { 147 return v.Kind() == reflect.Ptr 148 } 149 150 // IsValueInterface reports whether v is an interface type. 151 func IsValueInterface(v reflect.Value) bool { 152 return v.Kind() == reflect.Interface 153 } 154 155 // IsValueStruct reports whether v is a struct type. 156 func IsValueStruct(v reflect.Value) bool { 157 return v.Kind() == reflect.Struct 158 } 159 160 // IsValueStructPtr reports whether v is a struct ptr type. 161 func IsValueStructPtr(v reflect.Value) bool { 162 return v.Kind() == reflect.Ptr && IsValueStruct(v.Elem()) 163 } 164 165 // IsValueMap reports whether v is a map type. 166 func IsValueMap(v reflect.Value) bool { 167 return v.Kind() == reflect.Map 168 } 169 170 // IsValueSlice reports whether v is a slice type. 171 func IsValueSlice(v reflect.Value) bool { 172 return v.Kind() == reflect.Slice 173 } 174 175 // IsValueScalar reports whether v is a scalar type. 176 func IsValueScalar(v reflect.Value) bool { 177 if IsNilOrInvalidValue(v) { 178 return false 179 } 180 if IsValuePtr(v) { 181 if v.IsNil() { 182 return false 183 } 184 v = v.Elem() 185 } 186 return !IsValueStruct(v) && !IsValueMap(v) && !IsValueSlice(v) 187 } 188 189 // ValuesAreSameType returns true if v1 and v2 has the same reflect.Type, 190 // otherwise it returns false. 191 func ValuesAreSameType(v1 reflect.Value, v2 reflect.Value) bool { 192 return v1.Type() == v2.Type() 193 } 194 195 // IsEmptyString returns true if value is an empty string. 196 func IsEmptyString(value any) bool { 197 if value == nil { 198 return true 199 } 200 switch kindOf(value) { 201 case reflect.String: 202 if _, ok := value.(string); ok { 203 return value.(string) == "" 204 } 205 } 206 return false 207 } 208 209 // DeleteFromSlicePtr deletes an entry at index from the parent, which must be a slice ptr. 210 func DeleteFromSlicePtr(parentSlice any, index int) error { 211 scope.Debugf("DeleteFromSlicePtr index=%d, slice=\n%v", index, parentSlice) 212 pv := reflect.ValueOf(parentSlice) 213 214 if !IsSliceInterfacePtr(parentSlice) { 215 return fmt.Errorf("deleteFromSlicePtr parent type is %T, must be *[]interface{}", parentSlice) 216 } 217 218 pvv := pv.Elem() 219 if pvv.Kind() == reflect.Interface { 220 pvv = pvv.Elem() 221 } 222 223 pv.Elem().Set(reflect.AppendSlice(pvv.Slice(0, index), pvv.Slice(index+1, pvv.Len()))) 224 225 return nil 226 } 227 228 // UpdateSlicePtr updates an entry at index in the parent, which must be a slice ptr, with the given value. 229 func UpdateSlicePtr(parentSlice any, index int, value any) error { 230 scope.Debugf("UpdateSlicePtr parent=\n%v\n, index=%d, value=\n%v", parentSlice, index, value) 231 pv := reflect.ValueOf(parentSlice) 232 v := reflect.ValueOf(value) 233 234 if !IsSliceInterfacePtr(parentSlice) { 235 return fmt.Errorf("updateSlicePtr parent type is %T, must be *[]interface{}", parentSlice) 236 } 237 238 pvv := pv.Elem() 239 if pvv.Kind() == reflect.Interface { 240 pv.Elem().Elem().Index(index).Set(v) 241 return nil 242 } 243 pv.Elem().Index(index).Set(v) 244 245 return nil 246 } 247 248 // InsertIntoMap inserts value with key into parent which must be a map, map ptr, or interface to map. 249 func InsertIntoMap(parentMap any, key any, value any) error { 250 scope.Debugf("InsertIntoMap key=%v, value=%v, map=\n%v", key, value, parentMap) 251 v := reflect.ValueOf(parentMap) 252 kv := reflect.ValueOf(key) 253 vv := reflect.ValueOf(value) 254 255 if v.Type().Kind() == reflect.Ptr { 256 v = v.Elem() 257 } 258 if v.Type().Kind() == reflect.Interface { 259 v = v.Elem() 260 } 261 262 if v.Type().Kind() != reflect.Map { 263 scope.Debugf("error %v", v.Type().Kind()) 264 return fmt.Errorf("insertIntoMap parent type is %T, must be map", parentMap) 265 } 266 267 v.SetMapIndex(kv, vv) 268 269 return nil 270 } 271 272 // DeleteFromMap deletes an entry with the given key parent, which must be a map. 273 func DeleteFromMap(parentMap any, key any) error { 274 scope.Debugf("DeleteFromMap key=%s, parent:\n%v\n", key, parentMap) 275 pv := reflect.ValueOf(parentMap) 276 277 if !IsMap(parentMap) { 278 return fmt.Errorf("deleteFromMap parent type is %T, must be map", parentMap) 279 } 280 pv.SetMapIndex(reflect.ValueOf(key), reflect.Value{}) 281 282 return nil 283 } 284 285 // ToIntValue returns 0, false if val is not a number type, otherwise it returns the int value of val. 286 func ToIntValue(val any) (int, bool) { 287 if IsValueNil(val) { 288 return 0, false 289 } 290 v := reflect.ValueOf(val) 291 switch { 292 case IsIntKind(v.Kind()): 293 return int(v.Int()), true 294 case IsUintKind(v.Kind()): 295 return int(v.Uint()), true 296 } 297 return 0, false 298 } 299 300 // IsIntKind reports whether k is an integer kind of any size. 301 func IsIntKind(k reflect.Kind) bool { 302 switch k { 303 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 304 return true 305 } 306 return false 307 } 308 309 // IsUintKind reports whether k is an unsigned integer kind of any size. 310 func IsUintKind(k reflect.Kind) bool { 311 switch k { 312 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 313 return true 314 } 315 return false 316 }