1/* 2Copyright 2014 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package conversion 18 19import ( 20 "fmt" 21 "reflect" 22) 23 24type typePair struct { 25 source reflect.Type 26 dest reflect.Type 27} 28 29type NameFunc func(t reflect.Type) string 30 31var 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. 37type ConversionFunc func(a, b interface{}, scope Scope) error 38 39// Converter knows how to convert one type to another. 40type 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 ignoredConversions map[typePair]struct{} 48 ignoredUntypedConversions map[typePair]struct{} 49 50 // nameFunc is called to retrieve the name of a type; this name is used for the 51 // purpose of deciding whether two types match or not (i.e., will we attempt to 52 // do a conversion). The default returns the go type name. 53 nameFunc func(t reflect.Type) string 54} 55 56// NewConverter creates a new Converter object. 57func NewConverter(nameFn NameFunc) *Converter { 58 c := &Converter{ 59 conversionFuncs: NewConversionFuncs(), 60 generatedConversionFuncs: NewConversionFuncs(), 61 ignoredConversions: make(map[typePair]struct{}), 62 ignoredUntypedConversions: make(map[typePair]struct{}), 63 nameFunc: nameFn, 64 } 65 c.RegisterUntypedConversionFunc( 66 (*[]byte)(nil), (*[]byte)(nil), 67 func(a, b interface{}, s Scope) error { 68 return Convert_Slice_byte_To_Slice_byte(a.(*[]byte), b.(*[]byte), s) 69 }, 70 ) 71 return c 72} 73 74// WithConversions returns a Converter that is a copy of c but with the additional 75// fns merged on top. 76func (c *Converter) WithConversions(fns ConversionFuncs) *Converter { 77 copied := *c 78 copied.conversionFuncs = c.conversionFuncs.Merge(fns) 79 return &copied 80} 81 82// DefaultMeta returns meta for a given type. 83func (c *Converter) DefaultMeta(t reflect.Type) *Meta { 84 return &Meta{} 85} 86 87// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte 88func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error { 89 if *in == nil { 90 *out = nil 91 return nil 92 } 93 *out = make([]byte, len(*in)) 94 copy(*out, *in) 95 return nil 96} 97 98// Scope is passed to conversion funcs to allow them to continue an ongoing conversion. 99// If multiple converters exist in the system, Scope will allow you to use the correct one 100// from a conversion function--that is, the one your conversion function was called by. 101type Scope interface { 102 // Call Convert to convert sub-objects. Note that if you call it with your own exact 103 // parameters, you'll run out of stack space before anything useful happens. 104 Convert(src, dest interface{}) error 105 106 // Meta returns any information originally passed to Convert. 107 Meta() *Meta 108} 109 110func NewConversionFuncs() ConversionFuncs { 111 return ConversionFuncs{ 112 untyped: make(map[typePair]ConversionFunc), 113 } 114} 115 116type ConversionFuncs struct { 117 untyped map[typePair]ConversionFunc 118} 119 120// AddUntyped adds the provided conversion function to the lookup table for the types that are 121// supplied as a and b. a and b must be pointers or an error is returned. This method overwrites 122// previously defined functions. 123func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error { 124 tA, tB := reflect.TypeOf(a), reflect.TypeOf(b) 125 if tA.Kind() != reflect.Ptr { 126 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", a) 127 } 128 if tB.Kind() != reflect.Ptr { 129 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b) 130 } 131 c.untyped[typePair{tA, tB}] = fn 132 return nil 133} 134 135// Merge returns a new ConversionFuncs that contains all conversions from 136// both other and c, with other conversions taking precedence. 137func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { 138 merged := NewConversionFuncs() 139 for k, v := range c.untyped { 140 merged.untyped[k] = v 141 } 142 for k, v := range other.untyped { 143 merged.untyped[k] = v 144 } 145 return merged 146} 147 148// Meta is supplied by Scheme, when it calls Convert. 149type Meta struct { 150 // Context is an optional field that callers may use to pass info to conversion functions. 151 Context interface{} 152} 153 154// scope contains information about an ongoing conversion. 155type scope struct { 156 converter *Converter 157 meta *Meta 158} 159 160// Convert continues a conversion. 161func (s *scope) Convert(src, dest interface{}) error { 162 return s.converter.Convert(src, dest, s.meta) 163} 164 165// Meta returns the meta object that was originally passed to Convert. 166func (s *scope) Meta() *Meta { 167 return s.meta 168} 169 170// RegisterUntypedConversionFunc 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. 173func (c *Converter) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 174 return c.conversionFuncs.AddUntyped(a, b, fn) 175} 176 177// RegisterGeneratedUntypedConversionFunc registers a function that converts between a and b by passing objects of those 178// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce 179// any other guarantee. 180func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error { 181 return c.generatedConversionFuncs.AddUntyped(a, b, fn) 182} 183 184// RegisterIgnoredConversion registers a "no-op" for conversion, where any requested 185// conversion between from and to is ignored. 186func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error { 187 typeFrom := reflect.TypeOf(from) 188 typeTo := reflect.TypeOf(to) 189 if reflect.TypeOf(from).Kind() != reflect.Ptr { 190 return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom) 191 } 192 if typeTo.Kind() != reflect.Ptr { 193 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo) 194 } 195 c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{} 196 c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{} 197 return nil 198} 199 200// Convert will translate src to dest if it knows how. Both must be pointers. 201// If no conversion func is registered and the default copying mechanism 202// doesn't work on this type pair, an error will be returned. 203// 'meta' is given to allow you to pass information to conversion functions, 204// it is not used by Convert() other than storing it in the scope. 205// Not safe for objects with cyclic references! 206func (c *Converter) Convert(src, dest interface{}, meta *Meta) error { 207 pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)} 208 scope := &scope{ 209 converter: c, 210 meta: meta, 211 } 212 213 // ignore conversions of this type 214 if _, ok := c.ignoredUntypedConversions[pair]; ok { 215 return nil 216 } 217 if fn, ok := c.conversionFuncs.untyped[pair]; ok { 218 return fn(src, dest, scope) 219 } 220 if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok { 221 return fn(src, dest, scope) 222 } 223 224 dv, err := EnforcePtr(dest) 225 if err != nil { 226 return err 227 } 228 sv, err := EnforcePtr(src) 229 if err != nil { 230 return err 231 } 232 return fmt.Errorf("converting (%s) to (%s): unknown conversion", sv.Type(), dv.Type()) 233} 234