code: func NewProvider(constructor interface{}, argPtrs ...interface{}) Provider {
  	fnValue := reflect.ValueOf(constructor)
  	if fnValue.Kind() != reflect.Func {
  		panic(fmt.Sprintf("constructor (%v) is not a function, found %v", fnValue, fnValue.Kind()))
  	}
  
  	fnType := reflect.TypeOf(constructor)
  	if fnType.NumOut() != 1 {
  		panic(fmt.Sprintf("constructor must have exactly 1 return value, found %v", fnType.NumOut()))
  	}
  
  	argCount := fnType.NumIn()
  	if !fnValue.Type().IsVariadic() && argCount != len(argPtrs) {
  		panic(fmt.Sprintf("argPtrs (%d) must match constructor arguments (%d)", len(argPtrs), argCount))
  	}
  
  	var kind reflect.Kind
  	for i, argPtr := range argPtrs {
  		isVariadic := fnValue.Type().IsVariadic() && (fnType.NumIn() == 1 || i >= fnType.NumIn())
  
  		if i < fnType.NumIn() {
  			kind = fnType.In(i).Kind()
  		} else {
  			kind = fnType.In(fnType.NumIn() - 1).Kind()
  		}
  
  		if reflect.TypeOf(argPtr).Kind() != reflect.Ptr {
  			panic(fmt.Sprintf("argPtrs must all be pointers, found %v", reflect.TypeOf(argPtr)))
  		}
  
  		if !isVariadic && reflect.ValueOf(argPtr).Elem().Kind() != kind {
  			panic("argPtrs must match constructor argument types")
  		}
  	}
  
  	return provider{
  		constructor: constructor,
  		argPtrs:     argPtrs,
  	}
  }
docs: // NewProvider specifies how to construct a value given its constructor function and argument pointers