| 253 | } |
| 254 | |
| 255 | func (c *C) provide(constructor interface{}) { |
| 256 | var ( |
| 257 | options []dig.ProvideOption |
| 258 | shouldMakeFunc bool |
| 259 | ) |
| 260 | |
| 261 | if op, ok := constructor.(di.OptionalProvider); ok { |
| 262 | constructor = op.Constructor |
| 263 | options = op.Options |
| 264 | } |
| 265 | |
| 266 | ftype := reflect.TypeOf(constructor) |
| 267 | if ftype == nil { |
| 268 | panic("can't provide an untyped nil") |
| 269 | } |
| 270 | if ftype.Kind() != reflect.Func { |
| 271 | panic(fmt.Sprintf("must provide constructor function, got %v (type %v)", constructor, ftype)) |
| 272 | } |
| 273 | |
| 274 | inTypes := make([]reflect.Type, 0) |
| 275 | outTypes := make([]reflect.Type, 0) |
| 276 | for i := 0; i < ftype.NumOut(); i++ { |
| 277 | outT := ftype.Out(i) |
| 278 | if isCleanup(outT) { |
| 279 | shouldMakeFunc = true |
| 280 | continue |
| 281 | } |
| 282 | if isModule(outT) { |
| 283 | shouldMakeFunc = true |
| 284 | } |
| 285 | outTypes = append(outTypes, outT) |
| 286 | } |
| 287 | |
| 288 | for i := 0; i < ftype.NumIn(); i++ { |
| 289 | inT := ftype.In(i) |
| 290 | if isModule(inT) { |
| 291 | shouldMakeFunc = true |
| 292 | } |
| 293 | inTypes = append(inTypes, inT) |
| 294 | } |
| 295 | |
| 296 | // no cleanup or module, we can use normal dig. |
| 297 | if !shouldMakeFunc { |
| 298 | err := c.di.Provide(constructor, options...) |
| 299 | if err != nil { |
| 300 | panic(err) |
| 301 | } |
| 302 | return |
| 303 | } |
| 304 | |
| 305 | // has cleanup or module, use reflect.MakeFunc as interceptor. |
| 306 | fnType := reflect.FuncOf(inTypes, outTypes, ftype.IsVariadic() /* variadic */) |
| 307 | fn := reflect.MakeFunc(fnType, func(args []reflect.Value) []reflect.Value { |
| 308 | filteredOuts := make([]reflect.Value, 0) |
| 309 | outVs := reflect.ValueOf(constructor).Call(args) |
| 310 | for _, v := range outVs { |
| 311 | vType := v.Type() |
| 312 | if isCleanup(vType) { |