parent
b22ad50d59
commit
cc21f5fae2
@ -0,0 +1,33 @@
|
|||||||
|
package iox
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// LimitTeeReader returns a Reader that writes up to n bytes to w what it reads from r.
|
||||||
|
// First n bytes reads from r performed through it are matched with
|
||||||
|
// corresponding writes to w. There is no internal buffering -
|
||||||
|
// the write must complete before the first n bytes read completes.
|
||||||
|
// Any error encountered while writing is reported as a read error.
|
||||||
|
func LimitTeeReader(r io.Reader, w io.Writer, n int64) io.Reader {
|
||||||
|
return &limitTeeReader{r, w, n}
|
||||||
|
}
|
||||||
|
|
||||||
|
type limitTeeReader struct {
|
||||||
|
r io.Reader
|
||||||
|
w io.Writer
|
||||||
|
n int64 // limit bytes remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *limitTeeReader) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = t.r.Read(p)
|
||||||
|
if n > 0 && t.n > 0 {
|
||||||
|
limit := int64(n)
|
||||||
|
if limit > t.n {
|
||||||
|
limit = t.n
|
||||||
|
}
|
||||||
|
if n, err := t.w.Write(p[:limit]); err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
t.n -= limit
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package iox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLimitTeeReader(t *testing.T) {
|
||||||
|
limit := int64(4)
|
||||||
|
src := []byte("hello, world")
|
||||||
|
dst := make([]byte, len(src))
|
||||||
|
rb := bytes.NewBuffer(src)
|
||||||
|
wb := new(bytes.Buffer)
|
||||||
|
r := LimitTeeReader(rb, wb, limit)
|
||||||
|
if n, err := io.ReadFull(r, dst); err != nil || n != len(src) {
|
||||||
|
t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src))
|
||||||
|
}
|
||||||
|
if !bytes.Equal(dst, src) {
|
||||||
|
t.Errorf("bytes read = %q want %q", dst, src)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(wb.Bytes(), src[:limit]) {
|
||||||
|
t.Errorf("bytes written = %q want %q", wb.Bytes(), src)
|
||||||
|
}
|
||||||
|
if n, err := r.Read(dst); n != 0 || err != io.EOF {
|
||||||
|
t.Errorf("r.Read at EOF = %d, %v want 0, EOF", n, err)
|
||||||
|
}
|
||||||
|
rb = bytes.NewBuffer(src)
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
pr.Close()
|
||||||
|
r = LimitTeeReader(rb, pw, limit)
|
||||||
|
if n, err := io.ReadFull(r, dst); n != 0 || err != io.ErrClosedPipe {
|
||||||
|
t.Errorf("closed tee: ReadFull(r, dst) = %d, %v; want 0, EPIPE", n, err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue