readwriter.mx raw

   1  // Copyright 2011 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package norm
   6  
   7  import "io"
   8  
   9  type normWriter struct {
  10  	rb  reorderBuffer
  11  	w   io.Writer
  12  	buf []byte
  13  }
  14  
  15  // Write implements the standard write interface.  If the last characters are
  16  // not at a normalization boundary, the bytes will be buffered for the next
  17  // write. The remaining bytes will be written on close.
  18  func (w *normWriter) Write(data []byte) (n int, err error) {
  19  	// Process data in pieces to keep w.buf size bounded.
  20  	const chunk = 4000
  21  
  22  	for len(data) > 0 {
  23  		// Normalize into w.buf.
  24  		m := len(data)
  25  		if m > chunk {
  26  			m = chunk
  27  		}
  28  		w.rb.src = inputBytes(data[:m])
  29  		w.rb.nsrc = m
  30  		w.buf = doAppend(&w.rb, w.buf, 0)
  31  		data = data[m:]
  32  		n += m
  33  
  34  		// Write out complete prefix, save remainder.
  35  		// Note that lastBoundary looks back at most 31 runes.
  36  		i := lastBoundary(&w.rb.f, w.buf)
  37  		if i == -1 {
  38  			i = 0
  39  		}
  40  		if i > 0 {
  41  			if _, err = w.w.Write(w.buf[:i]); err != nil {
  42  				break
  43  			}
  44  			bn := copy(w.buf, w.buf[i:])
  45  			w.buf = w.buf[:bn]
  46  		}
  47  	}
  48  	return n, err
  49  }
  50  
  51  // Close forces data that remains in the buffer to be written.
  52  func (w *normWriter) Close() error {
  53  	if len(w.buf) > 0 {
  54  		_, err := w.w.Write(w.buf)
  55  		if err != nil {
  56  			return err
  57  		}
  58  	}
  59  	return nil
  60  }
  61  
  62  // Writer returns a new writer that implements Write(b)
  63  // by writing f(b) to w. The returned writer may use an
  64  // internal buffer to maintain state across Write calls.
  65  // Calling its Close method writes any buffered data to w.
  66  func (f Form) Writer(w io.Writer) io.WriteCloser {
  67  	wr := &normWriter{rb: reorderBuffer{}, w: w}
  68  	wr.rb.init(f, nil)
  69  	return wr
  70  }
  71  
  72  type normReader struct {
  73  	rb           reorderBuffer
  74  	r            io.Reader
  75  	inbuf        []byte
  76  	outbuf       []byte
  77  	bufStart     int
  78  	lastBoundary int
  79  	err          error
  80  }
  81  
  82  // Read implements the standard read interface.
  83  func (r *normReader) Read(p []byte) (int, error) {
  84  	for {
  85  		if r.lastBoundary-r.bufStart > 0 {
  86  			n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
  87  			r.bufStart += n
  88  			if r.lastBoundary-r.bufStart > 0 {
  89  				return n, nil
  90  			}
  91  			return n, r.err
  92  		}
  93  		if r.err != nil {
  94  			return 0, r.err
  95  		}
  96  		outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
  97  		r.outbuf = r.outbuf[0:outn]
  98  		r.bufStart = 0
  99  
 100  		n, err := r.r.Read(r.inbuf)
 101  		r.rb.src = inputBytes(r.inbuf[0:n])
 102  		r.rb.nsrc, r.err = n, err
 103  		if n > 0 {
 104  			r.outbuf = doAppend(&r.rb, r.outbuf, 0)
 105  		}
 106  		if err == io.EOF {
 107  			r.lastBoundary = len(r.outbuf)
 108  		} else {
 109  			r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
 110  			if r.lastBoundary == -1 {
 111  				r.lastBoundary = 0
 112  			}
 113  		}
 114  	}
 115  }
 116  
 117  // Reader returns a new reader that implements Read
 118  // by reading data from r and returning f(data).
 119  func (f Form) Reader(r io.Reader) io.Reader {
 120  	const chunk = 4000
 121  	buf := []byte{:chunk}
 122  	rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
 123  	rr.rb.init(f, buf)
 124  	return rr
 125  }
 126