// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // data-cursors.go package expr import ( "errors" "io" ) const ( initName = "init" cleanName = "clean" resetName = "reset" nextName = "next" currentName = "current" ) type dataCursor struct { ds map[string]Functor ctx ExprContext index int resource any nextFunc Functor cleanFunc Functor resetFunc Functor currentFunc Functor } func newDataCursor(ctx ExprContext, ds map[string]Functor) (dc *dataCursor) { dc = &dataCursor{ ds: ds, index: -1, ctx: ctx.Clone(), } return } func (dc *dataCursor) String() string { return "$(...)" } func (dc *dataCursor) HasOperation(name string) (exists bool) { f, ok := dc.ds[name] exists = ok && isFunctor(f) return } func (dc *dataCursor) CallOperation(name string) (value any, err error) { if functor, ok := dc.ds[name]; ok && isFunctor(functor) { ctx := cloneContext(dc.ctx) value, err = functor.Invoke(ctx, name, []any{}) exportObjects(dc.ctx, ctx) } else { err = errNoOperation(name) } return } func (dc *dataCursor) Reset() (err error) { if dc.resetFunc != nil { ctx := cloneContext(dc.ctx) if _, err = dc.resetFunc.Invoke(ctx, resetName, []any{}); err == nil { dc.index = -1 } exportObjects(dc.ctx, ctx) } else { err = errors.New("no 'reset' function defined in the data-source") } return } func (dc *dataCursor) Clean() (err error) { if dc.cleanFunc != nil { ctx := cloneContext(dc.ctx) _, err = dc.cleanFunc.Invoke(ctx, cleanName, []any{}) exportObjects(dc.ctx, ctx) } else { err = errors.New("no 'clean' function defined in the data-source") } return } func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item ctx := cloneContext(dc.ctx) if item, err = dc.currentFunc.Invoke(ctx, currentName, []any{}); err == nil && item == nil { err = io.EOF } exportObjects(dc.ctx, ctx) return } func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item ctx := cloneContext(dc.ctx) if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{}); err == nil { if item == nil { err = io.EOF } else { dc.index++ } } exportObjects(dc.ctx, ctx) return } func (dc *dataCursor) Index() int { return dc.index }