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  }