From 442f7b7c0cceeca6256396ea67dc594a90c7eb42 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Mon, 28 Aug 2023 20:55:06 +0000 Subject: [PATCH] introduce NewReadCloser to allow byte and string buffers to offer io.ReadCloser Signed-off-by: Alejandro Mery --- readcloser.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 readcloser.go diff --git a/readcloser.go b/readcloser.go new file mode 100644 index 0000000..4bc8b05 --- /dev/null +++ b/readcloser.go @@ -0,0 +1,69 @@ +package core + +import ( + "bytes" + "io" + "io/fs" + "strings" +) + +var ( + _ io.Reader = (*ReadCloser)(nil) + _ io.Closer = (*ReadCloser)(nil) +) + +// ReadCloser adds a Close() to Readers without one +type ReadCloser struct { + r io.Reader +} + +// Read passes the Read() call to the underlying [io.Reader] +// and fail if it was Closed() +func (rc *ReadCloser) Read(b []byte) (int, error) { + switch { + case rc.r != nil: + return rc.r.Read(b) + default: + return 0, fs.ErrClosed + } +} + +// Close attempts to Close the underlying [io.Reader], or +// remove it if it doesn't support Close() and fail +// if closed twice +func (rc *ReadCloser) Close() error { + switch { + case rc.r != nil: + rc.r = nil + return nil + default: + return fs.ErrClosed + } +} + +// NewReadCloser wraps a [io.Reader] to satisfy +// [io.ReadCloser] if needed +func NewReadCloser(r io.Reader) io.ReadCloser { + switch p := r.(type) { + case io.ReadCloser: + return p + case nil: + return nil + default: + return &ReadCloser{ + r: r, + } + } +} + +// NewReadCloserBytes wraps a bytes slice to implement +// a [io.ReadCloser] +func NewReadCloserBytes(b []byte) io.ReadCloser { + return NewReadCloser(bytes.NewReader(b)) +} + +// NewReadCloserString wraps a string to implement +// a [io.ReadCloser] +func NewReadCloserString(s string) io.ReadCloser { + return NewReadCloser(strings.NewReader(s)) +}