7
"github.com/juju/errors"
10
// SizeReaderAt combines io.ReaderAt with a Size method.
11
type SizeReaderAt interface {
12
// Size returns the size of the data readable
18
// NewMultiReaderAt is like io.MultiReader but produces a ReaderAt
19
// (and Size), instead of just a reader.
21
// Note: this implementation was taken from a talk given
22
// by Brad Fitzpatrick as OSCON 2013.
24
// http://talks.golang.org/2013/oscon-dl.slide#49
25
// https://github.com/golang/talks/blob/master/2013/oscon-dl/server-compose.go
26
func NewMultiReaderAt(parts ...SizeReaderAt) SizeReaderAt {
28
parts: make([]offsetAndSource, 0, len(parts)),
31
for _, p := range parts {
32
m.parts = append(m.parts, offsetAndSource{off, p})
39
type offsetAndSource struct {
44
type multiReaderAt struct {
45
parts []offsetAndSource
49
func (m *multiReaderAt) Size() int64 {
53
func (m *multiReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
56
// Skip past the requested offset.
57
skipParts := sort.Search(len(m.parts), func(i int) bool {
58
// This function returns whether parts[i] will
59
// contribute any bytes to our output.
61
return part.off+part.Size() > off
63
parts := m.parts[skipParts:]
65
// How far to skip in the first part.
68
needSkip -= parts[0].off
71
for len(parts) > 0 && len(p) > 0 {
73
partSize := parts[0].Size()
74
if int64(len(readP)) > partSize-needSkip {
75
readP = readP[:partSize-needSkip]
77
pn, err0 := parts[0].ReadAt(readP, needSkip)
83
if int64(pn)+needSkip == partSize {
90
err = io.ErrUnexpectedEOF
95
// NewMultiReaderSeeker returns an io.ReadSeeker that combines
96
// all the given readers into a single one. It assumes that
97
// all the seekers are initially positioned at the start.
98
func NewMultiReaderSeeker(readers ...io.ReadSeeker) io.ReadSeeker {
99
sreaders := make([]SizeReaderAt, len(readers))
100
for i, r := range readers {
101
r1, err := newSizeReaderAt(r)
108
r: NewMultiReaderAt(sreaders...),
112
// newSizeReaderAt adapts an io.ReadSeeker to a SizeReaderAt.
113
// Note that it doesn't strictly adhere to the ReaderAt
114
// contract because it's not safe to call ReadAt concurrently.
115
// This doesn't matter because io.ReadSeeker doesn't
116
// need to be thread-safe and this is only used in that
118
func newSizeReaderAt(r io.ReadSeeker) (SizeReaderAt, error) {
119
size, err := r.Seek(0, 2)
123
return &sizeReaderAt{
130
// sizeReaderAt adapts an io.ReadSeeker to a SizeReaderAt.
131
type sizeReaderAt struct {
137
// ReadAt implemnts SizeReaderAt.ReadAt.
138
func (r *sizeReaderAt) ReadAt(buf []byte, off int64) (n int, err error) {
140
_, err = r.r.Seek(off, 0)
146
n, err = io.ReadFull(r.r, buf)
151
// Size implemnts SizeReaderAt.Size.
152
func (r *sizeReaderAt) Size() int64 {
156
// readSeeker adapts a SizeReaderAt to an io.ReadSeeker.
157
type readSeeker struct {
162
// Seek implements io.Seeker.Seek.
163
func (r *readSeeker) Seek(off int64, whence int) (int64, error) {
169
off = r.r.Size() + off
172
return 0, errors.New("negative position")
178
// Read implements io.Reader.Read.
179
func (r *readSeeker) Read(buf []byte) (int, error) {
180
n, err := r.r.ReadAt(buf, r.off)
182
if err == io.ErrUnexpectedEOF {