Skip to content

Commit 9c514e1

Browse files
committed
io: add WriteString support to MultiWriter
Fixes #11805 Change-Id: I081e16b869dc706bd847ee645bb902bc671c123f Reviewed-on: https://go-review.googlesource.com/12485 Reviewed-by: Josh Bleecher Snyder <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 8ceaefb commit 9c514e1

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

src/io/multi.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ func (t *multiWriter) Write(p []byte) (n int, err error) {
5252
return len(p), nil
5353
}
5454

55+
var _ stringWriter = (*multiWriter)(nil)
56+
57+
func (t *multiWriter) WriteString(s string) (n int, err error) {
58+
var p []byte // lazily initialized if/when needed
59+
for _, w := range t.writers {
60+
if sw, ok := w.(stringWriter); ok {
61+
n, err = sw.WriteString(s)
62+
} else {
63+
if p == nil {
64+
p = []byte(s)
65+
}
66+
n, err = w.Write(p)
67+
}
68+
if err != nil {
69+
return
70+
}
71+
if n != len(s) {
72+
err = ErrShortWrite
73+
return
74+
}
75+
}
76+
return len(s), nil
77+
}
78+
5579
// MultiWriter creates a writer that duplicates its writes to all the
5680
// provided writers, similar to the Unix tee(1) command.
5781
func MultiWriter(writers ...Writer) Writer {

src/io/multi_test.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,59 @@ func TestMultiReader(t *testing.T) {
6262
}
6363

6464
func TestMultiWriter(t *testing.T) {
65-
sha1 := sha1.New()
6665
sink := new(bytes.Buffer)
66+
// Hide bytes.Buffer's WriteString method:
67+
testMultiWriter(t, struct {
68+
Writer
69+
fmt.Stringer
70+
}{sink, sink})
71+
}
72+
73+
func TestMultiWriter_String(t *testing.T) {
74+
testMultiWriter(t, new(bytes.Buffer))
75+
}
76+
77+
// test that a multiWriter.WriteString calls results in at most 1 allocation,
78+
// even if multiple targets don't support WriteString.
79+
func TestMultiWriter_WriteStringSingleAlloc(t *testing.T) {
80+
var sink1, sink2 bytes.Buffer
81+
type simpleWriter struct { // hide bytes.Buffer's WriteString
82+
Writer
83+
}
84+
mw := MultiWriter(simpleWriter{&sink1}, simpleWriter{&sink2})
85+
allocs := int(testing.AllocsPerRun(1000, func() {
86+
WriteString(mw, "foo")
87+
}))
88+
if allocs != 1 {
89+
t.Errorf("num allocations = %d; want 1", allocs)
90+
}
91+
}
92+
93+
type writeStringChecker struct{ called bool }
94+
95+
func (c *writeStringChecker) WriteString(s string) (n int, err error) {
96+
c.called = true
97+
return len(s), nil
98+
}
99+
100+
func (c *writeStringChecker) Write(p []byte) (n int, err error) {
101+
return len(p), nil
102+
}
103+
104+
func TestMultiWriter_StringCheckCall(t *testing.T) {
105+
var c writeStringChecker
106+
mw := MultiWriter(&c)
107+
WriteString(mw, "foo")
108+
if !c.called {
109+
t.Error("did not see WriteString call to writeStringChecker")
110+
}
111+
}
112+
113+
func testMultiWriter(t *testing.T, sink interface {
114+
Writer
115+
fmt.Stringer
116+
}) {
117+
sha1 := sha1.New()
67118
mw := MultiWriter(sha1, sink)
68119

69120
sourceString := "My input text."

0 commit comments

Comments
 (0)