Commit 7127b6fd authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

bytes,strings: make *Reader implement io.ReaderAt

R=golang-dev, adg, bradfitz, r
CC=golang-dev
https://golang.org/cl/5675053
parent b4d32d83
...@@ -278,7 +278,7 @@ func TestInvalidFiles(t *testing.T) { ...@@ -278,7 +278,7 @@ func TestInvalidFiles(t *testing.T) {
b := make([]byte, size) b := make([]byte, size)
// zeroes // zeroes
_, err := NewReader(sliceReaderAt(b), size) _, err := NewReader(bytes.NewReader(b), size)
if err != ErrFormat { if err != ErrFormat {
t.Errorf("zeroes: error=%v, want %v", err, ErrFormat) t.Errorf("zeroes: error=%v, want %v", err, ErrFormat)
} }
...@@ -289,15 +289,8 @@ func TestInvalidFiles(t *testing.T) { ...@@ -289,15 +289,8 @@ func TestInvalidFiles(t *testing.T) {
for i := 0; i < size-4; i += 4 { for i := 0; i < size-4; i += 4 {
copy(b[i:i+4], sig) copy(b[i:i+4], sig)
} }
_, err = NewReader(sliceReaderAt(b), size) _, err = NewReader(bytes.NewReader(b), size)
if err != ErrFormat { if err != ErrFormat {
t.Errorf("sigs: error=%v, want %v", err, ErrFormat) t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
} }
} }
type sliceReaderAt []byte
func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, error) {
copy(b, r[int(off):int(off)+len(b)])
return len(b), nil
}
...@@ -77,7 +77,7 @@ func TestWriter(t *testing.T) { ...@@ -77,7 +77,7 @@ func TestWriter(t *testing.T) {
} }
// read it back // read it back
r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len())) r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -9,22 +9,12 @@ package zip ...@@ -9,22 +9,12 @@ package zip
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"reflect" "reflect"
"strings"
"testing" "testing"
"time" "time"
) )
type stringReaderAt string
func (s stringReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
if off >= int64(len(s)) {
return 0, io.EOF
}
n = copy(p, s[off:])
return
}
func TestOver65kFiles(t *testing.T) { func TestOver65kFiles(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Logf("slow test; skipping") t.Logf("slow test; skipping")
...@@ -42,8 +32,8 @@ func TestOver65kFiles(t *testing.T) { ...@@ -42,8 +32,8 @@ func TestOver65kFiles(t *testing.T) {
if err := w.Close(); err != nil { if err := w.Close(); err != nil {
t.Fatalf("Writer.Close: %v", err) t.Fatalf("Writer.Close: %v", err)
} }
rat := stringReaderAt(buf.String()) s := buf.String()
zr, err := NewReader(rat, int64(len(rat))) zr, err := NewReader(strings.NewReader(s), int64(len(s)))
if err != nil { if err != nil {
t.Fatalf("NewReader: %v", err) t.Fatalf("NewReader: %v", err)
} }
......
...@@ -10,8 +10,9 @@ import ( ...@@ -10,8 +10,9 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// A Reader implements the io.Reader, io.Seeker, io.ByteScanner, and // A Reader implements the io.Reader, io.ReaderAt, io.Seeker,
// io.RuneScanner interfaces by reading from a byte slice. // io.ByteScanner, and io.RuneScanner interfaces by reading from
// a byte slice.
// Unlike a Buffer, a Reader is read-only and supports seeking. // Unlike a Buffer, a Reader is read-only and supports seeking.
type Reader struct { type Reader struct {
s []byte s []byte
...@@ -41,6 +42,20 @@ func (r *Reader) Read(b []byte) (n int, err error) { ...@@ -41,6 +42,20 @@ func (r *Reader) Read(b []byte) (n int, err error) {
return return
} }
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
if off < 0 {
return 0, errors.New("bytes: invalid offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
n = copy(b, r.s[int(off):])
if n < len(b) {
err = io.EOF
}
return
}
func (r *Reader) ReadByte() (b byte, err error) { func (r *Reader) ReadByte() (b byte, err error) {
if r.i >= len(r.s) { if r.i >= len(r.s) {
return 0, io.EOF return 0, io.EOF
......
...@@ -6,6 +6,8 @@ package bytes_test ...@@ -6,6 +6,8 @@ package bytes_test
import ( import (
. "bytes" . "bytes"
"fmt"
"io"
"os" "os"
"testing" "testing"
) )
...@@ -56,3 +58,31 @@ func TestReader(t *testing.T) { ...@@ -56,3 +58,31 @@ func TestReader(t *testing.T) {
} }
} }
} }
func TestReaderAt(t *testing.T) {
r := NewReader([]byte("0123456789"))
tests := []struct {
off int64
n int
want string
wanterr interface{}
}{
{0, 10, "0123456789", nil},
{1, 10, "123456789", io.EOF},
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
{-1, 0, "", "bytes: invalid offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
rn, err := r.ReadAt(b, tt.off)
got := string(b[:rn])
if got != tt.want {
t.Errorf("%d. got %q; want %q", i, got, tt.want)
}
if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) {
t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr)
}
}
}
...@@ -130,7 +130,7 @@ type FileHeader struct { ...@@ -130,7 +130,7 @@ type FileHeader struct {
// Open opens and returns the FileHeader's associated File. // Open opens and returns the FileHeader's associated File.
func (fh *FileHeader) Open() (File, error) { func (fh *FileHeader) Open() (File, error) {
if b := fh.content; b != nil { if b := fh.content; b != nil {
r := io.NewSectionReader(sliceReaderAt(b), 0, int64(len(b))) r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
return sectionReadCloser{r}, nil return sectionReadCloser{r}, nil
} }
return os.Open(fh.tmpfile) return os.Open(fh.tmpfile)
...@@ -155,13 +155,3 @@ type sectionReadCloser struct { ...@@ -155,13 +155,3 @@ type sectionReadCloser struct {
func (rc sectionReadCloser) Close() error { func (rc sectionReadCloser) Close() error {
return nil return nil
} }
type sliceReaderAt []byte
func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, error) {
if int(off) >= len(r) || off < 0 {
return 0, io.ErrUnexpectedEOF
}
n := copy(b, r[int(off):])
return n, nil
}
...@@ -10,8 +10,9 @@ import ( ...@@ -10,8 +10,9 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// A Reader implements the io.Reader, io.Seeker, io.ByteScanner, and // A Reader implements the io.Reader, io.ReaderAt, io.Seeker,
// io.RuneScanner interfaces by reading from a string. // io.ByteScanner, and io.RuneScanner interfaces by reading
// from a string.
type Reader struct { type Reader struct {
s string s string
i int // current reading index i int // current reading index
...@@ -40,6 +41,20 @@ func (r *Reader) Read(b []byte) (n int, err error) { ...@@ -40,6 +41,20 @@ func (r *Reader) Read(b []byte) (n int, err error) {
return return
} }
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
if off < 0 {
return 0, errors.New("strings: invalid offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
n = copy(b, r.s[int(off):])
if n < len(b) {
err = io.EOF
}
return
}
func (r *Reader) ReadByte() (b byte, err error) { func (r *Reader) ReadByte() (b byte, err error) {
if r.i >= len(r.s) { if r.i >= len(r.s) {
return 0, io.EOF return 0, io.EOF
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
package strings_test package strings_test
import ( import (
"fmt"
"io"
"os" "os"
"strings" "strings"
"testing" "testing"
...@@ -56,3 +58,31 @@ func TestReader(t *testing.T) { ...@@ -56,3 +58,31 @@ func TestReader(t *testing.T) {
} }
} }
} }
func TestReaderAt(t *testing.T) {
r := strings.NewReader("0123456789")
tests := []struct {
off int64
n int
want string
wanterr interface{}
}{
{0, 10, "0123456789", nil},
{1, 10, "123456789", io.EOF},
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
{-1, 0, "", "strings: invalid offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
rn, err := r.ReadAt(b, tt.off)
got := string(b[:rn])
if got != tt.want {
t.Errorf("%d. got %q; want %q", i, got, tt.want)
}
if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) {
t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment