|  | // Copyright 2010 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package io | 
|  |  | 
|  | type eofReader struct{} | 
|  |  | 
|  | func (eofReader) Read([]byte) (int, error) { | 
|  | return 0, EOF | 
|  | } | 
|  |  | 
|  | type multiReader struct { | 
|  | readers []Reader | 
|  | } | 
|  |  | 
|  | func (mr *multiReader) Read(p []byte) (n int, err error) { | 
|  | for len(mr.readers) > 0 { | 
|  | // Optimization to flatten nested multiReaders (Issue 13558). | 
|  | if len(mr.readers) == 1 { | 
|  | if r, ok := mr.readers[0].(*multiReader); ok { | 
|  | mr.readers = r.readers | 
|  | continue | 
|  | } | 
|  | } | 
|  | n, err = mr.readers[0].Read(p) | 
|  | if err == EOF { | 
|  | // Use eofReader instead of nil to avoid nil panic | 
|  | // after performing flatten (Issue 18232). | 
|  | mr.readers[0] = eofReader{} // permit earlier GC | 
|  | mr.readers = mr.readers[1:] | 
|  | } | 
|  | if n > 0 || err != EOF { | 
|  | if err == EOF && len(mr.readers) > 0 { | 
|  | // Don't return EOF yet. More readers remain. | 
|  | err = nil | 
|  | } | 
|  | return | 
|  | } | 
|  | } | 
|  | return 0, EOF | 
|  | } | 
|  |  | 
|  | // MultiReader returns a Reader that's the logical concatenation of | 
|  | // the provided input readers. They're read sequentially. Once all | 
|  | // inputs have returned EOF, Read will return EOF.  If any of the readers | 
|  | // return a non-nil, non-EOF error, Read will return that error. | 
|  | func MultiReader(readers ...Reader) Reader { | 
|  | r := make([]Reader, len(readers)) | 
|  | copy(r, readers) | 
|  | return &multiReader{r} | 
|  | } | 
|  |  | 
|  | type multiWriter struct { | 
|  | writers []Writer | 
|  | } | 
|  |  | 
|  | func (t *multiWriter) Write(p []byte) (n int, err error) { | 
|  | for _, w := range t.writers { | 
|  | n, err = w.Write(p) | 
|  | if err != nil { | 
|  | return | 
|  | } | 
|  | if n != len(p) { | 
|  | err = ErrShortWrite | 
|  | return | 
|  | } | 
|  | } | 
|  | return len(p), nil | 
|  | } | 
|  |  | 
|  | var _ StringWriter = (*multiWriter)(nil) | 
|  |  | 
|  | func (t *multiWriter) WriteString(s string) (n int, err error) { | 
|  | var p []byte // lazily initialized if/when needed | 
|  | for _, w := range t.writers { | 
|  | if sw, ok := w.(StringWriter); ok { | 
|  | n, err = sw.WriteString(s) | 
|  | } else { | 
|  | if p == nil { | 
|  | p = []byte(s) | 
|  | } | 
|  | n, err = w.Write(p) | 
|  | } | 
|  | if err != nil { | 
|  | return | 
|  | } | 
|  | if n != len(s) { | 
|  | err = ErrShortWrite | 
|  | return | 
|  | } | 
|  | } | 
|  | return len(s), nil | 
|  | } | 
|  |  | 
|  | // MultiWriter creates a writer that duplicates its writes to all the | 
|  | // provided writers, similar to the Unix tee(1) command. | 
|  | // | 
|  | // Each write is written to each listed writer, one at a time. | 
|  | // If a listed writer returns an error, that overall write operation | 
|  | // stops and returns the error; it does not continue down the list. | 
|  | func MultiWriter(writers ...Writer) Writer { | 
|  | allWriters := make([]Writer, 0, len(writers)) | 
|  | for _, w := range writers { | 
|  | if mw, ok := w.(*multiWriter); ok { | 
|  | allWriters = append(allWriters, mw.writers...) | 
|  | } else { | 
|  | allWriters = append(allWriters, w) | 
|  | } | 
|  | } | 
|  | return &multiWriter{allWriters} | 
|  | } |