...

Source file src/sigs.k8s.io/structured-merge-diff/v4/value/valuereflect.go

Documentation: sigs.k8s.io/structured-merge-diff/v4/value

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package value
    18  
    19  import (
    20  	"encoding/base64"
    21  	"fmt"
    22  	"reflect"
    23  )
    24  
    25  // NewValueReflect creates a Value backed by an "interface{}" type,
    26  // typically an structured object in Kubernetes world that is uses reflection to expose.
    27  // The provided "interface{}" value must be a pointer so that the value can be modified via reflection.
    28  // The provided "interface{}" may contain structs and types that are converted to Values
    29  // by the jsonMarshaler interface.
    30  func NewValueReflect(value interface{}) (Value, error) {
    31  	if value == nil {
    32  		return NewValueInterface(nil), nil
    33  	}
    34  	v := reflect.ValueOf(value)
    35  	if v.Kind() != reflect.Ptr {
    36  		// The root value to reflect on must be a pointer so that map.Set() and map.Delete() operations are possible.
    37  		return nil, fmt.Errorf("value provided to NewValueReflect must be a pointer")
    38  	}
    39  	return wrapValueReflect(v, nil, nil)
    40  }
    41  
    42  // wrapValueReflect wraps the provide reflect.Value as a value. If parent in the data tree is a map, parentMap
    43  // and parentMapKey must be provided so that the returned value may be set and deleted.
    44  func wrapValueReflect(value reflect.Value, parentMap, parentMapKey *reflect.Value) (Value, error) {
    45  	val := HeapAllocator.allocValueReflect()
    46  	return val.reuse(value, nil, parentMap, parentMapKey)
    47  }
    48  
    49  // wrapValueReflect wraps the provide reflect.Value as a value, and panics if there is an error. If parent in the data
    50  // tree is a map, parentMap and parentMapKey must be provided so that the returned value may be set and deleted.
    51  func mustWrapValueReflect(value reflect.Value, parentMap, parentMapKey *reflect.Value) Value {
    52  	v, err := wrapValueReflect(value, parentMap, parentMapKey)
    53  	if err != nil {
    54  		panic(err)
    55  	}
    56  	return v
    57  }
    58  
    59  // the value interface doesn't care about the type for value.IsNull, so we can use a constant
    60  var nilType = reflect.TypeOf(&struct{}{})
    61  
    62  // reuse replaces the value of the valueReflect. If parent in the data tree is a map, parentMap and parentMapKey
    63  // must be provided so that the returned value may be set and deleted.
    64  func (r *valueReflect) reuse(value reflect.Value, cacheEntry *TypeReflectCacheEntry, parentMap, parentMapKey *reflect.Value) (Value, error) {
    65  	if cacheEntry == nil {
    66  		cacheEntry = TypeReflectEntryOf(value.Type())
    67  	}
    68  	if cacheEntry.CanConvertToUnstructured() {
    69  		u, err := cacheEntry.ToUnstructured(value)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  		if u == nil {
    74  			value = reflect.Zero(nilType)
    75  		} else {
    76  			value = reflect.ValueOf(u)
    77  		}
    78  	}
    79  	r.Value = dereference(value)
    80  	r.ParentMap = parentMap
    81  	r.ParentMapKey = parentMapKey
    82  	r.kind = kind(r.Value)
    83  	return r, nil
    84  }
    85  
    86  // mustReuse replaces the value of the valueReflect and panics if there is an error. If parent in the data tree is a
    87  // map, parentMap and parentMapKey must be provided so that the returned value may be set and deleted.
    88  func (r *valueReflect) mustReuse(value reflect.Value, cacheEntry *TypeReflectCacheEntry, parentMap, parentMapKey *reflect.Value) Value {
    89  	v, err := r.reuse(value, cacheEntry, parentMap, parentMapKey)
    90  	if err != nil {
    91  		panic(err)
    92  	}
    93  	return v
    94  }
    95  
    96  func dereference(val reflect.Value) reflect.Value {
    97  	kind := val.Kind()
    98  	if (kind == reflect.Interface || kind == reflect.Ptr) && !safeIsNil(val) {
    99  		return val.Elem()
   100  	}
   101  	return val
   102  }
   103  
   104  type valueReflect struct {
   105  	ParentMap    *reflect.Value
   106  	ParentMapKey *reflect.Value
   107  	Value        reflect.Value
   108  	kind         reflectType
   109  }
   110  
   111  func (r valueReflect) IsMap() bool {
   112  	return r.kind == mapType || r.kind == structMapType
   113  }
   114  
   115  func (r valueReflect) IsList() bool {
   116  	return r.kind == listType
   117  }
   118  
   119  func (r valueReflect) IsBool() bool {
   120  	return r.kind == boolType
   121  }
   122  
   123  func (r valueReflect) IsInt() bool {
   124  	return r.kind == intType || r.kind == uintType
   125  }
   126  
   127  func (r valueReflect) IsFloat() bool {
   128  	return r.kind == floatType
   129  }
   130  
   131  func (r valueReflect) IsString() bool {
   132  	return r.kind == stringType || r.kind == byteStringType
   133  }
   134  
   135  func (r valueReflect) IsNull() bool {
   136  	return r.kind == nullType
   137  }
   138  
   139  type reflectType = int
   140  
   141  const (
   142  	mapType = iota
   143  	structMapType
   144  	listType
   145  	intType
   146  	uintType
   147  	floatType
   148  	stringType
   149  	byteStringType
   150  	boolType
   151  	nullType
   152  )
   153  
   154  func kind(v reflect.Value) reflectType {
   155  	typ := v.Type()
   156  	rk := typ.Kind()
   157  	switch rk {
   158  	case reflect.Map:
   159  		if v.IsNil() {
   160  			return nullType
   161  		}
   162  		return mapType
   163  	case reflect.Struct:
   164  		return structMapType
   165  	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
   166  		return intType
   167  	case reflect.Uint, reflect.Uint32, reflect.Uint16, reflect.Uint8:
   168  		// Uint64 deliberately excluded, see valueUnstructured.Int.
   169  		return uintType
   170  	case reflect.Float64, reflect.Float32:
   171  		return floatType
   172  	case reflect.String:
   173  		return stringType
   174  	case reflect.Bool:
   175  		return boolType
   176  	case reflect.Slice:
   177  		if v.IsNil() {
   178  			return nullType
   179  		}
   180  		elemKind := typ.Elem().Kind()
   181  		if elemKind == reflect.Uint8 {
   182  			return byteStringType
   183  		}
   184  		return listType
   185  	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.UnsafePointer, reflect.Interface:
   186  		if v.IsNil() {
   187  			return nullType
   188  		}
   189  		panic(fmt.Sprintf("unsupported type: %v", v.Type()))
   190  	default:
   191  		panic(fmt.Sprintf("unsupported type: %v", v.Type()))
   192  	}
   193  }
   194  
   195  // TODO find a cleaner way to avoid panics from reflect.IsNil()
   196  func safeIsNil(v reflect.Value) bool {
   197  	k := v.Kind()
   198  	switch k {
   199  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
   200  		return v.IsNil()
   201  	}
   202  	return false
   203  }
   204  
   205  func (r valueReflect) AsMap() Map {
   206  	return r.AsMapUsing(HeapAllocator)
   207  }
   208  
   209  func (r valueReflect) AsMapUsing(a Allocator) Map {
   210  	switch r.kind {
   211  	case structMapType:
   212  		v := a.allocStructReflect()
   213  		v.valueReflect = r
   214  		return v
   215  	case mapType:
   216  		v := a.allocMapReflect()
   217  		v.valueReflect = r
   218  		return v
   219  	default:
   220  		panic("value is not a map or struct")
   221  	}
   222  }
   223  
   224  func (r valueReflect) AsList() List {
   225  	return r.AsListUsing(HeapAllocator)
   226  }
   227  
   228  func (r valueReflect) AsListUsing(a Allocator) List {
   229  	if r.IsList() {
   230  		v := a.allocListReflect()
   231  		v.Value = r.Value
   232  		return v
   233  	}
   234  	panic("value is not a list")
   235  }
   236  
   237  func (r valueReflect) AsBool() bool {
   238  	if r.IsBool() {
   239  		return r.Value.Bool()
   240  	}
   241  	panic("value is not a bool")
   242  }
   243  
   244  func (r valueReflect) AsInt() int64 {
   245  	if r.kind == intType {
   246  		return r.Value.Int()
   247  	}
   248  	if r.kind == uintType {
   249  		return int64(r.Value.Uint())
   250  	}
   251  
   252  	panic("value is not an int")
   253  }
   254  
   255  func (r valueReflect) AsFloat() float64 {
   256  	if r.IsFloat() {
   257  		return r.Value.Float()
   258  	}
   259  	panic("value is not a float")
   260  }
   261  
   262  func (r valueReflect) AsString() string {
   263  	switch r.kind {
   264  	case stringType:
   265  		return r.Value.String()
   266  	case byteStringType:
   267  		return base64.StdEncoding.EncodeToString(r.Value.Bytes())
   268  	}
   269  	panic("value is not a string")
   270  }
   271  
   272  func (r valueReflect) Unstructured() interface{} {
   273  	val := r.Value
   274  	switch {
   275  	case r.IsNull():
   276  		return nil
   277  	case val.Kind() == reflect.Struct:
   278  		return structReflect{r}.Unstructured()
   279  	case val.Kind() == reflect.Map:
   280  		return mapReflect{valueReflect: r}.Unstructured()
   281  	case r.IsList():
   282  		return listReflect{r.Value}.Unstructured()
   283  	case r.IsString():
   284  		return r.AsString()
   285  	case r.IsInt():
   286  		return r.AsInt()
   287  	case r.IsBool():
   288  		return r.AsBool()
   289  	case r.IsFloat():
   290  		return r.AsFloat()
   291  	default:
   292  		panic(fmt.Sprintf("value of type %s is not a supported by value reflector", val.Type()))
   293  	}
   294  }
   295  

View as plain text