Skip to content

Commit ff75205

Browse files
mhaggerznull
authored andcommitted
Simplify the NopClosers
* Rename * `newNopCloser()` → `newReaderNopCloser()` * `nopCloser` → `readerNopCloser` * `nopCloserWriterTo` → `readerWriterToNopCloser` * `nopWriteCloser` → `writerNopCloser` to help keep readers and writers straight and because only the `Close()` part is a NOP. * Move `writerNopCloser` to `nop_closer.go` to be with its siblings.
1 parent a080d32 commit ff75205

5 files changed

Lines changed: 44 additions & 33 deletions

File tree

pipe/command.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ func (s *commandStage) Start(
7474
// See the long comment in `Pipeline.Start()` for the
7575
// explanation of this special case.
7676
switch stdin := stdin.(type) {
77-
case nopCloser:
77+
case readerNopCloser:
7878
s.cmd.Stdin = stdin.Reader
79-
case nopCloserWriterTo:
79+
case readerWriterToNopCloser:
8080
s.cmd.Stdin = stdin.Reader
8181
default:
8282
s.cmd.Stdin = stdin

pipe/iocopier.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ func (s *ioCopier) Start(_ context.Context, _ Env, r io.ReadCloser) (io.ReadClos
4646
go func() {
4747
var err error
4848

49-
// Unwrap nopWriteCloser to see if the underlying writer
49+
// Unwrap writerNopCloser to see if the underlying writer
5050
// supports ReaderFrom (e.g., for zero-copy network I/O).
5151
var dst io.Writer = s.w
52-
if nwc, ok := s.w.(nopWriteCloser); ok {
52+
if nwc, ok := s.w.(writerNopCloser); ok {
5353
dst = nwc.Writer
5454
}
5555

pipe/iocopier_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestIOCopierPoolBufferUsed(t *testing.T) {
3131
pw.Close()
3232
}()
3333
var warmBuf bytes.Buffer
34-
c := newIOCopier(nopWriteCloser{&warmBuf})
34+
c := newIOCopier(writerNopCloser{&warmBuf})
3535
_, _ = c.Start(context.TODO(), Env{}, pr)
3636
_ = c.Wait()
3737

@@ -46,7 +46,7 @@ func TestIOCopierPoolBufferUsed(t *testing.T) {
4646
pw.Close()
4747
}()
4848
var buf bytes.Buffer
49-
c = newIOCopier(nopWriteCloser{&buf})
49+
c = newIOCopier(writerNopCloser{&buf})
5050

5151
// GC clears sync.Pool, so re-warm it afterward to isolate the
5252
// measurement from pool repopulation overhead.
@@ -93,7 +93,7 @@ func (w *readFromWriter) Close() error { return nil }
9393

9494
// TestIOCopierUsesReadFrom verifies that ioCopier dispatches to
9595
// ReaderFrom when the destination writer supports it, even when
96-
// wrapped in nopWriteCloser (as happens with WithStdout).
96+
// wrapped in writerNopCloser (as happens with WithStdout).
9797
func TestIOCopierUsesReadFrom(t *testing.T) {
9898
const payload = "hello readfrom\n"
9999

@@ -107,7 +107,7 @@ func TestIOCopierUsesReadFrom(t *testing.T) {
107107
}()
108108

109109
w := &readFromWriter{}
110-
c := newIOCopier(nopWriteCloser{w})
110+
c := newIOCopier(writerNopCloser{w})
111111
_, _ = c.Start(context.TODO(), Env{}, pr)
112112
_ = c.Wait()
113113

@@ -117,6 +117,6 @@ func TestIOCopierUsesReadFrom(t *testing.T) {
117117

118118
if !w.readFromCalled.Load() {
119119
t.Error("ioCopier did not call ReadFrom on destination; " +
120-
"nopWriteCloser may be hiding the ReaderFrom interface")
120+
"writerNopCloser may be hiding the ReaderFrom interface")
121121
}
122122
}

pipe/nop_closer.go

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,48 @@ package pipe
66

77
import "io"
88

9-
// newNopCloser returns a ReadCloser with a no-op Close method wrapping
10-
// the provided io.Reader r.
11-
// If r implements io.WriterTo, the returned io.ReadCloser will implement io.WriterTo
12-
// by forwarding calls to r.
13-
func newNopCloser(r io.Reader) io.ReadCloser {
9+
// newReaderNopCloser returns a ReadCloser with a no-op Close method,
10+
// wrapping the provided io.Reader `r`. If `r` implements
11+
// `io.WriterTo`, the returned `io.ReadCloser` will also implement
12+
// `io.WriterTo` by forwarding calls to `r`.
13+
func newReaderNopCloser(r io.Reader) io.ReadCloser {
1414
if _, ok := r.(io.WriterTo); ok {
15-
return nopCloserWriterTo{r}
15+
return readerWriterToNopCloser{r}
1616
}
17-
return nopCloser{r}
17+
return readerNopCloser{r}
1818
}
1919

20-
type nopCloser struct {
20+
// readerNopCloser is a ReadCloser that wraps a provided `io.Reader`,
21+
// but whose `Close()` method does nothing. We don't need to check
22+
// whether the wrapped reader also implements `io.WriterTo`, since
23+
// it's always unwrapped before use.
24+
type readerNopCloser struct {
2125
io.Reader
2226
}
2327

24-
func (nopCloser) Close() error { return nil }
28+
func (readerNopCloser) Close() error {
29+
return nil
30+
}
2531

26-
type nopCloserWriterTo struct {
32+
// readerWriterToNopCloser is like `readerNopCloser` except that it
33+
// also implements `io.WriterTo` by delegating `WriteTo()` to the
34+
// wrapped `io.Reader` (which must also implement `io.WriterTo`).
35+
type readerWriterToNopCloser struct {
2736
io.Reader
2837
}
2938

30-
func (nopCloserWriterTo) Close() error { return nil }
39+
func (readerWriterToNopCloser) Close() error { return nil }
40+
41+
func (r readerWriterToNopCloser) WriteTo(w io.Writer) (n int64, err error) {
42+
return r.Reader.(io.WriterTo).WriteTo(w)
43+
}
44+
45+
// writerNopCloser is a WriteCloser that wraps a provided `io.Writer`,
46+
// but whose `Close()` method does nothing.
47+
type writerNopCloser struct {
48+
io.Writer
49+
}
3150

32-
func (c nopCloserWriterTo) WriteTo(w io.Writer) (n int64, err error) {
33-
return c.Reader.(io.WriterTo).WriteTo(w)
51+
func (w writerNopCloser) Close() error {
52+
return nil
3453
}

pipe/pipeline.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,6 @@ type Pipeline struct {
7070

7171
var emptyEventHandler = func(_ *Event) {}
7272

73-
type nopWriteCloser struct {
74-
io.Writer
75-
}
76-
77-
func (w nopWriteCloser) Close() error {
78-
return nil
79-
}
80-
8173
type NewPipeFn func(opts ...Option) *Pipeline
8274

8375
// NewPipeline returns a Pipeline struct with all of the `options`
@@ -114,7 +106,7 @@ func WithStdin(stdin io.Reader) Option {
114106
// WithStdout assigns stdout to the last command in the pipeline.
115107
func WithStdout(stdout io.Writer) Option {
116108
return func(p *Pipeline) {
117-
p.stdout = nopWriteCloser{stdout}
109+
p.stdout = writerNopCloser{stdout}
118110
}
119111
}
120112

@@ -277,7 +269,7 @@ func (p *Pipeline) Start(ctx context.Context) error {
277269
// own `nopCloser`, which behaves like `io.NopCloser`, except
278270
// that `pipe.CommandStage` knows how to unwrap it before
279271
// passing it to `exec.Cmd`.
280-
nextStdin = newNopCloser(p.stdin)
272+
nextStdin = newReaderNopCloser(p.stdin)
281273
}
282274

283275
for i, s := range p.stages {
@@ -325,7 +317,7 @@ func (p *Pipeline) Start(ctx context.Context) error {
325317

326318
func (p *Pipeline) Output(ctx context.Context) ([]byte, error) {
327319
var buf bytes.Buffer
328-
p.stdout = nopWriteCloser{&buf}
320+
p.stdout = writerNopCloser{&buf}
329321
err := p.Run(ctx)
330322
return buf.Bytes(), err
331323
}

0 commit comments

Comments
 (0)