converter.go 7.4 KB

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