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 p := rc.r.(type) { case io.Closer: return p.Close() case nil: return fs.ErrClosed default: rc.r = nil return nil } } // NewReadCloser wraps a [io.Reader] to satisfy // [io.ReadCloser] func NewReadCloser(r io.Reader) *ReadCloser { if r == nil { return nil } return &ReadCloser{ r: r, } } // NewReadCloserBytes wraps a bytes slice to implement // a [io.ReadCloser] func NewReadCloserBytes(b []byte) *ReadCloser { return NewReadCloser(bytes.NewReader(b)) } // NewReadCloserString wraps a string to implement // a [io.ReadCloser] func NewReadCloserString(s string) *ReadCloser { return NewReadCloser(strings.NewReader(s)) }