Home | History | Annotate | Download | only in strings
      1 // Copyright 2009 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 strings
      6 
      7 import (
      8 	"errors"
      9 	"io"
     10 	"unicode/utf8"
     11 )
     12 
     13 // A Reader implements the io.Reader, io.ReaderAt, io.Seeker, io.WriterTo,
     14 // io.ByteScanner, and io.RuneScanner interfaces by reading
     15 // from a string.
     16 type Reader struct {
     17 	s        string
     18 	i        int64 // current reading index
     19 	prevRune int   // index of previous rune; or < 0
     20 }
     21 
     22 // Len returns the number of bytes of the unread portion of the
     23 // string.
     24 func (r *Reader) Len() int {
     25 	if r.i >= int64(len(r.s)) {
     26 		return 0
     27 	}
     28 	return int(int64(len(r.s)) - r.i)
     29 }
     30 
     31 // Size returns the original length of the underlying string.
     32 // Size is the number of bytes available for reading via ReadAt.
     33 // The returned value is always the same and is not affected by calls
     34 // to any other method.
     35 func (r *Reader) Size() int64 { return int64(len(r.s)) }
     36 
     37 func (r *Reader) Read(b []byte) (n int, err error) {
     38 	if len(b) == 0 {
     39 		return 0, nil
     40 	}
     41 	if r.i >= int64(len(r.s)) {
     42 		return 0, io.EOF
     43 	}
     44 	r.prevRune = -1
     45 	n = copy(b, r.s[r.i:])
     46 	r.i += int64(n)
     47 	return
     48 }
     49 
     50 func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
     51 	// cannot modify state - see io.ReaderAt
     52 	if off < 0 {
     53 		return 0, errors.New("strings.Reader.ReadAt: negative offset")
     54 	}
     55 	if off >= int64(len(r.s)) {
     56 		return 0, io.EOF
     57 	}
     58 	n = copy(b, r.s[off:])
     59 	if n < len(b) {
     60 		err = io.EOF
     61 	}
     62 	return
     63 }
     64 
     65 func (r *Reader) ReadByte() (b byte, err error) {
     66 	r.prevRune = -1
     67 	if r.i >= int64(len(r.s)) {
     68 		return 0, io.EOF
     69 	}
     70 	b = r.s[r.i]
     71 	r.i++
     72 	return
     73 }
     74 
     75 func (r *Reader) UnreadByte() error {
     76 	r.prevRune = -1
     77 	if r.i <= 0 {
     78 		return errors.New("strings.Reader.UnreadByte: at beginning of string")
     79 	}
     80 	r.i--
     81 	return nil
     82 }
     83 
     84 func (r *Reader) ReadRune() (ch rune, size int, err error) {
     85 	if r.i >= int64(len(r.s)) {
     86 		r.prevRune = -1
     87 		return 0, 0, io.EOF
     88 	}
     89 	r.prevRune = int(r.i)
     90 	if c := r.s[r.i]; c < utf8.RuneSelf {
     91 		r.i++
     92 		return rune(c), 1, nil
     93 	}
     94 	ch, size = utf8.DecodeRuneInString(r.s[r.i:])
     95 	r.i += int64(size)
     96 	return
     97 }
     98 
     99 func (r *Reader) UnreadRune() error {
    100 	if r.prevRune < 0 {
    101 		return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune")
    102 	}
    103 	r.i = int64(r.prevRune)
    104 	r.prevRune = -1
    105 	return nil
    106 }
    107 
    108 // Seek implements the io.Seeker interface.
    109 func (r *Reader) Seek(offset int64, whence int) (int64, error) {
    110 	r.prevRune = -1
    111 	var abs int64
    112 	switch whence {
    113 	case 0:
    114 		abs = offset
    115 	case 1:
    116 		abs = int64(r.i) + offset
    117 	case 2:
    118 		abs = int64(len(r.s)) + offset
    119 	default:
    120 		return 0, errors.New("strings.Reader.Seek: invalid whence")
    121 	}
    122 	if abs < 0 {
    123 		return 0, errors.New("strings.Reader.Seek: negative position")
    124 	}
    125 	r.i = abs
    126 	return abs, nil
    127 }
    128 
    129 // WriteTo implements the io.WriterTo interface.
    130 func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
    131 	r.prevRune = -1
    132 	if r.i >= int64(len(r.s)) {
    133 		return 0, nil
    134 	}
    135 	s := r.s[r.i:]
    136 	m, err := io.WriteString(w, s)
    137 	if m > len(s) {
    138 		panic("strings.Reader.WriteTo: invalid WriteString count")
    139 	}
    140 	r.i += int64(m)
    141 	n = int64(m)
    142 	if m != len(s) && err == nil {
    143 		err = io.ErrShortWrite
    144 	}
    145 	return
    146 }
    147 
    148 // NewReader returns a new Reader reading from s.
    149 // It is similar to bytes.NewBufferString but more efficient and read-only.
    150 func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
    151