package cache import ( "io" ) type ReaderAtCloser interface { io.ReaderAt io.Closer } type readerAtCloser struct { offset int64 rc io.ReadCloser ra io.ReaderAt open func(offset int64) (io.ReadCloser, error) closed bool } func NewReaderAtCloser(open func(offset int64) (io.ReadCloser, error)) ReaderAtCloser { return &readerAtCloser{ open: open, } } func (hrs *readerAtCloser) ReadAt(p []byte, off int64) (n int, err error) { if hrs.closed { return 0, io.EOF } if hrs.ra != nil { return hrs.ra.ReadAt(p, off) } if hrs.rc == nil || off != hrs.offset { if hrs.rc != nil { hrs.rc.Close() hrs.rc = nil } rc, err := hrs.open(off) if err != nil { return 0, err } hrs.rc = rc } if ra, ok := hrs.rc.(io.ReaderAt); ok { hrs.ra = ra n, err = ra.ReadAt(p, off) } else { for { var nn int nn, err = hrs.rc.Read(p) n += nn p = p[nn:] if nn == len(p) || err != nil { break } } } hrs.offset += int64(n) return } func (hrs *readerAtCloser) Close() error { if hrs.closed { return nil } hrs.closed = true if hrs.rc != nil { return hrs.rc.Close() } return nil } type rc struct { io.ReaderAt offset int } func (r *rc) Read(b []byte) (int, error) { n, err := r.ReadAt(b, int64(r.offset)) r.offset += n if n > 0 && err == io.EOF { err = nil } return n, err }