lotus/node/options.go

157 lines
3.6 KiB
Go
Raw Permalink Normal View History

2019-07-04 15:50:48 +00:00
package node
import (
"reflect"
"go.uber.org/fx"
2019-07-04 15:50:48 +00:00
)
2019-07-04 20:06:02 +00:00
// 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
2019-07-10 13:06:04 +00:00
type Option func(*Settings) error
2019-07-04 15:50:48 +00:00
2019-07-04 20:06:02 +00:00
// Options groups multiple options into one
2019-07-04 15:50:48 +00:00
func Options(opts ...Option) Option {
2019-07-10 13:06:04 +00:00
return func(s *Settings) error {
2019-07-04 15:50:48 +00:00
for _, opt := range opts {
if err := opt(s); err != nil {
return err
}
}
return nil
}
}
2019-07-04 20:06:02 +00:00
// Error is a special option which returns an error when applied
2019-07-04 15:50:48 +00:00
func Error(err error) Option {
2019-07-10 13:06:04 +00:00
return func(_ *Settings) error {
2019-07-04 15:50:48 +00:00
return err
}
}
2019-07-10 13:06:04 +00:00
func ApplyIf(check func(s *Settings) bool, opts ...Option) Option {
return func(s *Settings) error {
2019-07-04 15:50:48 +00:00
if check(s) {
return Options(opts...)(s)
}
return nil
}
}
2019-11-20 20:31:00 +00:00
func If(b bool, opts ...Option) Option {
return ApplyIf(func(s *Settings) bool {
return b
}, opts...)
}
2019-10-23 11:02:00 +00:00
// 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
}
}
2020-03-04 19:42:49 +00:00
// From(*T) -> func(t T) T {return t}
func From(typ interface{}) interface{} {
rt := []reflect.Type{reflect.TypeOf(typ).Elem()}
ft := reflect.FuncOf(rt, rt, false)
return reflect.MakeFunc(ft, func(args []reflect.Value) (results []reflect.Value) {
return args
}).Interface()
}
2019-07-04 15:50:48 +00:00
// 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)
2019-07-04 15:50:48 +00:00
out := reflect.New(outType.Elem())
if outs[0].Type().AssignableTo(outType.Elem()) {
// Out: Iface = In: *Struct; Out: Iface = In: OtherIface
out.Elem().Set(outs[0])
} else {
// Out: Iface = &(In: Struct)
t := reflect.New(outs[0].Type())
t.Elem().Set(outs[0])
out.Elem().Set(t)
}
2019-07-04 15:50:48 +00:00
outs[0] = out.Elem()
return outs
}).Interface()
}