Skip to content

Commit fd211d7

Browse files
committed
refactor(countrw): move to iout
1 parent d7655cb commit fd211d7

File tree

6 files changed

+132
-27
lines changed

6 files changed

+132
-27
lines changed

countrw/cr.go

-26
This file was deleted.

iout/copy_range.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package iout
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"io"
7+
)
8+
9+
func CopyRange(w io.Writer, r io.Reader, start, length int64) error {
10+
if _, err := io.CopyN(io.Discard, r, start); err != nil && !errors.Is(err, io.EOF) {
11+
return fmt.Errorf("discard %d: %w", start, err)
12+
}
13+
if length == 0 {
14+
if _, err := io.Copy(w, r); err != nil && !errors.Is(err, io.EOF) {
15+
return fmt.Errorf("direct copy: %w", err)
16+
}
17+
return nil
18+
}
19+
if _, err := io.CopyN(w, io.MultiReader(r, NewNullReader()), length); err != nil && !errors.Is(err, io.EOF) {
20+
return fmt.Errorf("copy %d: %w", length, err)
21+
}
22+
return nil
23+
}

iout/copy_range_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package iout_test
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/matryer/is"
8+
"go.senan.xyz/gonic/iout"
9+
)
10+
11+
func TestCopyRange(t *testing.T) {
12+
t.Parallel()
13+
is := is.New(t)
14+
15+
realLength := 50
16+
cr := func(start, length int64) []byte {
17+
is.Helper()
18+
var data []byte
19+
for i := 0; i < realLength; i++ {
20+
data = append(data, byte(i%10))
21+
}
22+
var buff bytes.Buffer
23+
is.NoErr(iout.CopyRange(&buff, bytes.NewReader(data), start, length))
24+
return buff.Bytes()
25+
}
26+
27+
// range
28+
is.Equal(len(cr(0, 50)), 50)
29+
is.Equal(len(cr(10, 10)), 10)
30+
is.Equal(cr(10, 10)[0], byte(0))
31+
is.Equal(cr(10, 10)[5], byte(5))
32+
is.Equal(cr(25, 35)[0], byte(5))
33+
is.Equal(cr(25, 35)[5], byte(0))
34+
35+
// 0 padding
36+
is.Equal(len(cr(0, 5000)), 5000)
37+
is.Equal(cr(0, 5000)[50:], make([]byte, 5000-50))
38+
39+
// no bound
40+
is.Equal(len(cr(0, 0)), 50)
41+
is.Equal(len(cr(50, 0)), 0)
42+
}

countrw/cw.go iout/countrw.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1-
package countrw
1+
package iout
22

33
import (
44
"io"
55
"sync/atomic"
66
)
77

8+
type CountReader struct {
9+
r io.Reader
10+
c *uint64
11+
}
12+
13+
func NewCountReader(r io.Reader) *CountReader {
14+
return &CountReader{r: r, c: new(uint64)}
15+
}
16+
17+
func (c *CountReader) Reset() { atomic.StoreUint64(c.c, 0) }
18+
func (c *CountReader) Count() uint64 { return atomic.LoadUint64(c.c) }
19+
20+
func (c *CountReader) Read(p []byte) (int, error) {
21+
n, err := c.r.Read(p)
22+
atomic.AddUint64(c.c, uint64(n))
23+
return n, err
24+
}
25+
26+
var _ io.Reader = (*CountReader)(nil)
27+
828
type CountWriter struct {
929
r io.Writer
1030
c *uint64

iout/null_reader.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package iout
2+
3+
import "io"
4+
5+
type nullReader struct{}
6+
7+
func NewNullReader() io.Reader {
8+
return &nullReader{}
9+
}
10+
11+
func (*nullReader) Read(p []byte) (n int, err error) {
12+
for b := range p {
13+
p[b] = 0
14+
}
15+
return len(p), nil
16+
}
17+
18+
var _ io.Reader = (*nullReader)(nil)

iout/tee_closer.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package iout
2+
3+
import "io"
4+
5+
type teeCloser struct {
6+
r io.ReadCloser
7+
w io.WriteCloser
8+
}
9+
10+
func NewTeeCloser(r io.ReadCloser, w io.WriteCloser) io.ReadCloser {
11+
return &teeCloser{r, w}
12+
}
13+
14+
func (t *teeCloser) Read(p []byte) (int, error) {
15+
n, err := t.r.Read(p)
16+
if n > 0 {
17+
if n, err := t.w.Write(p[:n]); err != nil {
18+
return n, err
19+
}
20+
}
21+
return n, err
22+
}
23+
24+
func (t *teeCloser) Close() error {
25+
t.r.Close()
26+
t.w.Close()
27+
return nil
28+
}

0 commit comments

Comments
 (0)