From f3fc595830a066d8ba80517b316b59a7c2233f5f Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Fri, 16 Jul 2021 12:04:25 +0100 Subject: [PATCH] Refactor utility io conversions into one internal package Improve reader type conversion by checking if type satisfies ReaderAt to avoid unnecessary wrapping. Move io converters into one place. Fixes: - https://github.com/ipld/go-car/issues/145 --- v2/index_gen.go | 19 +------------------ v2/internal/io/converter.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/v2/index_gen.go b/v2/index_gen.go index 223939d..859909c 100644 --- a/v2/index_gen.go +++ b/v2/index_gen.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "os" - "sync" internalio "github.com/ipld/go-car/v2/internal/io" @@ -97,22 +96,6 @@ func GenerateIndexFromFile(path string) (index.Index, error) { return GenerateIndex(f) } -var _ io.ReaderAt = (*readSeekerAt)(nil) - -type readSeekerAt struct { - rs io.ReadSeeker - mu sync.Mutex -} - -func (rsa *readSeekerAt) ReadAt(p []byte, off int64) (n int, err error) { - rsa.mu.Lock() - defer rsa.mu.Unlock() - if _, err := rsa.rs.Seek(off, io.SeekStart); err != nil { - return 0, err - } - return rsa.rs.Read(p) -} - // ReadOrGenerateIndex accepts both CAR v1 and v2 format, and reads or generates an index for it. // When the given reader is in CAR v1 format an index is always generated. // For a payload in CAR v2 format, an index is only generated if Header.HasIndex returns false. @@ -137,7 +120,7 @@ func ReadOrGenerateIndex(rs io.ReadSeeker) (index.Index, error) { return GenerateIndex(rs) case 2: // Read CAR v2 format - v2r, err := NewReader(&readSeekerAt{rs: rs}) + v2r, err := NewReader(internalio.ToReaderAt(rs)) if err != nil { return nil, err } diff --git a/v2/internal/io/converter.go b/v2/internal/io/converter.go index 4c723ec..65350d3 100644 --- a/v2/internal/io/converter.go +++ b/v2/internal/io/converter.go @@ -3,6 +3,7 @@ package io import ( "io" "io/ioutil" + "sync" ) var ( @@ -10,6 +11,7 @@ var ( _ io.ByteReader = (*readSeekerPlusByte)(nil) _ io.ByteReader = (*discardingReadSeekerPlusByte)(nil) _ io.ReadSeeker = (*discardingReadSeekerPlusByte)(nil) + _ io.ReaderAt = (*readSeekerAt)(nil) ) type ( @@ -30,6 +32,11 @@ type ( io.ReadSeeker io.ByteReader } + + readSeekerAt struct { + rs io.ReadSeeker + mu sync.Mutex + } ) func ToByteReader(r io.Reader) io.ByteReader { @@ -49,6 +56,13 @@ func ToByteReadSeeker(r io.Reader) ByteReadSeeker { return &discardingReadSeekerPlusByte{Reader: r} } +func ToReaderAt(rs io.ReadSeeker) io.ReaderAt { + if ra, ok := rs.(io.ReaderAt); ok { + return ra + } + return &readSeekerAt{rs: rs} +} + func (rb readerPlusByte) ReadByte() (byte, error) { return readByte(rb) } @@ -89,3 +103,12 @@ func readByte(r io.Reader) (byte, error) { _, err := io.ReadFull(r, p[:]) return p[0], err } + +func (rsa *readSeekerAt) ReadAt(p []byte, off int64) (n int, err error) { + rsa.mu.Lock() + defer rsa.mu.Unlock() + if _, err := rsa.rs.Seek(off, io.SeekStart); err != nil { + return 0, err + } + return rsa.rs.Read(p) +} -- GitLab