github.com/aretext/aretext@v1.3.0/syntax/parser/tracking.go (about)

     1  package parser
     2  
     3  import (
     4  	"io"
     5  	"math"
     6  
     7  	"github.com/aretext/aretext/text"
     8  )
     9  
    10  // TrackingReader tracks the number of runes read by a reader iter and all its clones.
    11  // It updates a shared counter, so clones of this iter should NOT be used in other threads.
    12  // Copying the struct produces a new, independent iterator.
    13  type TrackingRuneIter struct {
    14  	reader  text.Reader
    15  	eof     bool
    16  	limit   uint64
    17  	numRead uint64
    18  	maxRead *uint64
    19  }
    20  
    21  // NewTrackingRuneIter starts tracking an existing rune iter.
    22  func NewTrackingRuneIter(reader text.Reader) TrackingRuneIter {
    23  	var maxRead uint64
    24  	return TrackingRuneIter{
    25  		reader:  reader,
    26  		limit:   math.MaxUint64,
    27  		maxRead: &maxRead,
    28  	}
    29  }
    30  
    31  // NextRune returns the next rune from the underlying reader and advances the iterator.
    32  func (iter *TrackingRuneIter) NextRune() (rune, error) {
    33  	if iter.limit == 0 {
    34  		return '\x00', io.EOF
    35  	}
    36  
    37  	r, _, err := iter.reader.ReadRune()
    38  
    39  	if err == nil && iter.limit > 0 {
    40  		iter.limit--
    41  	}
    42  
    43  	if err == nil || (err == io.EOF && !iter.eof) {
    44  		iter.eof = bool(err == io.EOF)
    45  		iter.numRead++
    46  		if iter.numRead > *iter.maxRead {
    47  			*iter.maxRead = iter.numRead
    48  		}
    49  	}
    50  
    51  	return r, err
    52  }
    53  
    54  // Skip advances the iterator by the specified number of positions or the end of the file, whichever comes first.
    55  func (iter *TrackingRuneIter) Skip(n uint64) uint64 {
    56  	for i := uint64(0); i < n; i++ {
    57  		_, err := iter.NextRune()
    58  		if err != nil {
    59  			return i
    60  		}
    61  	}
    62  	return n
    63  }
    64  
    65  // Limit sets the maximum number of runes this reader can produce.
    66  func (iter *TrackingRuneIter) Limit(n uint64) {
    67  	iter.limit = n
    68  }
    69  
    70  // MaxRead returns the maximum number of runes read by this iter and all its clones.
    71  func (iter *TrackingRuneIter) MaxRead() uint64 {
    72  	return *iter.maxRead
    73  }