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  }