Re-added SliceReaderAt

This commit is contained in:
Brandon Dyck 2024-09-30 13:02:57 -06:00
parent 5e6eafef64
commit c29be1a7b6
3 changed files with 58 additions and 0 deletions

View File

@ -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

View File

@ -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}
} }

View File

@ -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)
}))
}