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 }