133 lines
3.0 KiB
Go
133 lines
3.0 KiB
Go
package node
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
// Option is a functional option which can be used with the New function to
|
|
// change how the node is constructed
|
|
//
|
|
// Options are applied in sequence
|
|
type Option func(*Settings) error
|
|
|
|
// Options groups multiple options into one
|
|
func Options(opts ...Option) Option {
|
|
return func(s *Settings) error {
|
|
for _, opt := range opts {
|
|
if err := opt(s); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Error is a special option which returns an error when applied
|
|
func Error(err error) Option {
|
|
return func(_ *Settings) error {
|
|
return err
|
|
}
|
|
}
|
|
|
|
func ApplyIf(check func(s *Settings) bool, opts ...Option) Option {
|
|
return func(s *Settings) error {
|
|
if check(s) {
|
|
return Options(opts...)(s)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Override option changes constructor for a given type
|
|
func Override(typ, constructor interface{}) Option {
|
|
return func(s *Settings) error {
|
|
if i, ok := typ.(invoke); ok {
|
|
s.invokes[i] = fx.Invoke(constructor)
|
|
return nil
|
|
}
|
|
|
|
if c, ok := typ.(special); ok {
|
|
s.modules[c] = fx.Provide(constructor)
|
|
return nil
|
|
}
|
|
ctor := as(constructor, typ)
|
|
rt := reflect.TypeOf(typ).Elem()
|
|
|
|
s.modules[rt] = fx.Provide(ctor)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func Unset(typ interface{}) Option {
|
|
return func(s *Settings) error {
|
|
if i, ok := typ.(invoke); ok {
|
|
s.invokes[i] = nil
|
|
return nil
|
|
}
|
|
|
|
if c, ok := typ.(special); ok {
|
|
delete(s.modules, c)
|
|
return nil
|
|
}
|
|
rt := reflect.TypeOf(typ).Elem()
|
|
|
|
delete(s.modules, rt)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// from go-ipfs
|
|
// as casts input constructor to a given interface (if a value is given, it
|
|
// wraps it into a constructor).
|
|
//
|
|
// Note: this method may look like a hack, and in fact it is one.
|
|
// This is here only because https://github.com/uber-go/fx/issues/673 wasn't
|
|
// released yet
|
|
//
|
|
// Note 2: when making changes here, make sure this method stays at
|
|
// 100% coverage. This makes it less likely it will be terribly broken
|
|
func as(in interface{}, as interface{}) interface{} {
|
|
outType := reflect.TypeOf(as)
|
|
|
|
if outType.Kind() != reflect.Ptr {
|
|
panic("outType is not a pointer")
|
|
}
|
|
|
|
if reflect.TypeOf(in).Kind() != reflect.Func {
|
|
ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false)
|
|
|
|
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
|
out := reflect.New(outType.Elem())
|
|
out.Elem().Set(reflect.ValueOf(in))
|
|
|
|
return []reflect.Value{out.Elem()}
|
|
}).Interface()
|
|
}
|
|
|
|
inType := reflect.TypeOf(in)
|
|
|
|
ins := make([]reflect.Type, inType.NumIn())
|
|
outs := make([]reflect.Type, inType.NumOut())
|
|
|
|
for i := range ins {
|
|
ins[i] = inType.In(i)
|
|
}
|
|
outs[0] = outType.Elem()
|
|
for i := range outs[1:] {
|
|
outs[i+1] = inType.Out(i + 1)
|
|
}
|
|
|
|
ctype := reflect.FuncOf(ins, outs, false)
|
|
|
|
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
|
outs := reflect.ValueOf(in).Call(args)
|
|
out := reflect.New(outType.Elem())
|
|
out.Elem().Set(outs[0])
|
|
outs[0] = out.Elem()
|
|
|
|
return outs
|
|
}).Interface()
|
|
}
|