You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
4.6 KiB

  1. package fwd
  2. import "io"
  3. const (
  4. // DefaultWriterSize is the
  5. // default write buffer size.
  6. DefaultWriterSize = 2048
  7. minWriterSize = minReaderSize
  8. )
  9. // Writer is a buffered writer
  10. type Writer struct {
  11. w io.Writer // writer
  12. buf []byte // 0:len(buf) is bufered data
  13. }
  14. // NewWriter returns a new writer
  15. // that writes to 'w' and has a buffer
  16. // that is `DefaultWriterSize` bytes.
  17. func NewWriter(w io.Writer) *Writer {
  18. if wr, ok := w.(*Writer); ok {
  19. return wr
  20. }
  21. return &Writer{
  22. w: w,
  23. buf: make([]byte, 0, DefaultWriterSize),
  24. }
  25. }
  26. // NewWriterSize returns a new writer
  27. // that writes to 'w' and has a buffer
  28. // that is 'size' bytes.
  29. func NewWriterSize(w io.Writer, size int) *Writer {
  30. if wr, ok := w.(*Writer); ok && cap(wr.buf) >= size {
  31. return wr
  32. }
  33. return &Writer{
  34. w: w,
  35. buf: make([]byte, 0, max(size, minWriterSize)),
  36. }
  37. }
  38. // Buffered returns the number of buffered bytes
  39. // in the reader.
  40. func (w *Writer) Buffered() int { return len(w.buf) }
  41. // BufferSize returns the maximum size of the buffer.
  42. func (w *Writer) BufferSize() int { return cap(w.buf) }
  43. // Flush flushes any buffered bytes
  44. // to the underlying writer.
  45. func (w *Writer) Flush() error {
  46. l := len(w.buf)
  47. if l > 0 {
  48. n, err := w.w.Write(w.buf)
  49. // if we didn't write the whole
  50. // thing, copy the unwritten
  51. // bytes to the beginnning of the
  52. // buffer.
  53. if n < l && n > 0 {
  54. w.pushback(n)
  55. if err == nil {
  56. err = io.ErrShortWrite
  57. }
  58. }
  59. if err != nil {
  60. return err
  61. }
  62. w.buf = w.buf[:0]
  63. return nil
  64. }
  65. return nil
  66. }
  67. // Write implements `io.Writer`
  68. func (w *Writer) Write(p []byte) (int, error) {
  69. c, l, ln := cap(w.buf), len(w.buf), len(p)
  70. avail := c - l
  71. // requires flush
  72. if avail < ln {
  73. if err := w.Flush(); err != nil {
  74. return 0, err
  75. }
  76. l = len(w.buf)
  77. }
  78. // too big to fit in buffer;
  79. // write directly to w.w
  80. if c < ln {
  81. return w.w.Write(p)
  82. }
  83. // grow buf slice; copy; return
  84. w.buf = w.buf[:l+ln]
  85. return copy(w.buf[l:], p), nil
  86. }
  87. // WriteString is analogous to Write, but it takes a string.
  88. func (w *Writer) WriteString(s string) (int, error) {
  89. c, l, ln := cap(w.buf), len(w.buf), len(s)
  90. avail := c - l
  91. // requires flush
  92. if avail < ln {
  93. if err := w.Flush(); err != nil {
  94. return 0, err
  95. }
  96. l = len(w.buf)
  97. }
  98. // too big to fit in buffer;
  99. // write directly to w.w
  100. //
  101. // yes, this is unsafe. *but*
  102. // io.Writer is not allowed
  103. // to mutate its input or
  104. // maintain a reference to it,
  105. // per the spec in package io.
  106. //
  107. // plus, if the string is really
  108. // too big to fit in the buffer, then
  109. // creating a copy to write it is
  110. // expensive (and, strictly speaking,
  111. // unnecessary)
  112. if c < ln {
  113. return w.w.Write(unsafestr(s))
  114. }
  115. // grow buf slice; copy; return
  116. w.buf = w.buf[:l+ln]
  117. return copy(w.buf[l:], s), nil
  118. }
  119. // WriteByte implements `io.ByteWriter`
  120. func (w *Writer) WriteByte(b byte) error {
  121. if len(w.buf) == cap(w.buf) {
  122. if err := w.Flush(); err != nil {
  123. return err
  124. }
  125. }
  126. w.buf = append(w.buf, b)
  127. return nil
  128. }
  129. // Next returns the next 'n' free bytes
  130. // in the write buffer, flushing the writer
  131. // as necessary. Next will return `io.ErrShortBuffer`
  132. // if 'n' is greater than the size of the write buffer.
  133. // Calls to 'next' increment the write position by
  134. // the size of the returned buffer.
  135. func (w *Writer) Next(n int) ([]byte, error) {
  136. c, l := cap(w.buf), len(w.buf)
  137. if n > c {
  138. return nil, io.ErrShortBuffer
  139. }
  140. avail := c - l
  141. if avail < n {
  142. if err := w.Flush(); err != nil {
  143. return nil, err
  144. }
  145. l = len(w.buf)
  146. }
  147. w.buf = w.buf[:l+n]
  148. return w.buf[l:], nil
  149. }
  150. // take the bytes from w.buf[n:len(w.buf)]
  151. // and put them at the beginning of w.buf,
  152. // and resize to the length of the copied segment.
  153. func (w *Writer) pushback(n int) {
  154. w.buf = w.buf[:copy(w.buf, w.buf[n:])]
  155. }
  156. // ReadFrom implements `io.ReaderFrom`
  157. func (w *Writer) ReadFrom(r io.Reader) (int64, error) {
  158. // anticipatory flush
  159. if err := w.Flush(); err != nil {
  160. return 0, err
  161. }
  162. w.buf = w.buf[0:cap(w.buf)] // expand buffer
  163. var nn int64 // written
  164. var err error // error
  165. var x int // read
  166. // 1:1 reads and writes
  167. for err == nil {
  168. x, err = r.Read(w.buf)
  169. if x > 0 {
  170. n, werr := w.w.Write(w.buf[:x])
  171. nn += int64(n)
  172. if err != nil {
  173. if n < x && n > 0 {
  174. w.pushback(n - x)
  175. }
  176. return nn, werr
  177. }
  178. if n < x {
  179. w.pushback(n - x)
  180. return nn, io.ErrShortWrite
  181. }
  182. } else if err == nil {
  183. err = io.ErrNoProgress
  184. break
  185. }
  186. }
  187. if err != io.EOF {
  188. return nn, err
  189. }
  190. // we only clear here
  191. // because we are sure
  192. // the writes have
  193. // succeeded. otherwise,
  194. // we retain the data in case
  195. // future writes succeed.
  196. w.buf = w.buf[0:0]
  197. return nn, nil
  198. }