dependency.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package hero
  2. import (
  3. "fmt"
  4. "strings"
  5. "reflect"
  6. "github.com/kataras/iris/v12/context"
  7. )
  8. type (
  9. // DependencyHandler is the native function declaration which implementors should return a value match to an input.
  10. DependencyHandler = func(ctx *context.Context, input *Input) (reflect.Value, error)
  11. // DependencyMatchFunc type alias describes dependency
  12. // match function with an input (field or parameter).
  13. //
  14. // See "DependencyMatcher" too, which can be used on a Container to
  15. // change the way dependencies are matched to inputs for all dependencies.
  16. DependencyMatchFunc = func(in reflect.Type) bool
  17. // Dependency describes the design-time dependency to be injected at serve time.
  18. // Contains its source location, the dependency handler (provider) itself and information
  19. // such as static for static struct values or explicit to bind a value to its exact DestType and not if just assignable to it (interfaces).
  20. Dependency struct {
  21. OriginalValue interface{} // Used for debugging and for logging only.
  22. Source Source
  23. Handle DependencyHandler
  24. // It's the exact type of return to bind, if declared to return <T>, otherwise nil.
  25. DestType reflect.Type
  26. Static bool
  27. // If true then input and dependency DestType should be indedical,
  28. // not just assiginable to each other.
  29. // Example of use case: depenendency like time.Time that we want to be bindable
  30. // only to time.Time inputs and not to a service with a `String() string` method that time.Time struct implements too.
  31. Explicit bool
  32. // Match holds the matcher. Defaults to the Container's one.
  33. Match DependencyMatchFunc
  34. // StructDependents if true then the Container will try to resolve
  35. // the fields of a struct value, if any, when it's a dependent struct value
  36. // based on the previous registered dependencies.
  37. //
  38. // Defaults to false.
  39. StructDependents bool
  40. }
  41. )
  42. // Explicitly sets Explicit option to true.
  43. // See `Dependency.Explicit` field godoc for more.
  44. //
  45. // Returns itself.
  46. func (d *Dependency) Explicitly() *Dependency {
  47. d.Explicit = true
  48. return d
  49. }
  50. // EnableStructDependents sets StructDependents to true.
  51. func (d *Dependency) EnableStructDependents() *Dependency {
  52. d.StructDependents = true
  53. return d
  54. }
  55. func (d *Dependency) String() string {
  56. sourceLine := d.Source.String()
  57. val := d.OriginalValue
  58. if val == nil {
  59. val = d.Handle
  60. }
  61. return fmt.Sprintf("%s (%#+v)", sourceLine, val)
  62. }
  63. // NewDependency converts a function or a function which accepts other dependencies or static struct value to a *Dependency.
  64. //
  65. // See `Container.Handler` for more.
  66. func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dependency { // used only on tests.
  67. return newDependency(dependency, false, false, nil, funcDependencies...)
  68. }
  69. func newDependency(
  70. dependency interface{},
  71. disablePayloadAutoBinding bool,
  72. enableStructDependents bool,
  73. matchDependency DependencyMatcher,
  74. funcDependencies ...*Dependency,
  75. ) *Dependency {
  76. if dependency == nil {
  77. panic(fmt.Sprintf("bad value: nil: %T", dependency))
  78. }
  79. if d, ok := dependency.(*Dependency); ok {
  80. // already a *Dependency, do not continue (and most importatly do not call resolveDependency) .
  81. return d
  82. }
  83. v := valueOf(dependency)
  84. if !goodVal(v) {
  85. panic(fmt.Sprintf("bad value: %#+v", dependency))
  86. }
  87. if matchDependency == nil {
  88. matchDependency = DefaultDependencyMatcher
  89. }
  90. dest := &Dependency{
  91. Source: newSource(v),
  92. OriginalValue: dependency,
  93. StructDependents: enableStructDependents,
  94. }
  95. dest.Match = ToDependencyMatchFunc(dest, matchDependency)
  96. if !resolveDependency(v, disablePayloadAutoBinding, dest, funcDependencies...) {
  97. panic(fmt.Sprintf("bad value: could not resolve a dependency from: %#+v", dependency))
  98. }
  99. return dest
  100. }
  101. // DependencyResolver func(v reflect.Value, dest *Dependency) bool
  102. // Resolver DependencyResolver
  103. func resolveDependency(v reflect.Value, disablePayloadAutoBinding bool, dest *Dependency, prevDependencies ...*Dependency) bool {
  104. return fromDependencyHandler(v, dest) ||
  105. fromBuiltinValue(v, dest) ||
  106. fromStructValueOrDependentStructValue(v, disablePayloadAutoBinding, dest, prevDependencies) ||
  107. fromFunc(v, dest) ||
  108. len(prevDependencies) > 0 && fromDependentFunc(v, disablePayloadAutoBinding, dest, prevDependencies)
  109. }
  110. func fromDependencyHandler(_ reflect.Value, dest *Dependency) bool {
  111. // It's already on the desired form, just return it.
  112. dependency := dest.OriginalValue
  113. handler, ok := dependency.(DependencyHandler)
  114. if !ok {
  115. handler, ok = dependency.(func(*context.Context, *Input) (reflect.Value, error))
  116. if !ok {
  117. // It's almost a handler, only the second `Input` argument is missing.
  118. if h, is := dependency.(func(*context.Context) (reflect.Value, error)); is {
  119. handler = func(ctx *context.Context, _ *Input) (reflect.Value, error) {
  120. return h(ctx)
  121. }
  122. ok = is
  123. }
  124. }
  125. }
  126. if !ok {
  127. return false
  128. }
  129. dest.Handle = handler
  130. return true
  131. }
  132. func fromBuiltinValue(v reflect.Value, dest *Dependency) bool {
  133. if !isBuiltinValue(v) {
  134. return false
  135. }
  136. // It's just a static builtin value.
  137. handler := func(*context.Context, *Input) (reflect.Value, error) {
  138. return v, nil
  139. }
  140. dest.DestType = v.Type()
  141. dest.Static = true
  142. dest.Handle = handler
  143. return true
  144. }
  145. func fromStructValue(v reflect.Value, dest *Dependency) bool {
  146. if !isStructValue(v) {
  147. return false
  148. }
  149. // It's just a static struct value.
  150. handler := func(*context.Context, *Input) (reflect.Value, error) {
  151. return v, nil
  152. }
  153. dest.DestType = v.Type()
  154. dest.Static = true
  155. dest.Handle = handler
  156. return true
  157. }
  158. func fromStructValueOrDependentStructValue(v reflect.Value, disablePayloadAutoBinding bool, dest *Dependency, prevDependencies []*Dependency) bool {
  159. if !isStructValue(v) {
  160. // It's not just a static struct value.
  161. return false
  162. }
  163. if len(prevDependencies) == 0 || !dest.StructDependents { // As a non depedent struct.
  164. // We must make this check so we can avoid the auto-filling of
  165. // the dependencies from Iris builtin dependencies.
  166. return fromStructValue(v, dest)
  167. }
  168. // Check if it's a builtin dependency (e.g an MVC Application (see mvc.go#newApp)),
  169. // if it's and registered without a Dependency wrapper, like the rest builtin dependencies,
  170. // then do NOT try to resolve its fields.
  171. //
  172. // Although EnableStructDependents is false by default, we must check if it's a builtin dependency for any case.
  173. if strings.HasPrefix(indirectType(v.Type()).PkgPath(), "github.com/kataras/iris/v12") {
  174. return fromStructValue(v, dest)
  175. }
  176. bindings := getBindingsForStruct(v, prevDependencies, false, disablePayloadAutoBinding, dest.StructDependents, DefaultDependencyMatcher, -1, nil)
  177. if len(bindings) == 0 {
  178. return fromStructValue(v, dest) // same as above.
  179. }
  180. // As a depedent struct, however we may need to resolve its dependencies first
  181. // so we can decide if it's really a depedent struct or not.
  182. var (
  183. handler = func(*context.Context, *Input) (reflect.Value, error) {
  184. return v, nil
  185. }
  186. isStatic = true
  187. )
  188. for _, binding := range bindings {
  189. if !binding.Dependency.Static {
  190. isStatic = false
  191. break
  192. }
  193. }
  194. handler = func(ctx *context.Context, _ *Input) (reflect.Value, error) { // Called once per dependency on build-time if the dependency is static.
  195. elem := v
  196. if elem.Kind() == reflect.Ptr {
  197. elem = elem.Elem()
  198. }
  199. for _, binding := range bindings {
  200. field := elem.FieldByIndex(binding.Input.StructFieldIndex)
  201. if !field.CanSet() || !field.IsZero() {
  202. continue // already set.
  203. }
  204. // if !binding.Dependency.Match(field.Type()) { A check already happen in getBindingsForStruct.
  205. // continue
  206. // }
  207. input, err := binding.Dependency.Handle(ctx, binding.Input)
  208. if err != nil {
  209. if err == ErrSeeOther {
  210. continue
  211. }
  212. return emptyValue, err
  213. }
  214. // fmt.Printf("binding %s to %#+v\n", field.String(), input)
  215. field.Set(input)
  216. }
  217. return v, nil
  218. }
  219. dest.DestType = v.Type()
  220. dest.Static = isStatic
  221. dest.Handle = handler
  222. return true
  223. }
  224. func fromFunc(v reflect.Value, dest *Dependency) bool {
  225. if !isFunc(v) {
  226. return false
  227. }
  228. typ := v.Type()
  229. numIn := typ.NumIn()
  230. numOut := typ.NumOut()
  231. if numIn == 0 {
  232. // it's an empty function, that must return a structure.
  233. if numOut != 1 {
  234. firstOutType := indirectType(typ.Out(0))
  235. if firstOutType.Kind() != reflect.Struct && firstOutType.Kind() != reflect.Interface {
  236. panic(fmt.Sprintf("bad value: function has zero inputs: empty input function must output a single value but got: length=%v, type[0]=%s", numOut, firstOutType.String()))
  237. }
  238. }
  239. // fallback to structure.
  240. return fromStructValue(v.Call(nil)[0], dest)
  241. }
  242. if numOut == 0 {
  243. panic("bad value: function has zero outputs")
  244. }
  245. if numOut == 2 && !isError(typ.Out(1)) {
  246. panic("bad value: second output should be an error")
  247. }
  248. if numOut > 2 {
  249. // - at least one output value
  250. // - maximum of two output values
  251. // - second output value should be a type of error.
  252. panic(fmt.Sprintf("bad value: function has invalid number of output arguments: %v", numOut))
  253. }
  254. var handler DependencyHandler
  255. firstIsContext := isContext(typ.In(0))
  256. secondIsInput := numIn == 2 && typ.In(1) == inputTyp
  257. onlyContext := (numIn == 1 && firstIsContext) || (numIn == 2 && firstIsContext && typ.IsVariadic())
  258. if onlyContext || (firstIsContext && secondIsInput) {
  259. handler = handlerFromFunc(v, typ)
  260. }
  261. if handler == nil {
  262. return false
  263. }
  264. dest.DestType = typ.Out(0)
  265. dest.Handle = handler
  266. return true
  267. }
  268. func handlerFromFunc(v reflect.Value, typ reflect.Type) DependencyHandler {
  269. // * func(Context, *Input) <T>, func(Context) <T>
  270. // * func(Context) <T>, func(Context) <T>
  271. // * func(Context, *Input) <T>, func(Context) (<T>, error)
  272. // * func(Context) <T>, func(Context) (<T>, error)
  273. hasErrorOut := typ.NumOut() == 2 // if two, always an error type here.
  274. hasInputIn := typ.NumIn() == 2 && typ.In(1) == inputTyp
  275. return func(ctx *context.Context, input *Input) (reflect.Value, error) {
  276. inputs := ctx.ReflectValue()
  277. if hasInputIn {
  278. inputs = append(inputs, input.selfValue)
  279. }
  280. results := v.Call(inputs)
  281. if hasErrorOut {
  282. return results[0], toError(results[1])
  283. }
  284. return results[0], nil
  285. }
  286. }
  287. func fromDependentFunc(v reflect.Value, disablePayloadAutoBinding bool, dest *Dependency, funcDependencies []*Dependency) bool {
  288. // * func(<D>...) returns <T>
  289. // * func(<D>...) returns error
  290. // * func(<D>...) returns <T>, error
  291. typ := v.Type()
  292. if !isFunc(v) {
  293. return false
  294. }
  295. bindings := getBindingsForFunc(v, funcDependencies, disablePayloadAutoBinding, -1 /* parameter bindings are disabled for depent dependencies */)
  296. numIn := typ.NumIn()
  297. numOut := typ.NumOut()
  298. // d1 = Logger
  299. // d2 = func(Logger) S1
  300. // d2 should be static: it accepts dependencies that are static
  301. // (note: we don't check the output argument(s) of this dependency).
  302. if numIn == len(bindings) {
  303. static := true
  304. for _, b := range bindings {
  305. if !b.Dependency.Static && b.Dependency.Match(typ.In(b.Input.Index)) {
  306. static = false
  307. break
  308. }
  309. }
  310. if static {
  311. dest.Static = static
  312. }
  313. }
  314. firstOutIsError := numOut == 1 && isError(typ.Out(0))
  315. secondOutIsError := numOut == 2 && isError(typ.Out(1))
  316. handler := func(ctx *context.Context, _ *Input) (reflect.Value, error) {
  317. inputs := make([]reflect.Value, numIn)
  318. for _, binding := range bindings {
  319. input, err := binding.Dependency.Handle(ctx, binding.Input)
  320. if err != nil {
  321. if err == ErrSeeOther {
  322. continue
  323. }
  324. return emptyValue, err
  325. }
  326. inputs[binding.Input.Index] = input
  327. }
  328. outputs := v.Call(inputs)
  329. if firstOutIsError {
  330. return emptyValue, toError(outputs[0])
  331. } else if secondOutIsError {
  332. return outputs[0], toError(outputs[1])
  333. }
  334. return outputs[0], nil
  335. }
  336. dest.DestType = typ.Out(0)
  337. dest.Handle = handler
  338. return true
  339. }