github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/strings/reader.go (about)

     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        int // 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 >= len(r.s) {
    26  		return 0
    27  	}
    28  	return len(r.s) - r.i
    29  }
    30  
    31  func (r *Reader) Read(b []byte) (n int, err error) {
    32  	if len(b) == 0 {
    33  		return 0, nil
    34  	}
    35  	if r.i >= len(r.s) {
    36  		return 0, io.EOF
    37  	}
    38  	n = copy(b, r.s[r.i:])
    39  	r.i += n
    40  	r.prevRune = -1
    41  	return
    42  }
    43  
    44  func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
    45  	if off < 0 {
    46  		return 0, errors.New("strings: invalid offset")
    47  	}
    48  	if off >= int64(len(r.s)) {
    49  		return 0, io.EOF
    50  	}
    51  	n = copy(b, r.s[int(off):])
    52  	if n < len(b) {
    53  		err = io.EOF
    54  	}
    55  	return
    56  }
    57  
    58  func (r *Reader) ReadByte() (b byte, err error) {
    59  	if r.i >= len(r.s) {
    60  		return 0, io.EOF
    61  	}
    62  	b = r.s[r.i]
    63  	r.i++
    64  	r.prevRune = -1
    65  	return
    66  }
    67  
    68  func (r *Reader) UnreadByte() error {
    69  	if r.i <= 0 {
    70  		return errors.New("strings.Reader: at beginning of string")
    71  	}
    72  	r.i--
    73  	r.prevRune = -1
    74  	return nil
    75  }
    76  
    77  func (r *Reader) ReadRune() (ch rune, size int, err error) {
    78  	if r.i >= len(r.s) {
    79  		return 0, 0, io.EOF
    80  	}
    81  	r.prevRune = r.i
    82  	if c := r.s[r.i]; c < utf8.RuneSelf {
    83  		r.i++
    84  		return rune(c), 1, nil
    85  	}
    86  	ch, size = utf8.DecodeRuneInString(r.s[r.i:])
    87  	r.i += size
    88  	return
    89  }
    90  
    91  func (r *Reader) UnreadRune() error {
    92  	if r.prevRune < 0 {
    93  		return errors.New("strings.Reader: previous operation was not ReadRune")
    94  	}
    95  	r.i = r.prevRune
    96  	r.prevRune = -1
    97  	return nil
    98  }
    99  
   100  // Seek implements the io.Seeker interface.
   101  func (r *Reader) Seek(offset int64, whence int) (int64, error) {
   102  	var abs int64
   103  	switch whence {
   104  	case 0:
   105  		abs = offset
   106  	case 1:
   107  		abs = int64(r.i) + offset
   108  	case 2:
   109  		abs = int64(len(r.s)) + offset
   110  	default:
   111  		return 0, errors.New("strings: invalid whence")
   112  	}
   113  	if abs < 0 {
   114  		return 0, errors.New("strings: negative position")
   115  	}
   116  	if abs >= 1<<31 {
   117  		return 0, errors.New("strings: position out of range")
   118  	}
   119  	r.i = int(abs)
   120  	return abs, nil
   121  }
   122  
   123  // WriteTo implements the io.WriterTo interface.
   124  func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
   125  	r.prevRune = -1
   126  	if r.i >= len(r.s) {
   127  		return 0, nil
   128  	}
   129  	s := r.s[r.i:]
   130  	m, err := io.WriteString(w, s)
   131  	if m > len(s) {
   132  		panic("strings.Reader.WriteTo: invalid WriteString count")
   133  	}
   134  	r.i += m
   135  	n = int64(m)
   136  	if m != len(s) && err == nil {
   137  		err = io.ErrShortWrite
   138  	}
   139  	return
   140  }
   141  
   142  // NewReader returns a new Reader reading from s.
   143  // It is similar to bytes.NewBufferString but more efficient and read-only.
   144  func NewReader(s string) *Reader { return &Reader{s, 0, -1} }