summaryrefslogtreecommitdiff
path: root/vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go')
-rw-r--r--vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go63
1 files changed, 63 insertions, 0 deletions
diff --git a/vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go b/vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go
new file mode 100644
index 000000000..3f3ec44dd
--- /dev/null
+++ b/vendor/github.com/dsoprea/go-utility/v2/filesystem/readseeker_to_readerat.go
@@ -0,0 +1,63 @@
+package rifs
+
+import (
+ "io"
+
+ "github.com/dsoprea/go-logging"
+)
+
+// ReadSeekerToReaderAt is a wrapper that allows a ReadSeeker to masquerade as a
+// ReaderAt.
+type ReadSeekerToReaderAt struct {
+ rs io.ReadSeeker
+}
+
+// NewReadSeekerToReaderAt returns a new ReadSeekerToReaderAt instance.
+func NewReadSeekerToReaderAt(rs io.ReadSeeker) *ReadSeekerToReaderAt {
+ return &ReadSeekerToReaderAt{
+ rs: rs,
+ }
+}
+
+// ReadAt is a wrapper that satisfies the ReaderAt interface.
+//
+// Note that a requirement of ReadAt is that it doesn't have an effect on the
+// offset in the underlying resource as well as that concurrent calls can be
+// made to it. Since we're capturing the current offset in the underlying
+// resource and then seeking back to it before returning, it is the
+// responsibility of the caller to serialize (i.e. use a mutex with) these
+// requests in order to eliminate race-conditions in the parallel-usage
+// scenario.
+//
+// Note also that, since ReadAt() is going to be called on a particular
+// instance, that instance is going to internalize a file resource, that file-
+// resource is provided by the OS, and [most] OSs are only gonna support one
+// file-position per resource, locking is already going to be a necessary
+// internal semantic of a ReaderAt implementation.
+func (rstra *ReadSeekerToReaderAt) ReadAt(p []byte, offset int64) (n int, err error) {
+ defer func() {
+ if state := recover(); state != nil {
+ err = log.Wrap(state.(error))
+ }
+ }()
+
+ originalOffset, err := rstra.rs.Seek(0, io.SeekCurrent)
+ log.PanicIf(err)
+
+ defer func() {
+ _, err := rstra.rs.Seek(originalOffset, io.SeekStart)
+ log.PanicIf(err)
+ }()
+
+ _, err = rstra.rs.Seek(offset, io.SeekStart)
+ log.PanicIf(err)
+
+ // Note that all errors will be wrapped, here. The usage of this method is
+ // such that typically no specific errors would be expected as part of
+ // normal operation (in which case we'd check for those first and return
+ // them directly).
+ n, err = io.ReadFull(rstra.rs, p)
+ log.PanicIf(err)
+
+ return n, nil
+}