package core import ( "bytes" "io" "io/fs" "strings" ) // 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)) }