github.com/haraldrudell/parl@v0.4.176/pfs/dir-entry-iterator.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pfs
     7  
     8  import (
     9  	"io/fs"
    10  	"path/filepath"
    11  	"sync"
    12  
    13  	"github.com/haraldrudell/parl"
    14  	"github.com/haraldrudell/parl/iters"
    15  )
    16  
    17  type DirEntry struct {
    18  	fs.DirEntry
    19  	ProvidedPath string
    20  }
    21  
    22  type DirEntryIterator struct {
    23  	path string
    24  	iters.BaseIterator[DirEntry]
    25  	sliceOnce sync.Once
    26  	err       error
    27  
    28  	entriesLock sync.Mutex
    29  	entries     []fs.DirEntry
    30  }
    31  
    32  func NewDirEntryIterator(path string) (iterator iters.Iterator[DirEntry]) {
    33  	i := DirEntryIterator{path: path}
    34  	i.BaseIterator = *iters.NewBaseIterator(i.iteratorAction)
    35  	return &i
    36  }
    37  
    38  // Init implements the right-hand side of a short variable declaration in
    39  // the init statement of a Go “for” clause
    40  //
    41  //		for i, iterator := iters.NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); {
    42  //	   // i is pointer to slice element
    43  func (i *DirEntryIterator) Init() (result DirEntry, iterator iters.Iterator[DirEntry]) {
    44  	iterator = i
    45  	return
    46  }
    47  
    48  // iteratorAction provides items to the BaseIterator
    49  func (t *DirEntryIterator) iteratorAction(isCancel bool) (result DirEntry, err error) {
    50  	if isCancel {
    51  		return
    52  	}
    53  	t.sliceOnce.Do(t.loadSlice)
    54  	if err = t.err; err != nil {
    55  		return
    56  	}
    57  	result.DirEntry = t.entry()
    58  	if result.DirEntry == nil {
    59  		err = parl.ErrEndCallbacks
    60  		return
    61  	}
    62  	result.ProvidedPath = filepath.Join(t.path, result.Name())
    63  	return
    64  }
    65  
    66  func (t *DirEntryIterator) entry() (entry fs.DirEntry) {
    67  	t.entriesLock.Lock()
    68  	defer t.entriesLock.Unlock()
    69  
    70  	if len(t.entries) == 0 {
    71  		return
    72  	}
    73  	entry = t.entries[0]
    74  	t.entries[0] = nil
    75  	t.entries = t.entries[1:]
    76  
    77  	return
    78  }
    79  func (t *DirEntryIterator) loadSlice() { t.entries, t.err = ReadDir(t.path) }