Merge pull request #94480 from wojtek-t/remove_conversion_fields

Remove FieldMatchingFlags
This commit is contained in:
Kubernetes Prow Robot 2020-11-02 06:26:52 -08:00 committed by GitHub
commit a704860194
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 155 deletions

View File

@ -9,7 +9,6 @@ go_library(
"//pkg/apis/flowcontrol:go_default_library",
"//pkg/apis/flowcontrol/install:go_default_library",
"//staging/src/k8s.io/api/flowcontrol/v1alpha1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap:go_default_library",
],

View File

@ -18,7 +18,6 @@ package internalbootstrap
import (
fcv1a1 "k8s.io/api/flowcontrol/v1alpha1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap"
"k8s.io/kubernetes/pkg/apis/flowcontrol"
@ -49,11 +48,10 @@ func NewAPFScheme() *runtime.Scheme {
func internalizeFSes(exts []*fcv1a1.FlowSchema) map[string]*flowcontrol.FlowSchema {
ans := make(map[string]*flowcontrol.FlowSchema, len(exts))
converter := NewAPFScheme().Converter()
scheme := NewAPFScheme()
for _, ext := range exts {
var untyped flowcontrol.FlowSchema
err := converter.Convert(ext, &untyped, 0, &conversion.Meta{})
if err != nil {
if err := scheme.Convert(ext, &untyped, nil); err != nil {
panic(err)
}
ans[ext.Name] = &untyped
@ -63,11 +61,10 @@ func internalizeFSes(exts []*fcv1a1.FlowSchema) map[string]*flowcontrol.FlowSche
func internalizePLs(exts []*fcv1a1.PriorityLevelConfiguration) map[string]*flowcontrol.PriorityLevelConfiguration {
ans := make(map[string]*flowcontrol.PriorityLevelConfiguration, len(exts))
converter := NewAPFScheme().Converter()
scheme := NewAPFScheme()
for _, ext := range exts {
var untyped flowcontrol.PriorityLevelConfiguration
err := converter.Convert(ext, &untyped, 0, &conversion.Meta{})
if err != nil {
if err := scheme.Convert(ext, &untyped, nil); err != nil {
panic(err)
}
ans[ext.Name] = &untyped

View File

@ -47,12 +47,6 @@ type Converter struct {
ignoredConversions map[typePair]struct{}
ignoredUntypedConversions map[typePair]struct{}
// Map from an input type to a function which can apply a key name mapping
inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc
// Map from an input type to a set of default conversion flags.
inputDefaultFlags map[reflect.Type]FieldMatchingFlags
// nameFunc is called to retrieve the name of a type; this name is used for the
// purpose of deciding whether two types match or not (i.e., will we attempt to
// do a conversion). The default returns the go type name.
@ -67,9 +61,6 @@ func NewConverter(nameFn NameFunc) *Converter {
ignoredConversions: make(map[typePair]struct{}),
ignoredUntypedConversions: make(map[typePair]struct{}),
nameFunc: nameFn,
inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags),
}
c.RegisterUntypedConversionFunc(
(*[]byte)(nil), (*[]byte)(nil),
@ -88,11 +79,9 @@ func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
return &copied
}
// DefaultMeta returns the conversion FieldMappingFunc and meta for a given type.
func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) {
return c.inputDefaultFlags[t], &Meta{
KeyNameMapping: c.inputFieldMappingFuncs[t],
}
// DefaultMeta returns meta for a given type.
func (c *Converter) DefaultMeta(t reflect.Type) *Meta {
return &Meta{}
}
// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte
@ -112,19 +101,12 @@ func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
type Scope interface {
// Call Convert to convert sub-objects. Note that if you call it with your own exact
// parameters, you'll run out of stack space before anything useful happens.
Convert(src, dest interface{}, flags FieldMatchingFlags) error
// Flags returns the flags with which the conversion was started.
Flags() FieldMatchingFlags
Convert(src, dest interface{}) error
// Meta returns any information originally passed to Convert.
Meta() *Meta
}
// FieldMappingFunc can convert an input field value into different values, depending on
// the value of the source or destination struct tags.
type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)
func NewConversionFuncs() ConversionFuncs {
return ConversionFuncs{
untyped: make(map[typePair]ConversionFunc),
@ -165,9 +147,6 @@ func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
// Meta is supplied by Scheme, when it calls Convert.
type Meta struct {
// KeyNameMapping is an optional function which may map the listed key (field name)
// into a source and destination value.
KeyNameMapping FieldMappingFunc
// Context is an optional field that callers may use to pass info to conversion functions.
Context interface{}
}
@ -176,17 +155,11 @@ type Meta struct {
type scope struct {
converter *Converter
meta *Meta
flags FieldMatchingFlags
}
// Convert continues a conversion.
func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error {
return s.converter.Convert(src, dest, flags, s.meta)
}
// Flags returns the flags with which the current conversion was started.
func (s *scope) Flags() FieldMatchingFlags {
return s.flags
func (s *scope) Convert(src, dest interface{}) error {
return s.converter.Convert(src, dest, s.meta)
}
// Meta returns the meta object that was originally passed to Convert.
@ -224,65 +197,16 @@ func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
return nil
}
// RegisterInputDefaults registers a field name mapping function, used when converting
// from maps to structs. Inputs to the conversion methods are checked for this type and a mapping
// applied automatically if the input matches in. A set of default flags for the input conversion
// may also be provided, which will be used when no explicit flags are requested.
func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error {
fv := reflect.ValueOf(in)
ft := fv.Type()
if ft.Kind() != reflect.Ptr {
return fmt.Errorf("expected pointer 'in' argument, got: %v", ft)
}
c.inputFieldMappingFuncs[ft] = fn
c.inputDefaultFlags[ft] = defaultFlags
return nil
}
// FieldMatchingFlags contains a list of ways in which struct fields could be
// copied. These constants may be | combined.
type FieldMatchingFlags int
const (
// Loop through destination fields, search for matching source
// field to copy it from. Source fields with no corresponding
// destination field will be ignored. If SourceToDest is
// specified, this flag is ignored. If neither is specified,
// or no flags are passed, this flag is the default.
DestFromSource FieldMatchingFlags = 0
// Loop through source fields, search for matching dest field
// to copy it into. Destination fields with no corresponding
// source field will be ignored.
SourceToDest FieldMatchingFlags = 1 << iota
// Don't treat it as an error if the corresponding source or
// dest field can't be found.
IgnoreMissingFields
// Don't require type names to match.
AllowDifferentFieldTypeNames
)
// IsSet returns true if the given flag or combination of flags is set.
func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool {
if flag == DestFromSource {
// The bit logic doesn't work on the default value.
return f&SourceToDest != SourceToDest
}
return f&flag == flag
}
// Convert will translate src to dest if it knows how. Both must be pointers.
// If no conversion func is registered and the default copying mechanism
// doesn't work on this type pair, an error will be returned.
// Read the comments on the various FieldMatchingFlags constants to understand
// what the 'flags' parameter does.
// 'meta' is given to allow you to pass information to conversion functions,
// it is not used by Convert() other than storing it in the scope.
// Not safe for objects with cyclic references!
func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
func (c *Converter) Convert(src, dest interface{}, meta *Meta) error {
pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)}
scope := &scope{
converter: c,
flags: flags,
meta: meta,
}

View File

@ -27,7 +27,7 @@ func TestConverter_byteSlice(t *testing.T) {
c := NewConverter(DefaultNameFunc)
src := []byte{1, 2, 3}
dest := []byte{}
err := c.Convert(&src, &dest, 0, nil)
err := c.Convert(&src, &dest, nil)
if err != nil {
t.Fatalf("expected no error")
}
@ -58,7 +58,7 @@ func TestConverter_MismatchedTypes(t *testing.T) {
src := []string{"5"}
var dest int
if err := c.Convert(&src, &dest, 0, nil); err != nil {
if err := c.Convert(&src, &dest, nil); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := 5, dest; e != a {
@ -107,7 +107,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
x := A{"hello, intrepid test reader!", 3}
y := B{}
if err := c.Convert(&x, &y, 0, nil); err != nil {
if err := c.Convert(&x, &y, nil); err != nil {
t.Fatalf("unexpected error %v", err)
}
if e, a := x.Foo, y.Bar; e != a {
@ -120,7 +120,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
z := B{"all your test are belong to us", 42}
w := A{}
if err := c.Convert(&z, &w, 0, nil); err != nil {
if err := c.Convert(&z, &w, nil); err != nil {
t.Fatalf("unexpected error %v", err)
}
if e, a := z.Bar, w.Foo; e != a {
@ -141,7 +141,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
); err != nil {
t.Fatalf("unexpected error %v", err)
}
if err := c.Convert(&A{}, &C{}, 0, nil); err == nil {
if err := c.Convert(&A{}, &C{}, nil); err == nil {
t.Errorf("unexpected non-error")
}
}
@ -169,7 +169,7 @@ func TestConverter_IgnoredConversion(t *testing.T) {
}
a := A{}
b := B{}
if err := c.Convert(&a, &b, 0, nil); err != nil {
if err := c.Convert(&a, &b, nil); err != nil {
t.Errorf("%v", err)
}
if count != 0 {
@ -206,7 +206,7 @@ func TestConverter_GeneratedConversionOverridden(t *testing.T) {
a := A{}
b := B{}
if err := c.Convert(&a, &b, 0, nil); err != nil {
if err := c.Convert(&a, &b, nil); err != nil {
t.Errorf("%v", err)
}
}
@ -249,10 +249,10 @@ func TestConverter_WithConversionOverridden(t *testing.T) {
a := A{}
b := B{}
if err := c.Convert(&a, &b, 0, nil); err == nil || err.Error() != "conversion function should be overridden" {
if err := c.Convert(&a, &b, nil); err == nil || err.Error() != "conversion function should be overridden" {
t.Errorf("unexpected error: %v", err)
}
if err := newc.Convert(&a, &b, 0, nil); err != nil {
if err := newc.Convert(&a, &b, nil); err != nil {
t.Errorf("%v", err)
}
}
@ -278,7 +278,7 @@ func TestConverter_meta(t *testing.T) {
); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if err := c.Convert(&Foo{}, &Bar{}, 0, &Meta{}); err != nil {
if err := c.Convert(&Foo{}, &Bar{}, &Meta{}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if checks != 1 {

View File

@ -18,7 +18,6 @@ package runtime
import (
"fmt"
"net/url"
"reflect"
"strings"
@ -105,9 +104,6 @@ func NewScheme() *Scheme {
// Enable couple default conversions by default.
utilruntime.Must(RegisterEmbeddedConversions(s))
utilruntime.Must(RegisterStringConversions(s))
utilruntime.Must(s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields))
utilruntime.Must(s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields))
return s
}
@ -337,14 +333,6 @@ func (s *Scheme) AddFieldLabelConversionFunc(gvk schema.GroupVersionKind, conver
return nil
}
// RegisterInputDefaults sets the provided field mapping function and field matching
// as the defaults for the provided input type. The fn may be nil, in which case no
// mapping will happen by default. Use this method to register a mechanism for handling
// a specific input type in conversion, such as a map[string]string to structs.
func (s *Scheme) RegisterInputDefaults(in interface{}, fn conversion.FieldMappingFunc, defaultFlags conversion.FieldMatchingFlags) error {
return s.converter.RegisterInputDefaults(in, fn, defaultFlags)
}
// AddTypeDefaultingFunc registers a function that is passed a pointer to an
// object and can default fields on the object. These functions will be invoked
// when Default() is called. The function will never be called unless the
@ -428,12 +416,9 @@ func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
in = typed
}
flags, meta := s.generateConvertMeta(in)
meta := s.generateConvertMeta(in)
meta.Context = context
if flags == 0 {
flags = conversion.AllowDifferentFieldTypeNames
}
return s.converter.Convert(in, out, flags, meta)
return s.converter.Convert(in, out, meta)
}
// ConvertFieldLabel alters the given field label and value for an kind field selector from
@ -530,9 +515,9 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
in = in.DeepCopyObject()
}
flags, meta := s.generateConvertMeta(in)
meta := s.generateConvertMeta(in)
meta.Context = target
if err := s.converter.Convert(in, out, flags, meta); err != nil {
if err := s.converter.Convert(in, out, meta); err != nil {
return nil, err
}
@ -560,7 +545,7 @@ func (s *Scheme) unstructuredToTyped(in Unstructured) (Object, error) {
}
// generateConvertMeta constructs the meta value we pass to Convert.
func (s *Scheme) generateConvertMeta(in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
func (s *Scheme) generateConvertMeta(in interface{}) *conversion.Meta {
return s.converter.DefaultMeta(reflect.TypeOf(in))
}

View File

@ -817,21 +817,27 @@ func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.Snippet
sw.Do("$.|raw$(val)\n", outType.Elem)
}
} else {
sw.Do("newVal := new($.|raw$)\n", outType.Elem)
conversionExists := true
if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("newVal := new($.|raw$)\n", outType.Elem)
sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
sw.Do("newVal := new($.|raw$)\n", outType.Elem)
sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
} else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&val, newVal, 0); err != nil {\n", nil)
args := argsFromType(inType.Elem, outType.Elem)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
if inType.Key == outType.Key {
sw.Do("(*out)[key] = *newVal\n", nil)
} else {
sw.Do("(*out)[$.|raw$(key)] = *newVal\n", outType.Key)
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
if inType.Key == outType.Key {
sw.Do("(*out)[key] = *newVal\n", nil)
} else {
sw.Do("(*out)[$.|raw$(key)] = *newVal\n", outType.Key)
}
}
}
} else {
@ -855,21 +861,21 @@ func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.Snipp
sw.Do("(*out)[i] = $.|raw$((*in)[i])\n", outType.Elem)
}
} else {
conversionExists := true
if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
} else {
// TODO: This triggers on metav1.ObjectMeta <-> metav1.ObjectMeta and
// similar because neither package is the target package, and
// we really don't know which package will have the conversion
// function defined. This fires on basically every object
// conversion outside of pkg/api/v1.
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {\n", nil)
args := argsFromType(inType.Elem, outType.Elem)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("}\n", nil)
}
@ -976,14 +982,19 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
sw.Do("out.$.name$ = in.$.name$\n", args)
continue
}
conversionExists := true
if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) {
sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
} else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
args := argsFromType(inMemberType, outMemberType)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
case types.Alias:
if isDirectlyAssignable(inMemberType, outMemberType) {
if inMemberType == outMemberType {
@ -992,24 +1003,34 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args)
}
} else {
conversionExists := true
if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) {
sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
} else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
args := argsFromType(inMemberType, outMemberType)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
default:
conversionExists := true
if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) {
sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args)
} else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(&in.$.name$, &out.$.name$, 0); err != nil {\n", args)
args := argsFromType(inMemberType, outMemberType)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
}
}
@ -1038,16 +1059,21 @@ func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.Sni
sw.Do("**out = $.|raw$(**in)\n", outType.Elem)
}
} else {
conversionExists := true
if function, ok := g.preexists(inType.Elem, outType.Elem); ok {
sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function)
} else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) {
sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem))
} else {
sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil)
sw.Do("if err := s.Convert(*in, *out, 0); err != nil {\n", nil)
args := argsFromType(inType.Elem, outType.Elem)
sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args)
sw.Do("compileErrorOnMissingConversion()\n", nil)
conversionExists = false
}
if conversionExists {
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
sw.Do("return err\n", nil)
sw.Do("}\n", nil)
}
}