github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/util/ioutil/seek.go (about)

     1  package ioutil
     2  
     3  import (
     4  	"io"
     5  	"sync"
     6  )
     7  
     8  // SeekingReaderAt implements [io.ReaderAt]
     9  // through an underlying [io.ReadSeeker].
    10  type SeekingReaderAt struct {
    11  	// +checklocks:l
    12  	r io.ReadSeeker
    13  	l sync.Mutex
    14  }
    15  
    16  // NewSeekingReaderAt creates a new SeekingReaderAt.
    17  // The SeekingReaderAt takes ownership of r
    18  // and will modify its seek offset,
    19  // so callers should not use r after this call.
    20  func NewSeekingReaderAt(r io.ReadSeeker) *SeekingReaderAt {
    21  	return &SeekingReaderAt{r: r}
    22  }
    23  
    24  // ReadAt implements [io.ReaderAt].
    25  func (s *SeekingReaderAt) ReadAt(p []byte, off int64) (n int, _ error) {
    26  	s.l.Lock()
    27  	defer s.l.Unlock()
    28  
    29  	_, err := s.r.Seek(off, io.SeekStart)
    30  	if err != nil {
    31  		return 0, err
    32  	}
    33  
    34  	for len(p) > 0 {
    35  		i, err := s.r.Read(p)
    36  		p = p[i:]
    37  		n += i
    38  		if err != nil {
    39  			return n, err
    40  		}
    41  	}
    42  	return n, nil
    43  }
    44  
    45  // Size implements [SizeReaderAt].
    46  func (s *SeekingReaderAt) Size() (int64, error) {
    47  	s.l.Lock()
    48  	defer s.l.Unlock()
    49  	return s.r.Seek(0, io.SeekEnd)
    50  }
    51  
    52  // ReadAt implements [io.Closer].
    53  func (s *SeekingReaderAt) Close() error {
    54  	s.l.Lock()
    55  	defer s.l.Unlock()
    56  	if c, ok := s.r.(io.Closer); ok {
    57  		s.r = nil
    58  		return c.Close()
    59  	}
    60  	return nil
    61  }