package v2 import ( "reflect" "dario.cat/mergo" ) var t = newMultiTransformer( newIgnoreAttributesTransformer(ignoreTypes...), newOnlyDereferenceStructTransformer(), newInputDeviceMappingsTransformer(), ) type multiTransformer struct { transformers []mergo.Transformers } func newMultiTransformer(transformers ...mergo.Transformers) mergo.Transformers { return multiTransformer{ transformers: transformers, } } // Iterates through each transformer with the given type, returning the // first transformer function that is not nil. func (t multiTransformer) Transformer(typ reflect.Type) func(base, overlay reflect.Value) error { for _, transformer := range t.transformers { if f := transformer.Transformer(typ); f != nil { return f } } return nil } type ignoreAttributesTransformer struct { ignoredTypes []reflect.Type } func newIgnoreAttributesTransformer(ignoredTypes ...reflect.Type) mergo.Transformers { return ignoreAttributesTransformer{ ignoredTypes: ignoredTypes, } } // For attributes of types we want to ignore return a transformer // function that does nothing, making the merge for that type a no-op. func (t ignoreAttributesTransformer) Transformer(typ reflect.Type) func(base, overlay reflect.Value) error { for _, ignoreType := range t.ignoredTypes { if typ == ignoreType || typ == reflect.PointerTo(ignoreType) { return func(_, _ reflect.Value) error { return nil } } } return nil } type onlyDereferenceStructTransformer struct{} func newOnlyDereferenceStructTransformer() mergo.Transformers { return onlyDereferenceStructTransformer{} } // Always override non-struct pointers as we want 'empty' values such // as boolean false and integer 0 to be respected during the merge. func (t onlyDereferenceStructTransformer) Transformer(typ reflect.Type) func(base, overlay reflect.Value) error { if typ.Kind() == reflect.Pointer { if typ.Elem().Kind() == reflect.Struct { return nil } return func(base, overlay reflect.Value) error { if !overlay.IsNil() { base.Set(overlay) } return nil } } return nil } type inputDeviceMappingsTransformer struct{} func newInputDeviceMappingsTransformer() mergo.Transformers { return inputDeviceMappingsTransformer{} } // Allows input device mappings to be overridden by merging with // empty slice. Sets input device mappings to nil the the overlay // slice is empty, otherwise uses the merged mappings. func (t inputDeviceMappingsTransformer) Transformer(typ reflect.Type) func(base, overlay reflect.Value) error { if typ == reflect.TypeOf([]InputDeviceName{}) { return func(base, overlay reflect.Value) error { if overlay.Len() == 0 { var nilSlice []InputDeviceName overlay = reflect.ValueOf(nilSlice) } base.Set(overlay) return nil } } return nil }