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