mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
7.6 KiB
262 lines
7.6 KiB
// Copyright 2013 Jeremy Saenz |
|
// Copyright 2015 The Macaron Authors |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may |
|
// not use this file except in compliance with the License. You may obtain |
|
// a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|
// License for the specific language governing permissions and limitations |
|
// under the License. |
|
|
|
// Package inject provides utilities for mapping and injecting dependencies in various ways. |
|
package inject |
|
|
|
import ( |
|
"fmt" |
|
"reflect" |
|
) |
|
|
|
// Injector represents an interface for mapping and injecting dependencies into structs |
|
// and function arguments. |
|
type Injector interface { |
|
Applicator |
|
Invoker |
|
TypeMapper |
|
// SetParent sets the parent of the injector. If the injector cannot find a |
|
// dependency in its Type map it will check its parent before returning an |
|
// error. |
|
SetParent(Injector) |
|
} |
|
|
|
// Applicator represents an interface for mapping dependencies to a struct. |
|
type Applicator interface { |
|
// Maps dependencies in the Type map to each field in the struct |
|
// that is tagged with 'inject'. Returns an error if the injection |
|
// fails. |
|
Apply(interface{}) error |
|
} |
|
|
|
// Invoker represents an interface for calling functions via reflection. |
|
type Invoker interface { |
|
// Invoke attempts to call the interface{} provided as a function, |
|
// providing dependencies for function arguments based on Type. Returns |
|
// a slice of reflect.Value representing the returned values of the function. |
|
// Returns an error if the injection fails. |
|
Invoke(interface{}) ([]reflect.Value, error) |
|
} |
|
|
|
// FastInvoker represents an interface in order to avoid the calling function via reflection. |
|
// |
|
// example: |
|
// type handlerFuncHandler func(http.ResponseWriter, *http.Request) error |
|
// func (f handlerFuncHandler)Invoke([]interface{}) ([]reflect.Value, error){ |
|
// ret := f(p[0].(http.ResponseWriter), p[1].(*http.Request)) |
|
// return []reflect.Value{reflect.ValueOf(ret)}, nil |
|
// } |
|
// |
|
// type funcHandler func(int, string) |
|
// func (f funcHandler)Invoke([]interface{}) ([]reflect.Value, error){ |
|
// f(p[0].(int), p[1].(string)) |
|
// return nil, nil |
|
// } |
|
type FastInvoker interface { |
|
// Invoke attempts to call the ordinary functions. If f is a function |
|
// with the appropriate signature, f.Invoke([]interface{}) is a Call that calls f. |
|
// Returns a slice of reflect.Value representing the returned values of the function. |
|
// Returns an error if the injection fails. |
|
Invoke([]interface{}) ([]reflect.Value, error) |
|
} |
|
|
|
// IsFastInvoker check interface is FastInvoker |
|
func IsFastInvoker(h interface{}) bool { |
|
_, ok := h.(FastInvoker) |
|
return ok |
|
} |
|
|
|
// TypeMapper represents an interface for mapping interface{} values based on type. |
|
type TypeMapper interface { |
|
// Maps the interface{} value based on its immediate type from reflect.TypeOf. |
|
Map(interface{}) TypeMapper |
|
// Maps the interface{} value based on the pointer of an Interface provided. |
|
// This is really only useful for mapping a value as an interface, as interfaces |
|
// cannot at this time be referenced directly without a pointer. |
|
MapTo(interface{}, interface{}) TypeMapper |
|
// Provides a possibility to directly insert a mapping based on type and value. |
|
// This makes it possible to directly map type arguments not possible to instantiate |
|
// with reflect like unidirectional channels. |
|
Set(reflect.Type, reflect.Value) TypeMapper |
|
// Returns the Value that is mapped to the current type. Returns a zeroed Value if |
|
// the Type has not been mapped. |
|
GetVal(reflect.Type) reflect.Value |
|
} |
|
|
|
type injector struct { |
|
values map[reflect.Type]reflect.Value |
|
parent Injector |
|
} |
|
|
|
// InterfaceOf dereferences a pointer to an Interface type. |
|
// It panics if value is not an pointer to an interface. |
|
func InterfaceOf(value interface{}) reflect.Type { |
|
t := reflect.TypeOf(value) |
|
|
|
for t.Kind() == reflect.Ptr { |
|
t = t.Elem() |
|
} |
|
|
|
if t.Kind() != reflect.Interface { |
|
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") |
|
} |
|
|
|
return t |
|
} |
|
|
|
// New returns a new Injector. |
|
func New() Injector { |
|
return &injector{ |
|
values: make(map[reflect.Type]reflect.Value), |
|
} |
|
} |
|
|
|
// Invoke attempts to call the interface{} provided as a function, |
|
// providing dependencies for function arguments based on Type. |
|
// Returns a slice of reflect.Value representing the returned values of the function. |
|
// Returns an error if the injection fails. |
|
// It panics if f is not a function |
|
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { |
|
t := reflect.TypeOf(f) |
|
switch v := f.(type) { |
|
case FastInvoker: |
|
return inj.fastInvoke(v, t, t.NumIn()) |
|
default: |
|
return inj.callInvoke(f, t, t.NumIn()) |
|
} |
|
} |
|
|
|
func (inj *injector) fastInvoke(f FastInvoker, t reflect.Type, numIn int) ([]reflect.Value, error) { |
|
var in []interface{} |
|
if numIn > 0 { |
|
in = make([]interface{}, numIn) // Panic if t is not kind of Func |
|
var argType reflect.Type |
|
var val reflect.Value |
|
for i := 0; i < numIn; i++ { |
|
argType = t.In(i) |
|
val = inj.GetVal(argType) |
|
if !val.IsValid() { |
|
return nil, fmt.Errorf("Value not found for type %v", argType) |
|
} |
|
|
|
in[i] = val.Interface() |
|
} |
|
} |
|
return f.Invoke(in) |
|
} |
|
|
|
// callInvoke reflect.Value.Call |
|
func (inj *injector) callInvoke(f interface{}, t reflect.Type, numIn int) ([]reflect.Value, error) { |
|
var in []reflect.Value |
|
if numIn > 0 { |
|
in = make([]reflect.Value, numIn) |
|
var argType reflect.Type |
|
var val reflect.Value |
|
for i := 0; i < numIn; i++ { |
|
argType = t.In(i) |
|
val = inj.GetVal(argType) |
|
if !val.IsValid() { |
|
return nil, fmt.Errorf("Value not found for type %v", argType) |
|
} |
|
|
|
in[i] = val |
|
} |
|
} |
|
return reflect.ValueOf(f).Call(in), nil |
|
} |
|
|
|
// Maps dependencies in the Type map to each field in the struct |
|
// that is tagged with 'inject'. |
|
// Returns an error if the injection fails. |
|
func (inj *injector) Apply(val interface{}) error { |
|
v := reflect.ValueOf(val) |
|
|
|
for v.Kind() == reflect.Ptr { |
|
v = v.Elem() |
|
} |
|
|
|
if v.Kind() != reflect.Struct { |
|
return nil // Should not panic here ? |
|
} |
|
|
|
t := v.Type() |
|
|
|
for i := 0; i < v.NumField(); i++ { |
|
f := v.Field(i) |
|
structField := t.Field(i) |
|
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") { |
|
ft := f.Type() |
|
v := inj.GetVal(ft) |
|
if !v.IsValid() { |
|
return fmt.Errorf("Value not found for type %v", ft) |
|
} |
|
|
|
f.Set(v) |
|
} |
|
|
|
} |
|
|
|
return nil |
|
} |
|
|
|
// Maps the concrete value of val to its dynamic type using reflect.TypeOf, |
|
// It returns the TypeMapper registered in. |
|
func (i *injector) Map(val interface{}) TypeMapper { |
|
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) |
|
return i |
|
} |
|
|
|
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { |
|
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) |
|
return i |
|
} |
|
|
|
// Maps the given reflect.Type to the given reflect.Value and returns |
|
// the Typemapper the mapping has been registered in. |
|
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { |
|
i.values[typ] = val |
|
return i |
|
} |
|
|
|
func (i *injector) GetVal(t reflect.Type) reflect.Value { |
|
val := i.values[t] |
|
|
|
if val.IsValid() { |
|
return val |
|
} |
|
|
|
// no concrete types found, try to find implementors |
|
// if t is an interface |
|
if t.Kind() == reflect.Interface { |
|
for k, v := range i.values { |
|
if k.Implements(t) { |
|
val = v |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Still no type found, try to look it up on the parent |
|
if !val.IsValid() && i.parent != nil { |
|
val = i.parent.GetVal(t) |
|
} |
|
|
|
return val |
|
|
|
} |
|
|
|
func (i *injector) SetParent(parent Injector) { |
|
i.parent = parent |
|
}
|
|
|