|
@@ -13,13 +13,7 @@ import (
|
|
|
|
|
|
// Data interface
|
|
|
type Data = interface{}
|
|
|
-
|
|
|
-type opEntry struct {
|
|
|
- sync.Mutex
|
|
|
- name string
|
|
|
- inputs []*operation // still figuring, might be operation
|
|
|
- executor interface{}
|
|
|
-}
|
|
|
+type executorFunc func(...Data) Data
|
|
|
|
|
|
// Flow structure
|
|
|
// We could Create a single array of operations
|
|
@@ -74,9 +68,9 @@ func (f *Flow) Must(op Operation, err error) Operation {
|
|
|
|
|
|
// Res returns a deferred operation result
|
|
|
// passing the Id
|
|
|
-func (f *Flow) Res(id string) Operation {
|
|
|
- return opFunc(f, id)
|
|
|
-}
|
|
|
+/*func (f *Flow) Res(id string) Operation {
|
|
|
+ return deferred(f, id)
|
|
|
+}*/
|
|
|
|
|
|
// DefOp Manual tag an Operation
|
|
|
func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation, error) {
|
|
@@ -98,17 +92,115 @@ func (f *Flow) DefOp(id string, name string, params ...interface{}) (Operation,
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- f.operations.Store(id, &opEntry{sync.Mutex{}, name, inputs, executor})
|
|
|
- return opFunc(f, id), nil
|
|
|
+ opEntry := &operation{
|
|
|
+ Mutex: sync.Mutex{},
|
|
|
+ id: id,
|
|
|
+ flow: f,
|
|
|
+ name: name,
|
|
|
+ kind: "func",
|
|
|
+ inputs: inputs,
|
|
|
+ setter: nil, // No set
|
|
|
+ executor: executor,
|
|
|
+ }
|
|
|
+ f.operations.Store(id, opEntry)
|
|
|
+
|
|
|
+ return opEntry, nil
|
|
|
+}
|
|
|
+
|
|
|
+// DefErrOp define a nil operation that will return error
|
|
|
+// Usefull for builders
|
|
|
+func (f *Flow) DefErrOp(id string, err error) (Operation, error) {
|
|
|
+ executor := func() error { return err }
|
|
|
+ opEntry := &operation{
|
|
|
+ Mutex: sync.Mutex{},
|
|
|
+ id: id,
|
|
|
+ flow: f,
|
|
|
+ name: fmt.Sprintf("(error)<%v>", err),
|
|
|
+ kind: "error",
|
|
|
+ inputs: nil,
|
|
|
+ setter: nil,
|
|
|
+ executor: executor,
|
|
|
+ }
|
|
|
+ f.operations.Store(id, opEntry)
|
|
|
+ return opEntry, nil
|
|
|
+}
|
|
|
+
|
|
|
+// DefConst define a const by defined ID
|
|
|
+func (f *Flow) DefConst(id string, value Data) (Operation, error) {
|
|
|
+ // Optimize this definition
|
|
|
+ f.consts[id] = value
|
|
|
+ executor := func() Data { return f.consts[id] }
|
|
|
+ opEntry := &operation{
|
|
|
+ id: id,
|
|
|
+ Mutex: sync.Mutex{},
|
|
|
+ flow: f,
|
|
|
+ name: fmt.Sprintf("(const)<%s>", id),
|
|
|
+ kind: "const",
|
|
|
+ inputs: nil,
|
|
|
+ setter: nil,
|
|
|
+ executor: executor,
|
|
|
+ }
|
|
|
+ f.operations.Store(id, opEntry)
|
|
|
+
|
|
|
+ return opEntry, nil
|
|
|
+}
|
|
|
+
|
|
|
+// DefIn flow input operator
|
|
|
+// paramID - index of the parameter
|
|
|
+func (f *Flow) DefIn(id string, paramID int) Operation {
|
|
|
+ executor := func(params ...Data) Data {
|
|
|
+ return params[paramID]
|
|
|
+ }
|
|
|
+ opEntry := &operation{
|
|
|
+ id: id,
|
|
|
+ Mutex: sync.Mutex{},
|
|
|
+ flow: f,
|
|
|
+ name: fmt.Sprintf("(in)<%s>", id),
|
|
|
+ kind: "in",
|
|
|
+ inputs: nil,
|
|
|
+ setter: nil,
|
|
|
+ executor: executor,
|
|
|
+ }
|
|
|
+ f.operations.Store(id, opEntry)
|
|
|
+ //return opIn(f, paramID)
|
|
|
+ return opEntry
|
|
|
+}
|
|
|
+
|
|
|
+// DefVar define var operation with optional initial
|
|
|
+func (f *Flow) DefVar(id string, name string, initial ...Data) Operation {
|
|
|
+ // Unique
|
|
|
+ if _, ok := f.data[name]; !ok {
|
|
|
+ var v interface{}
|
|
|
+ if len(initial) > 0 {
|
|
|
+ v = initial[0]
|
|
|
+ }
|
|
|
+ f.data[name] = v
|
|
|
+ }
|
|
|
+ setter := func(v Data) { f.data[name] = v }
|
|
|
+ executor := func() Data { return f.data[name] }
|
|
|
+
|
|
|
+ opEntry := &operation{
|
|
|
+ Mutex: sync.Mutex{},
|
|
|
+ id: id,
|
|
|
+ flow: f,
|
|
|
+ name: fmt.Sprintf("(var)<%s>", name),
|
|
|
+ kind: "var",
|
|
|
+ inputs: nil,
|
|
|
+ setter: setter,
|
|
|
+ executor: executor,
|
|
|
+ }
|
|
|
+ f.operations.Store(id, opEntry)
|
|
|
+ return opEntry
|
|
|
}
|
|
|
|
|
|
+// Auto ID generation
|
|
|
+
|
|
|
// Op return an function operator
|
|
|
// name - a previous registered function
|
|
|
// params - the function inputs
|
|
|
func (f *Flow) Op(name string, params ...interface{}) (Operation, error) {
|
|
|
var op Operation
|
|
|
var err error
|
|
|
-
|
|
|
allocErr := f.allocID(func(id string) error {
|
|
|
op, err = f.DefOp(id, name, params...)
|
|
|
return err
|
|
@@ -119,14 +211,6 @@ func (f *Flow) Op(name string, params ...interface{}) (Operation, error) {
|
|
|
return op, err
|
|
|
}
|
|
|
|
|
|
-// DefErrOp define a nil operation that will return error
|
|
|
-// Usefull for builders
|
|
|
-func (f *Flow) DefErrOp(id string, err error) (Operation, error) {
|
|
|
- executor := func() error { return err }
|
|
|
- f.operations.Store(id, &opEntry{sync.Mutex{}, fmt.Sprintf("(error)<%v>", err), nil, executor})
|
|
|
- return opFunc(f, id), nil
|
|
|
-}
|
|
|
-
|
|
|
// ErrOp error operation with generated ID
|
|
|
func (f *Flow) ErrOp(operr error) (Operation, error) {
|
|
|
var op Operation
|
|
@@ -142,14 +226,6 @@ func (f *Flow) ErrOp(operr error) (Operation, error) {
|
|
|
return op, err
|
|
|
}
|
|
|
|
|
|
-// DefConst define a const by defined ID
|
|
|
-func (f *Flow) DefConst(id string, value Data) (Operation, error) {
|
|
|
- f.consts[id] = value
|
|
|
- executor := func() Data { return f.consts[id] }
|
|
|
- f.operations.Store(id, &opEntry{sync.Mutex{}, fmt.Sprintf("(const)<%s>", id), nil, executor})
|
|
|
- return opFunc(f, id), nil
|
|
|
-}
|
|
|
-
|
|
|
// Const returns a const operation with generated ID
|
|
|
func (f *Flow) Const(value Data) (Operation, error) {
|
|
|
var op Operation
|
|
@@ -166,20 +242,29 @@ func (f *Flow) Const(value Data) (Operation, error) {
|
|
|
|
|
|
// Var operation
|
|
|
func (f *Flow) Var(name string, initial ...Data) Operation {
|
|
|
- if _, ok := f.data[name]; !ok {
|
|
|
- var v interface{}
|
|
|
- if len(initial) > 0 {
|
|
|
- v = initial[0]
|
|
|
- }
|
|
|
- f.data[name] = v
|
|
|
+ var op Operation
|
|
|
+ err := f.allocID(func(id string) error {
|
|
|
+ op = f.DefVar(id, name, initial...)
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
}
|
|
|
- return opVar(f, name)
|
|
|
+ return op
|
|
|
}
|
|
|
|
|
|
-// In flow input operator
|
|
|
-// paramID - index of the parameter
|
|
|
-func (f *Flow) In(paramID int) Operation {
|
|
|
- return opIn(f, paramID)
|
|
|
+// In input operation
|
|
|
+func (f *Flow) In(paramID int) (Operation, error) {
|
|
|
+ var op Operation
|
|
|
+ err := f.allocID(func(id string) error {
|
|
|
+ op = f.DefIn(id, paramID)
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return op, nil
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// Analyse every operations
|
|
@@ -189,7 +274,7 @@ func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
|
}
|
|
|
fmt.Fprintf(w, "Ops analysis:\n")
|
|
|
f.operations.Range(func(pk, po interface{}) bool {
|
|
|
- k, op := pk.(string), po.(*opEntry)
|
|
|
+ k, op := pk.(string), po.(*operation)
|
|
|
fw := bytes.NewBuffer(nil)
|
|
|
//fmt.Fprintf(w, " [%s] (%v)", k, op.name)
|
|
|
fmt.Fprintf(fw, " [%s] %s(", pk, op.name)
|
|
@@ -203,12 +288,12 @@ func (f *Flow) Analyse(w io.Writer, params ...Data) {
|
|
|
fmt.Fprintf(w, "Operator: %s error#%s\n", op.name, err)
|
|
|
return false
|
|
|
}
|
|
|
- fmt.Fprintf(fw, " %s[%v](%v)", in.kind, in.id, ires)
|
|
|
+ fmt.Fprintf(fw, " %s[%v](%v)", op.kind, op.id, ires)
|
|
|
}
|
|
|
fmt.Fprintf(fw, ") - ")
|
|
|
// Create OpProcessor and execute
|
|
|
//
|
|
|
- opfn := opFunc(f, k)
|
|
|
+ opfn := f.GetOp(k)
|
|
|
res, err := opfn.Process(params...)
|
|
|
if err != nil {
|
|
|
fmt.Fprintf(fw, "ERR\n")
|
|
@@ -239,14 +324,14 @@ func (f *Flow) String() string {
|
|
|
|
|
|
fmt.Fprintf(ret, "funcs:\n")
|
|
|
f.operations.Range(func(pk, pv interface{}) bool {
|
|
|
- k, v := pk.(string), pv.(*opEntry)
|
|
|
+ k, v := pk.(string), pv.(*operation)
|
|
|
|
|
|
fmt.Fprintf(ret, " [%s] %s(", k, v.name)
|
|
|
for j, in := range v.inputs {
|
|
|
if j != 0 {
|
|
|
fmt.Fprintf(ret, ", ")
|
|
|
}
|
|
|
- fmt.Fprintf(ret, "%s[%v]", in.kind, in.id)
|
|
|
+ fmt.Fprintf(ret, "%s[%v]", "func", in.ID())
|
|
|
}
|
|
|
fmt.Fprintf(ret, ")\n")
|
|
|
return true
|
|
@@ -264,7 +349,7 @@ func (f *Flow) MarshalJSON() ([]byte, error) {
|
|
|
}
|
|
|
operations := map[string]opMarshal{}
|
|
|
f.operations.Range(func(pk, po interface{}) bool {
|
|
|
- k, o := pk.(string), po.(*opEntry)
|
|
|
+ k, o := pk.(string), po.(*operation)
|
|
|
refs := []map[string]interface{}{}
|
|
|
for _, in := range o.inputs { // Switch type?
|
|
|
refs = append(refs, map[string]interface{}{
|
|
@@ -315,7 +400,7 @@ func (f *Flow) allocID(fn func(id string) error) error {
|
|
|
|
|
|
}
|
|
|
|
|
|
-func (f *Flow) addEntry(entry *opEntry) (string, error) {
|
|
|
+func (f *Flow) addEntry(entry *operation) (string, error) {
|
|
|
f.Lock()
|
|
|
defer f.Unlock()
|
|
|
|
|
@@ -335,23 +420,22 @@ func (f *Flow) addEntry(entry *opEntry) (string, error) {
|
|
|
/////////////////
|
|
|
// Async data
|
|
|
/////
|
|
|
-func (f *Flow) getOp(id string) (*opEntry, bool) {
|
|
|
+func (f *Flow) getOp(id string) (*operation, bool) {
|
|
|
|
|
|
o, ok := f.operations.Load(id)
|
|
|
if !ok {
|
|
|
return nil, false
|
|
|
}
|
|
|
- return o.(*opEntry), true
|
|
|
+ return o.(*operation), true
|
|
|
}
|
|
|
|
|
|
// GetOp Return an existing operation or return notfound error
|
|
|
func (f *Flow) GetOp(id string) Operation {
|
|
|
- _, ok := f.operations.Load(id)
|
|
|
+ op, ok := f.operations.Load(id)
|
|
|
if !ok {
|
|
|
return nil
|
|
|
}
|
|
|
- return opFunc(f, id)
|
|
|
-
|
|
|
+ return op.(Operation)
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////
|