package seq import ( "reflect" "dev.hexasoftware.com/hxs/prettylog" ) var ( log = prettylog.New("Seq") ) type Entry struct { desc string fn reflect.Value seqFn func(sc *Context) error param []Param grab []reflect.Value } // Helper type Seq struct { seq []*Entry last *Entry } func NewSeq() *Seq { return &Seq{[]*Entry{}, nil} } func (s *Seq) Add(params ...interface{}) *Seq { entry := &Entry{} fni := 0 if v, ok := params[0].(string); ok { entry.desc = v fni = 1 } fn := params[fni] if v, ok := fn.(func(s *Context) error); ok { log.Println("Special func") entry.seqFn = v } else { entry.fn = reflect.ValueOf(fn) fnTyp := reflect.TypeOf(fn) if fnTyp.Kind() != reflect.Func { log.Fatal("First param must be a function") } vparam := []Param{} for _, p := range params[fni+1:] { sp := Param{} switch v := p.(type) { case Param: sp = v default: sp.typ = 0 sp.param = reflect.ValueOf(p) } vparam = append(vparam, sp) } entry.param = vparam } s.seq = append(s.seq, entry) s.last = entry return s } func (s *Seq) Grab(grab ...interface{}) { if s.last == nil { return } for _, g := range grab { gv := reflect.ValueOf(g) if gv.Kind() != reflect.Ptr { panic("Grab should be pointer") } s.last.grab = append(s.last.grab, gv) } } func (s *Seq) Exec(eparam ...interface{}) error { sCon := NewContext() sCon.params = eparam for _, e := range s.seq { if e.seqFn != nil { err := e.seqFn(sCon) sCon.Log("E:", e.desc, "=>", err) if err != nil { return err } continue } param := []reflect.Value{} for _, p := range e.param { var val reflect.Value switch p.typ { case 0: val = p.param case 1: val = reflect.ValueOf(sCon.Ret(p.nres, p.ires)) case 2: val = reflect.Indirect(reflect.ValueOf(eparam[p.nres])) } param = append(param, val) } retVal := e.fn.Call(param) iretList := []interface{}{} for i, r := range retVal { // Populate grabs if i < len(e.grab) { e.grab[i].Elem().Set(r) } iret := r.Interface() if err, ok := iret.(error); ok { return err } iretList = append(iretList, iret) } sCon.ret = append(sCon.ret, iretList) if e.desc != "" { // Only if we have a description sCon.Log("E:", e.desc, "=>", iretList) } } sCon.LogRep() return nil }