Re-added SliceReaderAt
This commit is contained in:
parent
5e6eafef64
commit
c29be1a7b6
1
TODO.txt
1
TODO.txt
@ -1,3 +1,4 @@
|
|||||||
|
Test State against both possible ReaderAt EOF behaviors
|
||||||
Write Repeat tests
|
Write Repeat tests
|
||||||
Think about not requiring so much Pos() when making messages
|
Think about not requiring so much Pos() when making messages
|
||||||
Rename Seq2 to Seq
|
Rename Seq2 to Seq
|
||||||
|
@ -116,6 +116,22 @@ type ReaderAt[T any] interface {
|
|||||||
ReadAt(p []T, off int64) (n int, err error)
|
ReadAt(p []T, off int64) (n int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SliceReaderAt[T any] []T
|
||||||
|
|
||||||
|
func (s SliceReaderAt[T]) ReadAt(dst []T, off int64) (n int, err error) {
|
||||||
|
if off < 0 {
|
||||||
|
return 0, errors.New("SliceReaderAt.ReadAt: negative offset")
|
||||||
|
}
|
||||||
|
if off >= int64(len(s)) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n = copy(dst, s[off:])
|
||||||
|
if n < len(dst) {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
func MakeState[In any](r ReaderAt[In]) State[In] {
|
func MakeState[In any](r ReaderAt[In]) State[In] {
|
||||||
return State[In]{r: r}
|
return State[In]{r: r}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@ package gigaparsec_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"cmp"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.codemonkeysoftware.net/b/gigaparsec"
|
"git.codemonkeysoftware.net/b/gigaparsec"
|
||||||
ptest "git.codemonkeysoftware.net/b/gigaparsec/test"
|
ptest "git.codemonkeysoftware.net/b/gigaparsec/test"
|
||||||
|
"git.codemonkeysoftware.net/b/gigaparsec/test/generator"
|
||||||
pgen "git.codemonkeysoftware.net/b/gigaparsec/test/generator"
|
pgen "git.codemonkeysoftware.net/b/gigaparsec/test/generator"
|
||||||
"github.com/shoenig/test"
|
"github.com/shoenig/test"
|
||||||
"github.com/shoenig/test/must"
|
"github.com/shoenig/test/must"
|
||||||
@ -102,3 +104,42 @@ func TestState(t *testing.T) {
|
|||||||
test.Zero(t, n)
|
test.Zero(t, n)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSliceReaderAt(t *testing.T) {
|
||||||
|
const maxLen = 100
|
||||||
|
t.Run("offset ≥ 0", rapid.MakeCheck(func(t *rapid.T) {
|
||||||
|
src := rapid.SliceOfN(rapid.Byte(), 0, maxLen).Draw(t, "src")
|
||||||
|
dst := generator.SliceOfNZero[byte](0, maxLen).Draw(t, "dst")
|
||||||
|
offset := rapid.Int64Range(0, int64(len(src))+10).Draw(t, "offset")
|
||||||
|
|
||||||
|
n, err := gigaparsec.SliceReaderAt[byte](src).ReadAt(dst, offset)
|
||||||
|
|
||||||
|
switch cmp.Compare(len(src), int(offset)+len(dst)) {
|
||||||
|
case -1:
|
||||||
|
// Read overruns src.
|
||||||
|
test.ErrorIs(t, err, io.EOF)
|
||||||
|
test.EqOp(t, max(0, len(src)-int(offset)), n)
|
||||||
|
case 0:
|
||||||
|
// Read exactly reaches end of source.
|
||||||
|
// io.ReaderAt spec allows error to be either io.EOF or nil.
|
||||||
|
test.EqOp(t, len(dst), n)
|
||||||
|
case 1:
|
||||||
|
// Read ends before end of source.
|
||||||
|
test.NoError(t, err)
|
||||||
|
test.EqOp(t, len(dst), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset < int64(len(src)) {
|
||||||
|
test.SliceEqOp(t, src[offset:offset+int64(n)], dst[:n])
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.Run("offset < 0", rapid.MakeCheck(func(t *rapid.T) {
|
||||||
|
src := rapid.SliceOfN(rapid.Byte(), 0, maxLen).Draw(t, "src")
|
||||||
|
dst := generator.SliceOfNZero[byte](0, maxLen).Draw(t, "dst")
|
||||||
|
offset := rapid.Int64Max(-1).Draw(t, "offset")
|
||||||
|
|
||||||
|
n, err := gigaparsec.SliceReaderAt[byte](src).ReadAt(dst, offset)
|
||||||
|
test.Error(t, err)
|
||||||
|
test.EqOp(t, 0, n)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user