github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/conversion/converter.go (about) 1 /* 2 Copyright 2014 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 conversion 18 19 import ( 20 "fmt" 21 "reflect" 22 ) 23 24 type typePair struct { 25 source reflect.Type 26 dest reflect.Type 27 } 28 29 type NameFunc func(t reflect.Type) string 30 31 var DefaultNameFunc = func(t reflect.Type) string { return t.Name() } 32 33 // ConversionFunc converts the object a into the object b, reusing arrays or objects 34 // or pointers if necessary. It should return an error if the object cannot be converted 35 // or if some data is invalid. If you do not wish a and b to share fields or nested 36 // objects, you must copy a before calling this function. 37 type ConversionFunc func(a, b interface{}, scope Scope) error 38 39 // Converter knows how to convert one type to another. 40 type Converter struct { 41 // Map from the conversion pair to a function which can 42 // do the conversion. 43 conversionFuncs ConversionFuncs 44 generatedConversionFuncs ConversionFuncs 45 46 // Set of conversions that should be treated as a no-op 47 ignoredUntypedConversions map[typePair]struct{} 48 } 49 50 // NewConverter creates a new Converter object. 51 // Arg NameFunc is just for backward compatibility. 52 func NewConverter(NameFunc) *Converter { 53 c := &Converter{ 54 conversionFuncs: NewConversionFuncs(), 55 generatedConversionFuncs: NewConversionFuncs(), 56 ignoredUntypedConversions: make(map[typePair]struct{}), 57 } 58 c.RegisterUntypedConversionFunc( 59 (*[]byte)(nil), (*[]byte)(nil), 60 func(a, b interface{}, s Scope) error { 61 return Convert_Slice_byte_To_Slice_byte(a.(*[]byte), b.(*[]byte), s) 62 }, 63 ) 64 return c 65 } 66 67 // WithConversions returns a Converter that is a copy of c but with the additional 68 // fns merged on top. 69 func (c *Converter) WithConversions(fns ConversionFuncs) *Converter { 70 copied := *c 71 copied.conversionFuncs = c.conversionFuncs.Merge(fns) 72 return &copied 73 } 74 75 // DefaultMeta returns meta for a given type. 76 func (c *Converter) DefaultMeta(t reflect.Type) *Meta { 77 return &Meta{} 78 } 79 80 // Convert_Slice_byte_To_Slice_byte prevents recursing into every byte 81 func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error { 82 if *in == nil { 83 *out = nil 84 return nil 85 } 86 *out = make([]byte, len(*in)) 87 copy(*out, *in) 88 return nil 89 } 90 91 // Scope is passed to conversion funcs to allow them to continue an ongoing conversion. 92 // If multiple converters exist in the system, Scope will allow you to use the correct one 93 // from a conversion function--that is, the one your conversion function was called by. 94 type Scope interface { 95 // Call Convert to convert sub-objects. Note that if you call it with your own exact 96 // parameters, you'll run out of stack space before anything useful happens. 97 Convert(src, dest interface{}) error 98 99 // Meta returns any information originally passed to Convert. 100 Meta() *Meta 101 } 102 103 func NewConversionFuncs() ConversionFuncs { 104 return ConversionFuncs{ 105 untyped: make(map[typePair]ConversionFunc), 106 } 107 } 108 109 type ConversionFuncs struct { 110 untyped map[typePair]ConversionFunc 111 } 112 113 // AddUntyped adds the provided conversion function to the lookup table for the types that are 114 // supplied as a and b. a and b must be pointers or an error is returned. This method overwrites 115 // previously defined functions. 116 func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error { 117 tA, tB := reflect.TypeOf(a), reflect.TypeOf(b) 118 if tA.Kind() != reflect.Pointer { 119 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", a) 120 } 121 if tB.Kind() != reflect.Pointer { 122 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b) 123 } 124 c.untyped[typePair{tA, tB}] = fn 125 return nil 126 } 127 128 // Merge returns a new ConversionFuncs that contains all conversions from 129 // both other and c, with other conversions taking precedence. 130 func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { 131 merged := NewConversionFuncs() 132 for k, v := range c.untyped { 133 merged.untyped[k] = v 134 } 135 for k, v := range other.untyped { 136 merged.untyped[k] = v 137 } 138 return merged 139 } 140 141 // Meta is supplied by Scheme, when it calls Convert. 142 type Meta struct { 143 // Context is an optional field that callers may use to pass info to conversion functions. 144 Context interface{} 145 } 146 147 // scope contains information about an ongoing conversion. 148 type scope struct { 149 converter *Converter 150 meta *Meta 151 } 152 153 // Convert continues a conversion. 154 func (s *scope) Convert(src, dest interface{}) error { 155 return s.converter.Convert(src, dest, s.meta) 156 } 157 158 // Meta returns the meta object that was originally passed to Convert. 159 func (s *scope) Meta() *Meta { 160 return s.meta 161 } 162 163 // RegisterUntypedConversionFunc registers a function that converts between a and b by passing objects of those 164 // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce 165 // any other guarantee. 166 func (c *Converter) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 167 return c.conversionFuncs.AddUntyped(a, b, fn) 168 } 169 170 // RegisterGeneratedUntypedConversionFunc registers a function that converts between a and b by passing objects of those 171 // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce 172 // any other guarantee. 173 func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 174 return c.generatedConversionFuncs.AddUntyped(a, b, fn) 175 } 176 177 // RegisterIgnoredConversion registers a "no-op" for conversion, where any requested 178 // conversion between from and to is ignored. 179 func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error { 180 typeFrom := reflect.TypeOf(from) 181 typeTo := reflect.TypeOf(to) 182 if typeFrom.Kind() != reflect.Pointer { 183 return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom) 184 } 185 if typeTo.Kind() != reflect.Pointer { 186 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo) 187 } 188 c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{} 189 return nil 190 } 191 192 // Convert will translate src to dest if it knows how. Both must be pointers. 193 // If no conversion func is registered and the default copying mechanism 194 // doesn't work on this type pair, an error will be returned. 195 // 'meta' is given to allow you to pass information to conversion functions, 196 // it is not used by Convert() other than storing it in the scope. 197 // Not safe for objects with cyclic references! 198 func (c *Converter) Convert(src, dest interface{}, meta *Meta) error { 199 pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)} 200 scope := &scope{ 201 converter: c, 202 meta: meta, 203 } 204 205 // ignore conversions of this type 206 if _, ok := c.ignoredUntypedConversions[pair]; ok { 207 return nil 208 } 209 if fn, ok := c.conversionFuncs.untyped[pair]; ok { 210 return fn(src, dest, scope) 211 } 212 if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok { 213 return fn(src, dest, scope) 214 } 215 216 dv, err := EnforcePtr(dest) 217 if err != nil { 218 return err 219 } 220 sv, err := EnforcePtr(src) 221 if err != nil { 222 return err 223 } 224 return fmt.Errorf("converting (%s) to (%s): unknown conversion", sv.Type(), dv.Type()) 225 }