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

     1  package plugin
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/pkg/errors"
     7  )
     8  
     9  func NewRegistry() *Registry {
    10  	return &Registry{make(map[reflect.Type]nameRegistry)}
    11  }
    12  
    13  type Registry struct {
    14  	typeToNameReg map[reflect.Type]nameRegistry
    15  }
    16  
    17  func newNameRegistry() nameRegistry { return make(nameRegistry) }
    18  
    19  type nameRegistry map[string]nameRegistryEntry
    20  
    21  type nameRegistryEntry struct {
    22  	constructor   implConstructor
    23  	defaultConfig defaultConfigContainer
    24  }
    25  
    26  // Register registers plugin constructor and optional default config factory,
    27  // for given plugin interface type and plugin name.
    28  // See package doc for type expectations details.
    29  // Register designed to be called in package init func, so it panics if something go wrong.
    30  // Panics if type expectations are violated.
    31  // Panics if some constructor have been already registered for this (pluginType, name) pair.
    32  // Register is thread unsafe.
    33  //
    34  // If constructor receive config argument, default config factory can be
    35  // registered. Default config factory type should be: is func() <configType>.
    36  // Default config factory is optional. If no default config factory has been
    37  // registered, than plugin factory will receive zero config (zero struct or
    38  // pointer to zero struct).
    39  // Registered constructor will never receive nil config, even there
    40  // are no registered default config factory, or default config is nil. Config
    41  // will be pointer to zero config in such case.
    42  func (r *Registry) Register(
    43  	pluginType reflect.Type,
    44  	name string,
    45  	constructor interface{},
    46  	defaultConfigOptional ...interface{}, // default config factory, or nothing.
    47  ) {
    48  	expect(pluginType.Kind() == reflect.Interface, "plugin type should be interface, but have: %T", pluginType)
    49  	expect(name != "", "empty name")
    50  	nameReg := r.typeToNameReg[pluginType]
    51  	if nameReg == nil {
    52  		nameReg = newNameRegistry()
    53  		r.typeToNameReg[pluginType] = nameReg
    54  	}
    55  	_, ok := nameReg[name]
    56  	expect(!ok, "plugin %s with name %q had been already registered", pluginType, name)
    57  	defaultConfig := getNewDefaultConfig(defaultConfigOptional)
    58  	nameReg[name] = newNameRegistryEntry(pluginType, constructor, defaultConfig)
    59  }
    60  
    61  // Lookup returns true if any plugin constructor has been registered for given
    62  // type.
    63  func (r *Registry) Lookup(pluginType reflect.Type) bool {
    64  	_, ok := r.typeToNameReg[pluginType]
    65  	return ok
    66  }
    67  
    68  // LookupFactory returns true if factoryType looks like func() (SomeInterface[, error])
    69  // and any plugin constructor has been registered for SomeInterface.
    70  // That is, you may create instance of this factoryType using this registry.
    71  func (r *Registry) LookupFactory(factoryType reflect.Type) bool {
    72  	return isFactoryType(factoryType) && r.Lookup(factoryType.Out(0))
    73  }
    74  
    75  // New creates plugin using registered plugin constructor. Returns error if creation
    76  // failed or no plugin were registered for given type and name.
    77  // Passed fillConf called on created config before calling plugin factory.
    78  // fillConf argument is always valid struct pointer, even if plugin factory
    79  // receives no config: fillConf is called on empty struct pointer in such case.
    80  // fillConf error fails plugin creation.
    81  // New is thread safe, if there is no concurrent Register calls.
    82  func (r *Registry) New(pluginType reflect.Type, name string, fillConfOptional ...func(conf interface{}) error) (plugin interface{}, err error) {
    83  	expect(pluginType.Kind() == reflect.Interface, "plugin type should be interface, but have: %T", pluginType)
    84  	expect(name != "", "empty name")
    85  	fillConf := getFillConf(fillConfOptional)
    86  	registered, err := r.get(pluginType, name)
    87  	if err != nil {
    88  		return
    89  	}
    90  	conf, err := registered.defaultConfig.Get(fillConf)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	return registered.constructor.NewPlugin(conf)
    95  }
    96  
    97  // NewFactory behaves like New, but creates factory func() (PluginInterface[, error]), that on call
    98  // creates New plugin by registered factory.
    99  // If registered constructor is <newPlugin> config is created filled for every factory call,
   100  // if <newFactory, that only once for factory creation.
   101  func (r *Registry) NewFactory(factoryType reflect.Type, name string, fillConfOptional ...func(conf interface{}) error) (factory interface{}, err error) {
   102  	expect(isFactoryType(factoryType), "plugin factory type should be like `func() (PluginInterface, error)`, but have: %T", factoryType)
   103  	expect(name != "", "empty name")
   104  	fillConf := getFillConf(fillConfOptional)
   105  	pluginType := factoryType.Out(0)
   106  	registered, err := r.get(pluginType, name)
   107  	if err != nil {
   108  		return
   109  	}
   110  	var getMaybeConfig func() ([]reflect.Value, error)
   111  	if registered.defaultConfig.configRequired() {
   112  		getMaybeConfig = func() ([]reflect.Value, error) {
   113  			return registered.defaultConfig.Get(fillConf)
   114  		}
   115  	} else if fillConf != nil {
   116  		// Just check, that fillConf not fails, when there is no config fields.
   117  		err := fillConf(&struct{}{})
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  	}
   122  	return registered.constructor.NewFactory(factoryType, getMaybeConfig)
   123  }
   124  
   125  func newNameRegistryEntry(pluginType reflect.Type, constructor interface{}, defaultConfig interface{}) nameRegistryEntry {
   126  	implConstructor := newImplConstructor(pluginType, constructor)
   127  	defaultConfigContainer := newDefaultConfigContainer(reflect.TypeOf(constructor), defaultConfig)
   128  	return nameRegistryEntry{implConstructor, defaultConfigContainer}
   129  }
   130  
   131  func (r *Registry) get(pluginType reflect.Type, name string) (factory nameRegistryEntry, err error) {
   132  	pluginReg, ok := r.typeToNameReg[pluginType]
   133  	if !ok {
   134  		err = errors.Errorf("no plugins for type %s has been registered", pluginType)
   135  		return
   136  	}
   137  	factory, ok = pluginReg[name]
   138  	if !ok {
   139  		err = errors.Errorf("no plugins of type %s has been registered for name %s", pluginType, name)
   140  	}
   141  	return
   142  }
   143  
   144  // defaultConfigContainer contains default config creation logic.
   145  // Zero value is valid and means that no config is needed.
   146  type defaultConfigContainer struct {
   147  	// !IsValid() if constructor accepts no arguments.
   148  	// Otherwise type is func() <configType>.
   149  	newValue reflect.Value
   150  }
   151  
   152  func newDefaultConfigContainer(constructorType reflect.Type, defaultConfig interface{}) defaultConfigContainer {
   153  	if constructorType.NumIn() == 0 {
   154  		expect(defaultConfig == nil, "constructor accept no config, but defaultConfig passed")
   155  		return defaultConfigContainer{}
   156  	}
   157  	expect(constructorType.NumIn() == 1, "constructor should accept zero or one argument")
   158  	configType := constructorType.In(0)
   159  	expect(configType.Kind() == reflect.Struct ||
   160  		configType.Kind() == reflect.Ptr && configType.Elem().Kind() == reflect.Struct,
   161  		"unexpected config kind: %s; should be struct or struct pointer")
   162  	newDefaultConfigType := reflect.FuncOf(nil, []reflect.Type{configType}, false)
   163  	if defaultConfig == nil {
   164  		value := reflect.MakeFunc(newDefaultConfigType,
   165  			func(_ []reflect.Value) (results []reflect.Value) {
   166  				// OPTIMIZE: create addressable.
   167  				return []reflect.Value{reflect.Zero(configType)}
   168  			})
   169  		return defaultConfigContainer{value}
   170  	}
   171  	value := reflect.ValueOf(defaultConfig)
   172  	expect(value.Type() == newDefaultConfigType,
   173  		"defaultConfig should be func that accepts nothing, and returns constructor argument, but have type %T", defaultConfig)
   174  	return defaultConfigContainer{value}
   175  }
   176  
   177  // In reflect pkg []Value used to call functions. It's easier to return it, that convert from pointer when needed.
   178  func (e defaultConfigContainer) Get(fillConf func(fillAddr interface{}) error) (maybeConf []reflect.Value, err error) {
   179  	var fillAddr interface{}
   180  	if e.configRequired() {
   181  		maybeConf, fillAddr = e.new()
   182  	} else {
   183  		var emptyStruct struct{}
   184  		fillAddr = &emptyStruct // No fields to fill.
   185  	}
   186  	if fillConf != nil {
   187  		err = fillConf(fillAddr)
   188  		if err != nil {
   189  			return nil, err
   190  		}
   191  	}
   192  	return
   193  }
   194  
   195  func (e defaultConfigContainer) new() (maybeConf []reflect.Value, fillAddr interface{}) {
   196  	if !e.configRequired() {
   197  		panic("try to create config when not required")
   198  	}
   199  	conf := e.newValue.Call(nil)[0]
   200  	switch conf.Kind() {
   201  	case reflect.Struct:
   202  		// Config can be filled only by pointer.
   203  		if !conf.CanAddr() {
   204  			// Can't address to pass pointer into decoder. Let's make New addressable!
   205  			newArg := reflect.New(conf.Type()).Elem()
   206  			newArg.Set(conf)
   207  			conf = newArg
   208  		}
   209  		fillAddr = conf.Addr().Interface()
   210  	case reflect.Ptr:
   211  		if conf.IsNil() {
   212  			// Can't fill nil config. Init with zero.
   213  			conf = reflect.New(conf.Type().Elem())
   214  		}
   215  		fillAddr = conf.Interface()
   216  	default:
   217  		panic("unexpected type " + conf.String())
   218  	}
   219  	maybeConf = []reflect.Value{conf}
   220  	return
   221  }
   222  
   223  func (e defaultConfigContainer) configRequired() bool {
   224  	return e.newValue.IsValid()
   225  }
   226  
   227  func getFillConf(fillConfOptional []func(conf interface{}) error) func(interface{}) error {
   228  	expect(len(fillConfOptional) <= 1, "only fill config parameter could be passed")
   229  	if len(fillConfOptional) == 0 {
   230  		return nil
   231  	}
   232  	return fillConfOptional[0]
   233  }
   234  
   235  func getNewDefaultConfig(newDefaultConfigOptional []interface{}) interface{} {
   236  	expect(len(newDefaultConfigOptional) <= 1, "too many arguments passed")
   237  	if len(newDefaultConfigOptional) == 0 {
   238  		return nil
   239  	}
   240  	return newDefaultConfigOptional[0]
   241  }