bufio: fix UnreadSlice followed by UnreadRune

Also, fix a write check in writeBuf and make some bounds checks simpler.

LGTM=gri
R=golang-codereviews, adg, gri, r, minux
CC=golang-codereviews
https://golang.org/cl/113060043
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index 61ef261..d3c68fe 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -30,8 +30,8 @@
 // Reader implements buffering for an io.Reader object.
 type Reader struct {
 	buf          []byte
-	rd           io.Reader
-	r, w         int
+	rd           io.Reader // reader provided by the client
+	r, w         int       // buf read and write positions
 	err          error
 	lastByte     int
 	lastRuneSize int
@@ -131,18 +131,17 @@
 	for b.w-b.r < n && b.err == nil {
 		b.fill() // b.w-b.r < len(b.buf) => buffer is not full
 	}
-	m := b.w - b.r
-	if m > n {
-		m = n
-	}
+
 	var err error
-	if m < n {
+	if avail := b.w - b.r; avail < n {
+		// not enough data in buffer
+		n = avail
 		err = b.readErr()
 		if err == nil {
 			err = ErrBufferFull
 		}
 	}
-	return b.buf[b.r : b.r+m], err
+	return b.buf[b.r : b.r+n], err
 }
 
 // Read reads data into p.
@@ -173,15 +172,13 @@
 			return n, b.readErr()
 		}
 		b.fill() // buffer is empty
-		if b.w == b.r {
+		if b.r == b.w {
 			return 0, b.readErr()
 		}
 	}
 
-	if n > b.w-b.r {
-		n = b.w - b.r
-	}
-	copy(p[0:n], b.buf[b.r:])
+	// copy as much as we can
+	n = copy(p, b.buf[b.r:b.w])
 	b.r += n
 	b.lastByte = int(b.buf[b.r-1])
 	b.lastRuneSize = -1
@@ -288,7 +285,7 @@
 		}
 
 		// Buffer full?
-		if n := b.Buffered(); n >= len(b.buf) {
+		if b.Buffered() >= len(b.buf) {
 			b.r = b.w
 			line = b.buf
 			err = ErrBufferFull
@@ -301,6 +298,7 @@
 	// Handle last byte, if any.
 	if i := len(line) - 1; i >= 0 {
 		b.lastByte = int(line[i])
+		b.lastRuneSize = -1
 	}
 
 	return
@@ -458,11 +456,13 @@
 	return n, b.readErr()
 }
 
+var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
+
 // writeBuf writes the Reader's buffer to the writer.
 func (b *Reader) writeBuf(w io.Writer) (int64, error) {
 	n, err := w.Write(b.buf[b.r:b.w])
-	if n < b.r-b.w {
-		panic(errors.New("bufio: writer did not write all data"))
+	if n < 0 {
+		panic(errNegativeWrite)
 	}
 	b.r += n
 	return int64(n), err
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index be43a80..4f3bc10 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -463,6 +463,18 @@
 	if r.UnreadRune() == nil {
 		t.Error("expected error after UnreadByte (3)")
 	}
+	// Test error after ReadSlice.
+	_, _, err = r.ReadRune() // reset state
+	if err != nil {
+		t.Error("unexpected error on ReadRune (4):", err)
+	}
+	_, err = r.ReadSlice(0)
+	if err != io.EOF {
+		t.Error("unexpected error on ReadSlice (4):", err)
+	}
+	if r.UnreadRune() == nil {
+		t.Error("expected error after ReadSlice (4)")
+	}
 }
 
 func TestUnreadRuneAtEOF(t *testing.T) {
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 97ae109..c5714f3 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -64,8 +64,9 @@
 )
 
 const (
-	// Maximum size used to buffer a token. The actual maximum token size
-	// may be smaller as the buffer may need to include, for instance, a newline.
+	// MaxScanTokenSize is the maximum size used to buffer a token.
+	// The actual maximum token size may be smaller as the buffer
+	// may need to include, for instance, a newline.
 	MaxScanTokenSize = 64 * 1024
 )