package vnode import ( "fmt" "log" "reflect" ) type IVNode interface { Result() interface{} } const ( OPT_VAR = iota OPT_FUNC OPT_FUNCI OPT_SFUNC ) type Result interface{} type VNodeFunc func(*VNode) Result type SourceEntry struct { fnInputType reflect.Type srcInputInterface interface{} srcInputValue reflect.Value // srcInputFn func() interface{} //iface interface{} Value func() reflect.Value //fnHandler func() reflect.Value opType int } type VNode struct { sourceList []SourceEntry mainFuncValue reflect.Value specialFn func(...interface{}) interface{} } func New(fns ...interface{}) *VNode { var vn VNode fn := fns[0] nInputs := 0 if len(fns) > 1 { nInputs = fns[1].(int) } rfn := reflect.ValueOf(fn) // Or Pointer // Check type func if rfn.Kind() != reflect.Func { log.Println("Argument should be a function") return nil } vn.mainFuncValue = rfn // could this reduce complexity?? /*var Func func(...interface{}) interface{} if rfn.Type() != reflect.TypeOf(Func) { nInputs = rfn.Type().NumIn() madeFn := reflect.MakeFunc(reflect.TypeOf(Func), func(in []reflect.Value) []reflect.Value { nargs := []reflect.Value{} for i := 0; i < in[0].Len(); i++ { narg := in[0].Index(i).Elem() nargs = append(nargs, narg) } res := rfn.Call(nargs) v := res[0].Interface() return []reflect.Value{reflect.ValueOf(&v).Elem()} }) reflect.ValueOf(&Func).Elem().Set(madeFn) fn = Func }*/ switch fn.(type) { case func(...interface{}) interface{}: vn.specialFn = fn.(func(...interface{}) interface{}) vn.sourceList = make([]SourceEntry, nInputs) for i := 0; i < nInputs; i++ { vn.sourceList[i].fnInputType = nil } default: nInputs = rfn.Type().NumIn() vn.sourceList = make([]SourceEntry, nInputs) for i := 0; i < nInputs; i++ { vn.sourceList[i].fnInputType = rfn.Type().In(i) } } return &vn } func (vn *VNode) SourceAt(i int, val interface{}) error { se := &vn.sourceList[i] // If fninputType is interface we can accept anything // Do some type checks here se.srcInputValue = reflect.ValueOf(val) if se.srcInputValue.Type() == reflect.TypeOf(vn) { se.srcInputValue = reflect.ValueOf(func() interface{} { return val.(*VNode).Exec() }) } var t func() interface{} if se.srcInputValue.Type() == reflect.TypeOf(t) { se.Value = func() reflect.Value { return reflect.ValueOf(se.srcInputValue.Interface().(func() interface{})()) } se.srcInputFn = se.srcInputValue.Interface().(func() interface{}) se.opType = OPT_SFUNC return nil } // Especial case: if se.srcInputValue.Kind() == reflect.Func { if se.srcInputValue.Type().NumOut() != 1 { // we could ignore this return fmt.Errorf("Input: %d Invalid number of returns", i) } out := se.srcInputValue.Type().Out(0) // check output type if not interface or same type /*if out.Kind() != reflect.Interface && out != se.fnInputType { return fmt.Errorf("Input: %d Type mismatch", i) }*/ if out.Kind() == reflect.Interface { se.Value = func() reflect.Value { return se.srcInputValue.Call([]reflect.Value{})[0].Elem() } se.opType = OPT_FUNCI } else { se.Value = func() reflect.Value { return se.srcInputValue.Call([]reflect.Value{})[0] } se.opType = OPT_FUNC } } else if se.srcInputValue.Type() == se.fnInputType || se.fnInputType == nil { se.Value = func() reflect.Value { return se.srcInputValue } se.srcInputInterface = se.srcInputValue.Interface() se.opType = OPT_VAR } else { return fmt.Errorf("Input: %d Didn't match", i) } //vn.sourceList[i] = se return nil } func (vn *VNode) Source(vnodes ...interface{}) error { for i, vnode := range vnodes { err := vn.SourceAt(i, vnode) if err != nil { return err } } return nil } // Change to execute func (vn *VNode) Exec() Result { //special case if vn.specialFn != nil { iargs := make([]interface{}, len(vn.sourceList)) for i, se := range vn.sourceList { switch se.opType { case OPT_VAR: // Direct value input iargs[i] = se.srcInputInterface case OPT_SFUNC: // Function returning interface , optimizations iargs[i] = se.srcInputFn() default: // Function call iargs[i] = se.srcInputValue.Call([]reflect.Value{})[0].Interface() //iargs[i] = se.Value().Interface() } } return vn.specialFn(iargs...) } rargs := make([]reflect.Value, len(vn.sourceList)) for i, se := range vn.sourceList { switch se.opType { case OPT_VAR: // Direct value input rargs[i] = se.srcInputValue case OPT_FUNC: rargs[i] = se.srcInputValue.Call([]reflect.Value{})[0] case OPT_FUNCI: rargs[i] = se.srcInputValue.Call([]reflect.Value{})[0].Elem() case OPT_SFUNC: // Function returning interface , optimizations rargs[i] = se.Value() default: // Function call rargs[i] = se.Value() //iargs[i] = se.srcInputValue.Call([]reflect.Value{})[0].Interface() //iargs[i] = se.Value().Interface() } } return vn.mainFuncValue.Call(rargs)[0].Interface() } // Exec input here /*func (vn *VNode) input(i int) interface{} { in := vn.sourceList[i] return in.fnHandler().Interface() }*/