github.com/haraldrudell/parl@v0.4.176/iters/function.go (about)

     1  /*
     2  © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package iters
     7  
     8  import (
     9  	"github.com/haraldrudell/parl/internal/cyclebreaker"
    10  	"github.com/haraldrudell/parl/perrors"
    11  )
    12  
    13  // Function traverses a function generating values
    14  type Function[T any] struct {
    15  	// IteratorFunction is a function that can be used with function iterator
    16  	//   - if isCancel true, it means this is the last invocation of IteratorFunction and
    17  	//     IteratorFunction should release any resources.
    18  	//     Any returned value is not used
    19  	//   - IteratorFunction signals end of values by returning parl.ErrEndCallbacks.
    20  	//     if hasValue true, the accompanying value is used
    21  	//   - if IteratorFunction returns error, it will not be invoked again.
    22  	//     Any returned value is not used
    23  	//   - IteratorFunction must be thread-safe
    24  	//   - IteratorFunction is invoked by at most one thread at a time
    25  	iteratorFunction IteratorFunction[T]
    26  	// BaseIterator implements the DelegateAction[T] function required by
    27  	// Delegator[T] and Cancel
    28  	//	- provides its delegateAction method to Delegator
    29  	*BaseIterator[T]
    30  }
    31  
    32  // NewFunctionIterator returns an [Iterator] iterating over a function
    33  //   - thread-safe
    34  func NewFunctionIterator[T any](
    35  	iteratorFunction IteratorFunction[T],
    36  	asyncCancel ...func(),
    37  ) (iterator Iterator[T]) {
    38  	if iteratorFunction == nil {
    39  		panic(cyclebreaker.NilError("iteratorFunction"))
    40  	}
    41  	f := &Function[T]{iteratorFunction: iteratorFunction}
    42  	f.BaseIterator = NewBaseIterator[T](f.iteratorAction, asyncCancel...)
    43  	return f
    44  }
    45  
    46  // Init implements the right-hand side of a short variable declaration in
    47  // the init statement for a Go “for” clause
    48  //
    49  // Usage:
    50  //
    51  //		for i, iterator := NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); {
    52  //	   // i is pointer to slice element
    53  func (i *Function[T]) Init() (iterationVariable T, iterator Iterator[T]) {
    54  	iterator = i
    55  	return
    56  }
    57  
    58  // baseIteratorRequest invokes fn recovering a possible panic
    59  //   - if cancelState == notCanceled, a new value is requested.
    60  //     Otherwise, iteration cancel is requested
    61  //   - if err is nil, value is valid and isPanic false.
    62  //     Otherwise, err is non-nil and isPanic may be set.
    63  //     value is zero-value
    64  //   - thread-safe but invocations must be serialized
    65  func (i *Function[T]) iteratorAction(isCancel bool) (value T, err error) {
    66  	// func(isCancel bool) (value T, err error)
    67  	if value, err = i.iteratorFunction(isCancel); err != nil {
    68  		err = perrors.Stack(err)
    69  	}
    70  
    71  	return
    72  }