From c0603b1c306e71cb80d8071d62400ad261c229b7 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Wed, 25 Sep 2024 16:34:31 -0600 Subject: [PATCH] Added a generic ReaderAt --- cursor/cursor.go | 35 ++++++++++++++++++++++++++++------- cursor/cursor_test.go | 2 +- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cursor/cursor.go b/cursor/cursor.go index 446cdaa..f682216 100644 --- a/cursor/cursor.go +++ b/cursor/cursor.go @@ -3,6 +3,7 @@ package cursor import ( + "errors" "io" ) @@ -32,6 +33,26 @@ type Cursor[Datum any] interface { At(pos uint64) Cursor[Datum] } +type ReaderAt[T any] interface { + 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 +} + type SliceCursor[Datum any] struct { data []Datum offset uint64 @@ -66,16 +87,16 @@ func (sc SliceCursor[Datum]) At(pos uint64) Cursor[Datum] { return sc } -type ReaderAtCursor struct { - r io.ReaderAt +type ReaderAtCursor[T any] struct { + r ReaderAt[T] pos uint64 } -func NewReaderAt(r io.ReaderAt) ReaderAtCursor { - return ReaderAtCursor{r: r} +func NewReaderAt[T any](r ReaderAt[T]) ReaderAtCursor[T] { + return ReaderAtCursor[T]{r: r} } -func (rac ReaderAtCursor) Read(dst []byte) (uint64, Cursor[byte], error) { +func (rac ReaderAtCursor[T]) Read(dst []T) (uint64, Cursor[T], error) { n, err := rac.r.ReadAt(dst, int64(rac.pos)) if n > 0 { rac.pos += uint64(n) @@ -83,11 +104,11 @@ func (rac ReaderAtCursor) Read(dst []byte) (uint64, Cursor[byte], error) { return uint64(n), rac, err } -func (rac ReaderAtCursor) Pos() uint64 { +func (rac ReaderAtCursor[T]) Pos() uint64 { return rac.pos } -func (rac ReaderAtCursor) At(pos uint64) Cursor[byte] { +func (rac ReaderAtCursor[T]) At(pos uint64) Cursor[T] { rac.pos = pos return rac } diff --git a/cursor/cursor_test.go b/cursor/cursor_test.go index 7b4c422..08f0e2b 100644 --- a/cursor/cursor_test.go +++ b/cursor/cursor_test.go @@ -105,7 +105,7 @@ func TestSliceCursor(t *testing.T) { } func TestReaderAtCursor(t *testing.T) { - testCursor(t, func(b []byte) cursor.ReaderAtCursor { + testCursor(t, func(b []byte) cursor.ReaderAtCursor[byte] { return cursor.NewReaderAt(bytes.NewReader(b)) }) t.Run("Read returns an error if the ReaderAt fails", rapid.MakeCheck(func(t *rapid.T) {