github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/syntax/deepcopy.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 "reflect" 21 "time" 22 23 v1 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/resource" 25 "k8s.io/apimachinery/pkg/labels" 26 ) 27 28 // DeepCopiable is an interface that can be implemented by types that need to 29 // customize their deep copy behavior. 30 type DeepCopiable interface { 31 DeepCopy() interface{} 32 } 33 34 // DeepCopy returns a deep copy of the given object. 35 func DeepCopy(src interface{}) interface{} { 36 if src == nil { 37 return nil 38 } 39 40 old := reflect.ValueOf(src) 41 cpy := reflect.New(old.Type()).Elem() 42 copyRecursive(old, cpy) 43 return cpy.Interface() 44 } 45 46 func copyRecursive(oldItem, newItem reflect.Value) { 47 if oldItem.CanInterface() { 48 if copyItem, ok := oldItem.Interface().(DeepCopiable); ok { 49 newItem.Set(reflect.ValueOf(copyItem.DeepCopy())) 50 return 51 } 52 } 53 54 switch oldItem.Kind() { 55 case reflect.Ptr: 56 oldValue := oldItem.Elem() 57 58 if !oldValue.IsValid() { 59 return 60 } 61 62 newItem.Set(reflect.New(oldValue.Type())) 63 copyRecursive(oldValue, newItem.Elem()) 64 case reflect.Interface: 65 if oldItem.IsNil() { 66 return 67 } 68 oldValue := oldItem.Elem() 69 70 copyValue := reflect.New(oldValue.Type()).Elem() 71 copyRecursive(oldValue, copyValue) 72 newItem.Set(copyValue) 73 case reflect.Struct: 74 // check for some native struct copy 75 if nativeStructCopy(oldItem, newItem) { 76 return 77 } 78 79 for i := 0; i < oldItem.NumField(); i++ { 80 if oldItem.Type().Field(i).PkgPath != "" { 81 continue 82 } 83 copyRecursive(oldItem.Field(i), newItem.Field(i)) 84 } 85 case reflect.Slice: 86 if oldItem.IsNil() { 87 return 88 } 89 90 newItem.Set(reflect.MakeSlice(oldItem.Type(), oldItem.Len(), oldItem.Cap())) 91 for i := 0; i < oldItem.Len(); i++ { 92 copyRecursive(oldItem.Index(i), newItem.Index(i)) 93 } 94 case reflect.Map: 95 if oldItem.IsNil() { 96 return 97 } 98 99 newItem.Set(reflect.MakeMap(oldItem.Type())) 100 for _, key := range oldItem.MapKeys() { 101 oldValue := oldItem.MapIndex(key) 102 newValue := reflect.New(oldValue.Type()).Elem() 103 copyRecursive(oldValue, newValue) 104 copyKey := DeepCopy(key.Interface()) 105 newItem.SetMapIndex(reflect.ValueOf(copyKey), newValue) 106 } 107 default: 108 newItem.Set(oldItem) 109 } 110 } 111 112 // nativeStructCopy support copy function for some native struct 113 func nativeStructCopy(oldItem, newItem reflect.Value) bool { 114 if !oldItem.CanInterface() { 115 return false 116 } 117 118 switch copier := oldItem.Interface().(type) { 119 case time.Time: 120 newItem.Set(reflect.ValueOf(copier)) 121 return true 122 case v1.ResourceList: 123 newItem.Set(reflect.ValueOf(copier.DeepCopy())) 124 return true 125 case resource.Quantity: 126 newItem.Set(reflect.ValueOf(copier.DeepCopy())) 127 return true 128 case labels.Selector: 129 newItem.Set(reflect.ValueOf(copier.DeepCopySelector())) 130 return true 131 } 132 133 return false 134 }