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 }