summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/philhofer/fwd/writer.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2020-10-19 23:40:00 +0200
committerGitHub <noreply@github.com>2020-10-19 23:40:00 +0200
commit075a84427f6332aab707d283ad770d69f8816032 (patch)
tree0ff9f56a057919f3fe968e57f6f0b1c0d1f85078 /vendor/github.com/philhofer/fwd/writer.go
parent950f2759bd2b20aa0bdedc3dc9a74d0dafb606d8 (diff)
downloadmatterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.tar.gz
matterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.tar.bz2
matterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.zip
Update vendor (#1265)
Diffstat (limited to 'vendor/github.com/philhofer/fwd/writer.go')
-rw-r--r--vendor/github.com/philhofer/fwd/writer.go224
1 files changed, 224 insertions, 0 deletions
diff --git a/vendor/github.com/philhofer/fwd/writer.go b/vendor/github.com/philhofer/fwd/writer.go
new file mode 100644
index 00000000..2dc392a9
--- /dev/null
+++ b/vendor/github.com/philhofer/fwd/writer.go
@@ -0,0 +1,224 @@
+package fwd
+
+import "io"
+
+const (
+ // DefaultWriterSize is the
+ // default write buffer size.
+ DefaultWriterSize = 2048
+
+ minWriterSize = minReaderSize
+)
+
+// Writer is a buffered writer
+type Writer struct {
+ w io.Writer // writer
+ buf []byte // 0:len(buf) is bufered data
+}
+
+// NewWriter returns a new writer
+// that writes to 'w' and has a buffer
+// that is `DefaultWriterSize` bytes.
+func NewWriter(w io.Writer) *Writer {
+ if wr, ok := w.(*Writer); ok {
+ return wr
+ }
+ return &Writer{
+ w: w,
+ buf: make([]byte, 0, DefaultWriterSize),
+ }
+}
+
+// NewWriterSize returns a new writer
+// that writes to 'w' and has a buffer
+// that is 'size' bytes.
+func NewWriterSize(w io.Writer, size int) *Writer {
+ if wr, ok := w.(*Writer); ok && cap(wr.buf) >= size {
+ return wr
+ }
+ return &Writer{
+ w: w,
+ buf: make([]byte, 0, max(size, minWriterSize)),
+ }
+}
+
+// Buffered returns the number of buffered bytes
+// in the reader.
+func (w *Writer) Buffered() int { return len(w.buf) }
+
+// BufferSize returns the maximum size of the buffer.
+func (w *Writer) BufferSize() int { return cap(w.buf) }
+
+// Flush flushes any buffered bytes
+// to the underlying writer.
+func (w *Writer) Flush() error {
+ l := len(w.buf)
+ if l > 0 {
+ n, err := w.w.Write(w.buf)
+
+ // if we didn't write the whole
+ // thing, copy the unwritten
+ // bytes to the beginnning of the
+ // buffer.
+ if n < l && n > 0 {
+ w.pushback(n)
+ if err == nil {
+ err = io.ErrShortWrite
+ }
+ }
+ if err != nil {
+ return err
+ }
+ w.buf = w.buf[:0]
+ return nil
+ }
+ return nil
+}
+
+// Write implements `io.Writer`
+func (w *Writer) Write(p []byte) (int, error) {
+ c, l, ln := cap(w.buf), len(w.buf), len(p)
+ avail := c - l
+
+ // requires flush
+ if avail < ln {
+ if err := w.Flush(); err != nil {
+ return 0, err
+ }
+ l = len(w.buf)
+ }
+ // too big to fit in buffer;
+ // write directly to w.w
+ if c < ln {
+ return w.w.Write(p)
+ }
+
+ // grow buf slice; copy; return
+ w.buf = w.buf[:l+ln]
+ return copy(w.buf[l:], p), nil
+}
+
+// WriteString is analogous to Write, but it takes a string.
+func (w *Writer) WriteString(s string) (int, error) {
+ c, l, ln := cap(w.buf), len(w.buf), len(s)
+ avail := c - l
+
+ // requires flush
+ if avail < ln {
+ if err := w.Flush(); err != nil {
+ return 0, err
+ }
+ l = len(w.buf)
+ }
+ // too big to fit in buffer;
+ // write directly to w.w
+ //
+ // yes, this is unsafe. *but*
+ // io.Writer is not allowed
+ // to mutate its input or
+ // maintain a reference to it,
+ // per the spec in package io.
+ //
+ // plus, if the string is really
+ // too big to fit in the buffer, then
+ // creating a copy to write it is
+ // expensive (and, strictly speaking,
+ // unnecessary)
+ if c < ln {
+ return w.w.Write(unsafestr(s))
+ }
+
+ // grow buf slice; copy; return
+ w.buf = w.buf[:l+ln]
+ return copy(w.buf[l:], s), nil
+}
+
+// WriteByte implements `io.ByteWriter`
+func (w *Writer) WriteByte(b byte) error {
+ if len(w.buf) == cap(w.buf) {
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ }
+ w.buf = append(w.buf, b)
+ return nil
+}
+
+// Next returns the next 'n' free bytes
+// in the write buffer, flushing the writer
+// as necessary. Next will return `io.ErrShortBuffer`
+// if 'n' is greater than the size of the write buffer.
+// Calls to 'next' increment the write position by
+// the size of the returned buffer.
+func (w *Writer) Next(n int) ([]byte, error) {
+ c, l := cap(w.buf), len(w.buf)
+ if n > c {
+ return nil, io.ErrShortBuffer
+ }
+ avail := c - l
+ if avail < n {
+ if err := w.Flush(); err != nil {
+ return nil, err
+ }
+ l = len(w.buf)
+ }
+ w.buf = w.buf[:l+n]
+ return w.buf[l:], nil
+}
+
+// take the bytes from w.buf[n:len(w.buf)]
+// and put them at the beginning of w.buf,
+// and resize to the length of the copied segment.
+func (w *Writer) pushback(n int) {
+ w.buf = w.buf[:copy(w.buf, w.buf[n:])]
+}
+
+// ReadFrom implements `io.ReaderFrom`
+func (w *Writer) ReadFrom(r io.Reader) (int64, error) {
+ // anticipatory flush
+ if err := w.Flush(); err != nil {
+ return 0, err
+ }
+
+ w.buf = w.buf[0:cap(w.buf)] // expand buffer
+
+ var nn int64 // written
+ var err error // error
+ var x int // read
+
+ // 1:1 reads and writes
+ for err == nil {
+ x, err = r.Read(w.buf)
+ if x > 0 {
+ n, werr := w.w.Write(w.buf[:x])
+ nn += int64(n)
+
+ if err != nil {
+ if n < x && n > 0 {
+ w.pushback(n - x)
+ }
+ return nn, werr
+ }
+ if n < x {
+ w.pushback(n - x)
+ return nn, io.ErrShortWrite
+ }
+ } else if err == nil {
+ err = io.ErrNoProgress
+ break
+ }
+ }
+ if err != io.EOF {
+ return nn, err
+ }
+
+ // we only clear here
+ // because we are sure
+ // the writes have
+ // succeeded. otherwise,
+ // we retain the data in case
+ // future writes succeed.
+ w.buf = w.buf[0:0]
+
+ return nn, nil
+}