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