-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader.go
82 lines (72 loc) · 2.09 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package readonly
import (
"io"
"reflect"
"unicode/utf8"
"unsafe"
)
// NewReader returns a new Reader reading from src.
// It is similar to strings.NewReader or bytes.NewReader but more
// efficient.
func NewReader[T ~string | ~[]byte | ByteSlice](src T) *Reader {
return &Reader{s: *(*string)(unsafe.Pointer(&src))}
}
// Reader implements the io.Reader, io.ByteReader, io.RuneReader and
// io.WriterTo interfaces by reading from a string.
// The zero value for Reader operates like a Reader of an empty string,
// nil byte slice or an empty byte slice.
type Reader struct{ s string }
// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int { return len(r.s) }
// Read implements the io.Reader interface.
func (r *Reader) Read(p []byte) (n int, err error) {
if len(r.s) == 0 {
return 0, io.EOF
}
n = copy(p, r.s)
r.s = r.s[n:]
return n, nil
}
// ReadByte implements the io.ByteReader interface.
func (r *Reader) ReadByte() (b byte, err error) {
if len(r.s) == 0 {
return 0, io.EOF
}
b, r.s = r.s[0], r.s[1:]
return b, nil
}
// ReadRune implements the io.RuneReader interface.
func (r *Reader) ReadRune() (ch rune, size int, err error) {
if len(r.s) == 0 {
return 0, 0, io.EOF
}
if r.s[0] < utf8.RuneSelf {
ch, size, r.s = rune(r.s[0]), 1, r.s[1:]
return ch, size, nil
}
ch, size = utf8.DecodeRuneInString(r.s)
r.s = r.s[size:]
return ch, size, nil
}
// WriteTo implements the io.WriterTo interface.
// w must not modify the slice data, even temporarily, see io.Writer.
func (r Reader) WriteTo(w io.Writer) (n int64, err error) {
if len(r.s) == 0 {
return 0, nil
}
// io.Writer has to guarantee that the slice of bytes will be
// unchanged.
b := *(*[]byte)(unsafe.Pointer(&r.s))
(*reflect.SliceHeader)(unsafe.Pointer(&b)).Cap = len(r.s)
m, err := w.Write(b)
switch n = int64(m); {
case err != nil:
return n, err
case m != len(r.s):
return n, io.ErrShortWrite
}
return n, nil
}
// ResetReader resets the Reader to be reading from b.
func ResetReader[T []byte | string | ByteSlice](r *Reader, b T) { r.s = *(*string)(unsafe.Pointer(&b)) }