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 }