|
| 1 | +// Copyright 2019 smallnest. All rights reserved. |
| 2 | +// Use of this source code is governed by a MIT-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +package ringbuffer |
| 6 | + |
| 7 | +import "io" |
| 8 | + |
| 9 | +// Pipe creates an asynchronous in-memory pipe compatible with io.Pipe |
| 10 | +// It can be used to connect code expecting an [io.Reader] |
| 11 | +// with code expecting an [io.Writer]. |
| 12 | +// |
| 13 | +// Reads and Writes will go to the ring buffer. |
| 14 | +// Writes will complete as long as the data fits within the ring buffer. |
| 15 | +// Reads will attempt to satisfy reads with data from the ring buffer. |
| 16 | +// Only if the ring buffer is empty will the read block. |
| 17 | +// |
| 18 | +// It is safe (and intended) to call Read and Write in parallel with each other or with Close. |
| 19 | +func (r *RingBuffer) Pipe() (*PipeReader, *PipeWriter) { |
| 20 | +r.SetBlocking(true) |
| 21 | +pr := PipeReader{pipe: r} |
| 22 | +return &pr, &PipeWriter{pipe: r} |
| 23 | +} |
| 24 | + |
| 25 | +// A PipeReader is the read half of a pipe. |
| 26 | +type PipeReader struct{ pipe *RingBuffer } |
| 27 | + |
| 28 | +// Read implements the standard Read interface: |
| 29 | +// it reads data from the pipe, blocking until a writer |
| 30 | +// arrives or the write end is closed. |
| 31 | +// If the write end is closed with an error, that error is |
| 32 | +// returned as err; otherwise err is io.EOF. |
| 33 | +func (r *PipeReader) Read(data []byte) (n int, err error) { |
| 34 | +return r.pipe.Read(data) |
| 35 | +} |
| 36 | + |
| 37 | +// Close closes the reader; subsequent writes to the |
| 38 | +// write half of the pipe will return the error [io.ErrClosedPipe]. |
| 39 | +func (r *PipeReader) Close() error { |
| 40 | +r.pipe.setErr(io.ErrClosedPipe, false) |
| 41 | +return nil |
| 42 | +} |
| 43 | + |
| 44 | +// CloseWithError closes the reader; subsequent writes |
| 45 | +// to the write half of the pipe will return the error err. |
| 46 | +// |
| 47 | +// CloseWithError never overwrites the previous error if it exists |
| 48 | +// and always returns nil. |
| 49 | +func (r *PipeReader) CloseWithError(err error) error { |
| 50 | +if err == nil { |
| 51 | +return r.Close() |
| 52 | +} |
| 53 | +r.pipe.setErr(err, false) |
| 54 | +return nil |
| 55 | +} |
| 56 | + |
| 57 | +// A PipeWriter is the write half of a pipe. |
| 58 | +type PipeWriter struct{ pipe *RingBuffer } |
| 59 | + |
| 60 | +// Write implements the standard Write interface: |
| 61 | +// it writes data to the pipe. |
| 62 | +// The Write will block until all data has been written to the ring buffer. |
| 63 | +// If the read end is closed with an error, that err is |
| 64 | +// returned as err; otherwise err is [io.ErrClosedPipe]. |
| 65 | +func (w *PipeWriter) Write(data []byte) (n int, err error) { |
| 66 | +if n, err = w.pipe.Write(data); err == ErrWriteOnClosed { |
| 67 | +// Replace error. |
| 68 | +err = io.ErrClosedPipe |
| 69 | +} |
| 70 | +return n, err |
| 71 | +} |
| 72 | + |
| 73 | +// Close closes the writer; subsequent reads from the |
| 74 | +// read half of the pipe will return no bytes and EOF. |
| 75 | +func (w *PipeWriter) Close() error { |
| 76 | +w.pipe.setErr(io.EOF, false) |
| 77 | +return nil |
| 78 | +} |
| 79 | + |
| 80 | +// CloseWithError closes the writer; subsequent reads from the |
| 81 | +// read half of the pipe will return no bytes and the error err, |
| 82 | +// or EOF if err is nil. |
| 83 | +// |
| 84 | +// CloseWithError never overwrites the previous error if it exists |
| 85 | +// and always returns nil. |
| 86 | +func (w *PipeWriter) CloseWithError(err error) error { |
| 87 | +if err == nil { |
| 88 | +return w.Close() |
| 89 | +} |
| 90 | +w.pipe.setErr(err, false) |
| 91 | +return nil |
| 92 | +} |
0 commit comments