github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/readers/repeatable.go (about)

     1  package readers
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"sync"
     7  )
     8  
     9  // A RepeatableReader implements the io.ReadSeeker it allow to seek cached data
    10  // back and forth within the reader but will only read data from the internal Reader as necessary
    11  // and will play nicely with the Account and io.LimitedReader to reflect current speed
    12  type RepeatableReader struct {
    13  	mu sync.Mutex // protect against concurrent use
    14  	in io.Reader  // Input reader
    15  	i  int64      // current reading index
    16  	b  []byte     // internal cache buffer
    17  }
    18  
    19  var _ io.ReadSeeker = (*RepeatableReader)(nil)
    20  
    21  // Seek implements the io.Seeker interface.
    22  // If seek position is passed the cache buffer length the function will return
    23  // the maximum offset that can be used and "fs.RepeatableReader.Seek: offset is unavailable" Error
    24  func (r *RepeatableReader) Seek(offset int64, whence int) (int64, error) {
    25  	r.mu.Lock()
    26  	defer r.mu.Unlock()
    27  
    28  	var abs int64
    29  	cacheLen := int64(len(r.b))
    30  	switch whence {
    31  	case io.SeekStart:
    32  		abs = offset
    33  	case io.SeekCurrent:
    34  		abs = r.i + offset
    35  	case io.SeekEnd:
    36  		abs = cacheLen + offset
    37  	default:
    38  		return 0, errors.New("fs.RepeatableReader.Seek: invalid whence")
    39  	}
    40  	if abs < 0 {
    41  		return 0, errors.New("fs.RepeatableReader.Seek: negative position")
    42  	}
    43  	if abs > cacheLen {
    44  		return offset - (abs - cacheLen), errors.New("fs.RepeatableReader.Seek: offset is unavailable")
    45  	}
    46  	r.i = abs
    47  	return abs, nil
    48  }
    49  
    50  // Read data from original Reader into bytes
    51  // Data is either served from the underlying Reader or from cache if was already read
    52  func (r *RepeatableReader) Read(b []byte) (n int, err error) {
    53  	r.mu.Lock()
    54  	defer r.mu.Unlock()
    55  
    56  	cacheLen := int64(len(r.b))
    57  	if r.i == cacheLen {
    58  		n, err = r.in.Read(b)
    59  		if n > 0 {
    60  			r.b = append(r.b, b[:n]...)
    61  		}
    62  	} else {
    63  		n = copy(b, r.b[r.i:])
    64  	}
    65  	r.i += int64(n)
    66  	return n, err
    67  }
    68  
    69  // NewRepeatableReader create new repeatable reader from Reader r
    70  func NewRepeatableReader(r io.Reader) *RepeatableReader {
    71  	return &RepeatableReader{in: r}
    72  }
    73  
    74  // NewRepeatableReaderSized create new repeatable reader from Reader r
    75  // with an initial buffer of size.
    76  func NewRepeatableReaderSized(r io.Reader, size int) *RepeatableReader {
    77  	return &RepeatableReader{
    78  		in: r,
    79  		b:  make([]byte, 0, size),
    80  	}
    81  }
    82  
    83  // NewRepeatableLimitReader create new repeatable reader from Reader r
    84  // with an initial buffer of size wrapped in an io.LimitReader to read
    85  // only size.
    86  func NewRepeatableLimitReader(r io.Reader, size int) *RepeatableReader {
    87  	return NewRepeatableReaderSized(io.LimitReader(r, int64(size)), size)
    88  }
    89  
    90  // NewRepeatableReaderBuffer create new repeatable reader from Reader r
    91  // using the buffer passed in.
    92  func NewRepeatableReaderBuffer(r io.Reader, buf []byte) *RepeatableReader {
    93  	return &RepeatableReader{
    94  		in: r,
    95  		b:  buf[:0],
    96  	}
    97  }
    98  
    99  // NewRepeatableLimitReaderBuffer create new repeatable reader from
   100  // Reader r and buf wrapped in an io.LimitReader to read only size.
   101  func NewRepeatableLimitReaderBuffer(r io.Reader, buf []byte, size int64) *RepeatableReader {
   102  	return NewRepeatableReaderBuffer(io.LimitReader(r, size), buf)
   103  }