github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/syntax/reflect.go (about)

     1  /*
     2  Copyright 2022 The Katalyst 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 syntax
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"reflect"
    23  )
    24  
    25  // MergeValueFunc is to merge src value to dst
    26  type MergeValueFunc func(src reflect.Value, dst reflect.Value) error
    27  
    28  // SetSliceOrArrayValue append src slice or array to the end of dst
    29  func SetSliceOrArrayValue(src reflect.Value, dst reflect.Value) {
    30  	if src.Type() != dst.Type() ||
    31  		(src.Kind() != reflect.Slice && src.Kind() != reflect.Array) {
    32  		return
    33  	}
    34  
    35  	// initialize a new slice
    36  	newSlice := reflect.New(dst.Type()).Elem()
    37  
    38  	for i := 0; i < dst.Len(); i++ {
    39  		if dst.Index(i).Kind() == reflect.Ptr && dst.Index(i).IsNil() {
    40  			continue
    41  		}
    42  
    43  		newSlice = reflect.Append(newSlice, dst.Index(i))
    44  	}
    45  
    46  	for i := 0; i < src.Len(); i++ {
    47  		if src.Index(i).Kind() == reflect.Ptr && src.Index(i).IsNil() {
    48  			continue
    49  		}
    50  
    51  		newSlice = reflect.Append(newSlice, src.Index(i))
    52  	}
    53  
    54  	// set dst slice with the new slice
    55  	dst.Set(newSlice)
    56  }
    57  
    58  // SetMapValue set all key and value from src map to dst map, and the value of
    59  // same key in the dst map will be overwritten
    60  func SetMapValue(src reflect.Value, dst reflect.Value) {
    61  	if src.Type() != dst.Type() ||
    62  		src.Kind() != reflect.Map {
    63  		return
    64  	}
    65  
    66  	// initialize a new map
    67  	newMap := reflect.MakeMap(dst.Type())
    68  
    69  	// set key and value of dst map to the new map
    70  	iter := dst.MapRange()
    71  	for iter.Next() {
    72  		newMap.SetMapIndex(iter.Key(), iter.Value())
    73  	}
    74  
    75  	// set key and value of src map to the new map
    76  	iter = src.MapRange()
    77  	for iter.Next() {
    78  		newMap.SetMapIndex(iter.Key(), iter.Value())
    79  	}
    80  
    81  	// set dst with the new map
    82  	dst.Set(newMap)
    83  }
    84  
    85  // ParseBytesByType parse []byte to a value with type t
    86  func ParseBytesByType(b []byte, t reflect.Type) (reflect.Value, error) {
    87  	newType := t
    88  	if t.Kind() == reflect.Ptr {
    89  		newType = t.Elem()
    90  	}
    91  
    92  	res := reflect.New(newType)
    93  	ptr := res.Interface()
    94  
    95  	err := json.Unmarshal(b, &ptr)
    96  	if err != nil {
    97  		return reflect.Value{}, fmt.Errorf("could not unmarshal to: %v", err)
    98  	}
    99  
   100  	if t.Kind() != reflect.Ptr {
   101  		if res.IsNil() {
   102  			res = reflect.New(res.Type().Elem())
   103  		}
   104  		res = res.Elem()
   105  	}
   106  
   107  	return res, nil
   108  }
   109  
   110  // SimpleMergeTwoValues merge two value with same type, which includes 3 cases:
   111  // 1. slice & array (or its pointer): append src slice to dst
   112  // 2. map (or its pointer): src map will overwrite dst
   113  // 3. other (or its pointer): set src by dst
   114  // since SimpleMergeTwoValues is a "simple" one, there may exist some cases
   115  // SimpleMergeTwoValues won't support, and a possible one is a struct with a map
   116  // or slice member, we will not merge its member object.
   117  // for example, consider src and dst with the same type of
   118  /*
   119  type newType struct {
   120  	a []string
   121  }
   122  */
   123  // and src is newType{"a":["2"]}, dst is newType{"a":["1"]}, the simple merge result
   124  // is newType{"a":["2"]}, and not newType{"a":["1","2"]}
   125  func SimpleMergeTwoValues(src reflect.Value, dst reflect.Value) error {
   126  	if src.Type() != dst.Type() {
   127  		return fmt.Errorf("type of src and dst is inconsistent")
   128  	}
   129  
   130  	switch dst.Kind() {
   131  	case reflect.Array, reflect.Slice:
   132  		SetSliceOrArrayValue(src, dst)
   133  	case reflect.Map:
   134  		SetMapValue(src, dst)
   135  	case reflect.Struct:
   136  		var errList []error
   137  		allFieldsCanSet := true
   138  		for i := 0; i < src.NumField(); i++ {
   139  			if !dst.Field(i).CanSet() {
   140  				allFieldsCanSet = false
   141  				break
   142  			}
   143  			if err := SimpleMergeTwoValues(src.Field(i), dst.Field(i)); err != nil {
   144  				errList = append(errList, err)
   145  			}
   146  		}
   147  		if !allFieldsCanSet {
   148  			dst.Set(src)
   149  		}
   150  		if len(errList) > 0 {
   151  			return fmt.Errorf("failed to merge struct: %v", errList)
   152  		}
   153  	case reflect.Ptr:
   154  		// if report value is nil, we no need to update origin value
   155  		if src.IsNil() {
   156  			return nil
   157  		}
   158  		src = src.Elem()
   159  
   160  		// initialize the origin value if it is nil
   161  		if dst.IsNil() {
   162  			dst.Set(reflect.New(dst.Type().Elem()))
   163  		}
   164  		dst = dst.Elem()
   165  
   166  		// merge their ptr value recursively
   167  		return SimpleMergeTwoValues(src, dst)
   168  	default:
   169  		dst.Set(src)
   170  	}
   171  
   172  	return nil
   173  }