func NewReader(ctx context.Context, r io.Reader) io.Reader {
	if r, ok := r.(*reader); ok && ctx == r.ctx {
		return r
	}
	return &reader{ctx: ctx, r: r}
}
NewReader wraps an io.Reader to handle context cancellation.

Context state is checked BEFORE every Read.
package contextio
import (
	"context"
	"io"
)
type writer struct {
	ctx context.Context
	w   io.Writer
}
type copier struct {
	writer
}
func NewWriter(ctx context.Context, w io.Writer) io.Writer {
	if w, ok := w.(*copier); ok && ctx == w.ctx {
		return w
	}
	return &copier{writer{ctx: ctx, w: w}}
}
func (w *writer) Write(p []byte) (n int, err error) {
	select {
	case <-w.ctx.Done():
		return 0, w.ctx.Err()
	default:
		return w.w.Write(p)
	}
}
type reader struct {
	ctx context.Context
	r   io.Reader
}