mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-11-29 03:52:51 +03:00
82 lines
1.6 KiB
Go
82 lines
1.6 KiB
Go
package rr
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
var ErrClosed = errors.New("RestartReader: closed")
|
|
|
|
type RestartReader struct {
|
|
r io.ReadCloser
|
|
buf []byte
|
|
|
|
// Where in the buffer we are. If it's equal to len(buf) then the reader
|
|
// should be used.
|
|
i int64
|
|
}
|
|
|
|
func (rr *RestartReader) Read(p []byte) (n int, err error) {
|
|
if rr.buf == nil {
|
|
return 0, ErrClosed
|
|
}
|
|
|
|
if rr.i >= int64(len(rr.buf)) {
|
|
// Read new data
|
|
tmp := make([]byte, len(p))
|
|
n, err = rr.r.Read(tmp)
|
|
if n > 0 {
|
|
rr.buf = append(rr.buf, tmp[:n]...)
|
|
copy(p, tmp[:n])
|
|
}
|
|
rr.i = int64(len(rr.buf))
|
|
return
|
|
}
|
|
|
|
// Reading from buffer
|
|
|
|
bufSize := len(rr.buf[rr.i:])
|
|
|
|
if len(p) > bufSize {
|
|
// It wants more data then what's in the buffer
|
|
tmp := make([]byte, len(p)-bufSize)
|
|
n, err = rr.r.Read(tmp)
|
|
if n > 0 {
|
|
rr.buf = append(rr.buf, tmp[:n]...)
|
|
}
|
|
copy(p, rr.buf[rr.i:])
|
|
n += bufSize
|
|
rr.i = int64(len(rr.buf))
|
|
return
|
|
}
|
|
// All the required data is in the buffer
|
|
end := rr.i + int64(len(p))
|
|
copy(p, rr.buf[rr.i:end])
|
|
rr.i = end
|
|
n = len(p)
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
// Restart causes subsequent Read calls to read from the beginning, instead
|
|
// of where they left off.
|
|
func (rr *RestartReader) Restart() {
|
|
rr.i = 0
|
|
}
|
|
|
|
// Close clears the buffer and closes the underlying io.ReadCloser, returning
|
|
// its error.
|
|
func (rr *RestartReader) Close() error {
|
|
rr.buf = nil
|
|
return rr.r.Close()
|
|
}
|
|
|
|
// NewRestartReader creates and initializes a new RestartReader that reads from
|
|
// the provided io.ReadCloser.
|
|
func NewRestartReader(r io.ReadCloser) *RestartReader {
|
|
return &RestartReader{
|
|
r: r,
|
|
buf: make([]byte, 0),
|
|
}
|
|
}
|