converter.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. ignoredConversions map[typePair]struct{}
  37. ignoredUntypedConversions map[typePair]struct{}
  38. // nameFunc is called to retrieve the name of a type; this name is used for the
  39. // purpose of deciding whether two types match or not (i.e., will we attempt to
  40. // do a conversion). The default returns the go type name.
  41. nameFunc func(t reflect.Type) string
  42. }
  43. // NewConverter creates a new Converter object.
  44. func NewConverter(nameFn NameFunc) *Converter {
  45. c := &Converter{
  46. conversionFuncs: NewConversionFuncs(),
  47. generatedConversionFuncs: NewConversionFuncs(),
  48. ignoredConversions: make(map[typePair]struct{}),
  49. ignoredUntypedConversions: make(map[typePair]struct{}),
  50. nameFunc: nameFn,
  51. }
  52. c.RegisterUntypedConversionFunc(
  53. (*[]byte)(nil), (*[]byte)(nil),
  54. func(a, b interface{}, s Scope) error {
  55. return Convert_Slice_byte_To_Slice_byte(a.(*[]byte), b.(*[]byte), s)
  56. },
  57. )
  58. return c
  59. }
  60. // WithConversions returns a Converter that is a copy of c but with the additional
  61. // fns merged on top.
  62. func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
  63. copied := *c
  64. copied.conversionFuncs = c.conversionFuncs.Merge(fns)
  65. return &copied
  66. }
  67. // DefaultMeta returns meta for a given type.
  68. func (c *Converter) DefaultMeta(t reflect.Type) *Meta {
  69. return &Meta{}
  70. }
  71. // Convert_Slice_byte_To_Slice_byte prevents recursing into every byte
  72. func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
  73. if *in == nil {
  74. *out = nil
  75. return nil
  76. }
  77. *out = make([]byte, len(*in))
  78. copy(*out, *in)
  79. return nil
  80. }
  81. // Scope is passed to conversion funcs to allow them to continue an ongoing conversion.
  82. // If multiple converters exist in the system, Scope will allow you to use the correct one
  83. // from a conversion function--that is, the one your conversion function was called by.
  84. type Scope interface {
  85. // Call Convert to convert sub-objects. Note that if you call it with your own exact
  86. // parameters, you'll run out of stack space before anything useful happens.
  87. Convert(src, dest interface{}) error
  88. // Meta returns any information originally passed to Convert.
  89. Meta() *Meta
  90. }
  91. func NewConversionFuncs() ConversionFuncs {
  92. return ConversionFuncs{
  93. untyped: make(map[typePair]ConversionFunc),
  94. }
  95. }
  96. type ConversionFuncs struct {
  97. untyped map[typePair]ConversionFunc
  98. }
  99. // AddUntyped adds the provided conversion function to the lookup table for the types that are
  100. // supplied as a and b. a and b must be pointers or an error is returned. This method overwrites
  101. // previously defined functions.
  102. func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error {
  103. tA, tB := reflect.TypeOf(a), reflect.TypeOf(b)
  104. if tA.Kind() != reflect.Ptr {
  105. return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", a)
  106. }
  107. if tB.Kind() != reflect.Ptr {
  108. return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b)
  109. }
  110. c.untyped[typePair{tA, tB}] = fn
  111. return nil
  112. }
  113. // Merge returns a new ConversionFuncs that contains all conversions from
  114. // both other and c, with other conversions taking precedence.
  115. func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
  116. merged := NewConversionFuncs()
  117. for k, v := range c.untyped {
  118. merged.untyped[k] = v
  119. }
  120. for k, v := range other.untyped {
  121. merged.untyped[k] = v
  122. }
  123. return merged
  124. }
  125. // Meta is supplied by Scheme, when it calls Convert.
  126. type Meta struct {
  127. // Context is an optional field that callers may use to pass info to conversion functions.
  128. Context interface{}
  129. }
  130. // scope contains information about an ongoing conversion.
  131. type scope struct {
  132. converter *Converter
  133. meta *Meta
  134. }
  135. // Convert continues a conversion.
  136. func (s *scope) Convert(src, dest interface{}) error {
  137. return s.converter.Convert(src, dest, s.meta)
  138. }
  139. // Meta returns the meta object that was originally passed to Convert.
  140. func (s *scope) Meta() *Meta {
  141. return s.meta
  142. }
  143. // RegisterUntypedConversionFunc 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) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
  147. return c.conversionFuncs.AddUntyped(a, b, fn)
  148. }
  149. // RegisterGeneratedUntypedConversionFunc registers a function that converts between a and b by passing objects of those
  150. // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
  151. // any other guarantee.
  152. func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
  153. return c.generatedConversionFuncs.AddUntyped(a, b, fn)
  154. }
  155. // RegisterIgnoredConversion registers a "no-op" for conversion, where any requested
  156. // conversion between from and to is ignored.
  157. func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
  158. typeFrom := reflect.TypeOf(from)
  159. typeTo := reflect.TypeOf(to)
  160. if reflect.TypeOf(from).Kind() != reflect.Ptr {
  161. return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom)
  162. }
  163. if typeTo.Kind() != reflect.Ptr {
  164. return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
  165. }
  166. c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
  167. c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{}
  168. return nil
  169. }
  170. // Convert will translate src to dest if it knows how. Both must be pointers.
  171. // If no conversion func is registered and the default copying mechanism
  172. // doesn't work on this type pair, an error will be returned.
  173. // 'meta' is given to allow you to pass information to conversion functions,
  174. // it is not used by Convert() other than storing it in the scope.
  175. // Not safe for objects with cyclic references!
  176. func (c *Converter) Convert(src, dest interface{}, meta *Meta) error {
  177. pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)}
  178. scope := &scope{
  179. converter: c,
  180. meta: meta,
  181. }
  182. // ignore conversions of this type
  183. if _, ok := c.ignoredUntypedConversions[pair]; ok {
  184. return nil
  185. }
  186. if fn, ok := c.conversionFuncs.untyped[pair]; ok {
  187. return fn(src, dest, scope)
  188. }
  189. if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok {
  190. return fn(src, dest, scope)
  191. }
  192. dv, err := EnforcePtr(dest)
  193. if err != nil {
  194. return err
  195. }
  196. sv, err := EnforcePtr(src)
  197. if err != nil {
  198. return err
  199. }
  200. return fmt.Errorf("converting (%s) to (%s): unknown conversion", sv.Type(), dv.Type())
  201. }