github.com/yandex/pandora@v0.5.32/core/plugin/constructor.go (about)

     1  package plugin
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  )
     7  
     8  // implConstructor interface representing ability to create some plugin interface
     9  // implementations and is't factory functions. Usually it wraps some newPlugin or newFactory function, and
    10  // use is as implementation creator.
    11  // implConstructor expects, that caller pass correct maybeConf value, that can be
    12  // passed to underlying implementation creator.
    13  type implConstructor interface {
    14  	// NewPlugin constructs plugin implementation.
    15  	NewPlugin(maybeConf []reflect.Value) (plugin interface{}, err error)
    16  	// getMaybeConf may be nil, if no config required.
    17  	// Underlying implementation creator may require new config for every instance create.
    18  	// If so, then getMaybeConf will be called on every instance create. Otherwise, only once.
    19  	NewFactory(factoryType reflect.Type, getMaybeConf func() ([]reflect.Value, error)) (pluginFactory interface{}, err error)
    20  }
    21  
    22  func newImplConstructor(pluginType reflect.Type, constructor interface{}) implConstructor {
    23  	constructorType := reflect.TypeOf(constructor)
    24  	expect(constructorType.Kind() == reflect.Func, "plugin constructor should be func")
    25  	expect(constructorType.NumOut() >= 1,
    26  		"plugin constructor should return plugin implementation as first output parameter")
    27  	if constructorType.Out(0).Kind() == reflect.Func {
    28  		return newFactoryConstructor(pluginType, constructor)
    29  	}
    30  	return newPluginConstructor(pluginType, constructor)
    31  }
    32  
    33  func newPluginConstructor(pluginType reflect.Type, newPlugin interface{}) *pluginConstructor {
    34  	expectPluginConstructor(pluginType, reflect.TypeOf(newPlugin), true)
    35  	return &pluginConstructor{pluginType, reflect.ValueOf(newPlugin)}
    36  }
    37  
    38  // pluginConstructor use newPlugin func([config <configType>]) (<pluginImpl> [, error])
    39  // to construct plugin implementations
    40  type pluginConstructor struct {
    41  	pluginType reflect.Type
    42  	newPlugin  reflect.Value
    43  }
    44  
    45  func (c *pluginConstructor) NewPlugin(maybeConf []reflect.Value) (plugin interface{}, err error) {
    46  	out := c.newPlugin.Call(maybeConf)
    47  	plugin = out[0].Interface()
    48  	if len(out) > 1 {
    49  		err, _ = out[1].Interface().(error)
    50  	}
    51  	return
    52  }
    53  
    54  func (c *pluginConstructor) NewFactory(factoryType reflect.Type, getMaybeConf func() ([]reflect.Value, error)) (interface{}, error) {
    55  	if c.newPlugin.Type() == factoryType {
    56  		return c.newPlugin.Interface(), nil
    57  	}
    58  	return reflect.MakeFunc(factoryType, func(in []reflect.Value) []reflect.Value {
    59  		var maybeConf []reflect.Value
    60  		if getMaybeConf != nil {
    61  			var err error
    62  			maybeConf, err = getMaybeConf()
    63  			if err != nil {
    64  				switch factoryType.NumOut() {
    65  				case 1:
    66  					panic(err)
    67  				case 2:
    68  					return []reflect.Value{reflect.Zero(c.pluginType), reflect.ValueOf(&err).Elem()}
    69  				default:
    70  					panic(fmt.Sprintf(" out params num expeced to be 1 or 2, but have: %v", factoryType.NumOut()))
    71  				}
    72  			}
    73  		}
    74  		out := c.newPlugin.Call(maybeConf)
    75  		return convertFactoryOutParams(c.pluginType, factoryType.NumOut(), out)
    76  	}).Interface(), nil
    77  }
    78  
    79  // factoryConstructor use newFactory func([config <configType>]) (func() (<pluginImpl>[, error])[, error)
    80  // to construct plugin implementations.
    81  type factoryConstructor struct {
    82  	pluginType reflect.Type
    83  	newFactory reflect.Value
    84  }
    85  
    86  func newFactoryConstructor(pluginType reflect.Type, newFactory interface{}) *factoryConstructor {
    87  	newFactoryType := reflect.TypeOf(newFactory)
    88  	expect(newFactoryType.Kind() == reflect.Func, "factory constructor should be func")
    89  	expect(newFactoryType.NumIn() <= 1, "factory constructor should accept config or nothing")
    90  
    91  	expect(1 <= newFactoryType.NumOut() && newFactoryType.NumOut() <= 2,
    92  		"factory constructor should return factory, and optionally error")
    93  	if newFactoryType.NumOut() == 2 {
    94  		expect(newFactoryType.Out(1) == errorType, "factory constructor should have no second return value, or it should be error")
    95  	}
    96  	factoryType := newFactoryType.Out(0)
    97  	expectPluginConstructor(pluginType, factoryType, false)
    98  	return &factoryConstructor{pluginType, reflect.ValueOf(newFactory)}
    99  }
   100  
   101  func (c *factoryConstructor) NewPlugin(maybeConf []reflect.Value) (plugin interface{}, err error) {
   102  	factory, err := c.callNewFactory(maybeConf)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	out := factory.Call(nil)
   107  	plugin = out[0].Interface()
   108  	if len(out) > 1 {
   109  		err, _ = out[1].Interface().(error)
   110  	}
   111  	return
   112  }
   113  
   114  func (c *factoryConstructor) NewFactory(factoryType reflect.Type, getMaybeConf func() ([]reflect.Value, error)) (interface{}, error) {
   115  	var maybeConf []reflect.Value
   116  	if getMaybeConf != nil {
   117  		var err error
   118  		maybeConf, err = getMaybeConf()
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  	}
   123  	factory, err := c.callNewFactory(maybeConf)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	if factory.Type() == factoryType {
   128  		return factory.Interface(), nil
   129  	}
   130  	return reflect.MakeFunc(factoryType, func(in []reflect.Value) []reflect.Value {
   131  		out := factory.Call(nil)
   132  		return convertFactoryOutParams(c.pluginType, factoryType.NumOut(), out)
   133  	}).Interface(), nil
   134  }
   135  
   136  func (c *factoryConstructor) callNewFactory(maybeConf []reflect.Value) (factory reflect.Value, err error) {
   137  	factoryAndMaybeErr := c.newFactory.Call(maybeConf)
   138  	if len(factoryAndMaybeErr) > 1 {
   139  		err, _ = factoryAndMaybeErr[1].Interface().(error)
   140  	}
   141  	return factoryAndMaybeErr[0], err
   142  }
   143  
   144  // expectPluginConstructor checks type expectations common for newPlugin, and factory, returned from newFactory.
   145  func expectPluginConstructor(pluginType, factoryType reflect.Type, configAllowed bool) {
   146  	expect(factoryType.Kind() == reflect.Func, "plugin constructor should be func")
   147  	if configAllowed {
   148  		expect(factoryType.NumIn() <= 1, "plugin constructor should accept config or nothing")
   149  	} else {
   150  		expect(factoryType.NumIn() == 0, "plugin constructor returned from newFactory, shouldn't accept any arguments")
   151  	}
   152  	expect(1 <= factoryType.NumOut() && factoryType.NumOut() <= 2,
   153  		"plugin constructor should return plugin implementation, and optionally error")
   154  	pluginImplType := factoryType.Out(0)
   155  	expect(pluginImplType.Implements(pluginType), "plugin constructor should implement plugin interface")
   156  	if factoryType.NumOut() == 2 {
   157  		expect(factoryType.Out(1) == errorType, "plugin constructor should have no second return value, or it should be error")
   158  	}
   159  }
   160  
   161  // convertFactoryOutParams converts output params of some factory (newPlugin) call to required.
   162  func convertFactoryOutParams(pluginType reflect.Type, numOut int, out []reflect.Value) []reflect.Value {
   163  	switch numOut {
   164  	case 1, 2:
   165  		// OK.
   166  	default:
   167  		panic(fmt.Sprintf("unexpeced out params num: %v; 1 or 2 expected", numOut))
   168  	}
   169  	if out[0].Type() != pluginType {
   170  		// Not plugin, but its implementation.
   171  		impl := out[0]
   172  		out[0] = reflect.New(pluginType).Elem()
   173  		out[0].Set(impl)
   174  	}
   175  	if len(out) < numOut {
   176  		// Registered factory returns no error, but we should.
   177  		out = append(out, reflect.Zero(errorType))
   178  	}
   179  	if numOut < len(out) {
   180  		// Registered factory returns error, but we should not.
   181  		if !out[1].IsNil() {
   182  			panic(out[1].Interface())
   183  		}
   184  		out = out[:1]
   185  	}
   186  	return out
   187  }