memio - memio.go
1 // Package memio implements Read, Write, Seek, Close and other io methods for a byte slice.
2 package memio // import "vimagination.zapto.org/memio"
3
4 import (
5 "bytes"
6 "errors"
7 "io"
8 )
9
10 const (
11 seekSet = iota
12 seekCurr
13 seekEnd
14 )
15
16 // ErrClosed is an error returned when trying to perform an operation after using Close().
17 var ErrClosed = errors.New("operation not permitted when closed")
18
19 // ReadMem holds a byte slice that can be used for many io interfaces
20 type ReadMem struct {
21 *bytes.Reader
22 }
23
24 // Open uses a byte slice for reading. Implements io.Reader, io.Seeker,
25 // io.Closer, io.ReaderAt, io.ByteReader and io.WriterTo.
26 func Open(data []byte) ReadMem {
27 return ReadMem{bytes.NewReader(data)}
28 }
29
30 // Close is a no-op func the lets ReadMem implement interfaces that require a
31 // Close method
32 func (ReadMem) Close() error {
33 return nil
34 }
35
36 // Peek reads the next n bytes without advancing the position
37 func (r ReadMem) Peek(n int) ([]byte, error) {
38 pos, _ := r.Seek(0, seekCurr)
39 buf := make([]byte, n)
40 _, err := r.ReadAt(buf, pos)
41 return buf, err
42 }
43
44 // WriteMem holds a pointer to a byte slice and allows numerous io interfaces
45 // to be used with it.
46 type WriteMem struct {
47 data *[]byte
48 pos int
49 }
50
51 // Create uses a byte slice for writing. Implements io.Writer, io.Seeker,
52 // io.Closer, io.WriterAt, io.ByteWriter and io.ReaderFrom.
53 func Create(data *[]byte) *WriteMem {
54 return &WriteMem{data, 0}
55 }
56
57 // Write is an implementation of the io.Writer interface
58 func (b *WriteMem) Write(p []byte) (int, error) {
59 if b.data == nil {
60 return 0, ErrClosed
61 }
62 b.setSize(b.pos + len(p))
63 n := copy((*b.data)[b.pos:], p)
64 b.pos += n
65 return n, nil
66 }
67
68 // WriteAt is an implementation of the io.WriterAt interface
69 func (b *WriteMem) WriteAt(p []byte, off int64) (int, error) {
70 if b.data == nil {
71 return 0, ErrClosed
72 }
73 b.setSize(int(off) + len(p))
74 return copy((*b.data)[off:], p), nil
75 }
76
77 // WriteByte is an implementation of the io.WriteByte interface
78 func (b *WriteMem) WriteByte(c byte) error {
79 if b.data == nil {
80 return ErrClosed
81 }
82 b.setSize(b.pos + 1)
83 (*b.data)[b.pos] = c
84 b.pos++
85 return nil
86 }
87
88 // ReadFrom is an implementation of the io.ReaderFrom interface
89 func (b *WriteMem) ReadFrom(f io.Reader) (int64, error) {
90 if b.data == nil {
91 return 0, ErrClosed
92 }
93 var (
94 c int64
95 n int
96 err error
97 )
98 buf := make([]byte, 1024)
99 for {
100 n, err = f.Read(buf)
101 if n > 0 {
102 c += int64(n)
103 b.setSize(b.pos + n)
104 copy((*b.data)[b.pos:], buf[:n])
105 b.pos += n
106 }
107 if err != nil {
108 if err == io.EOF {
109 err = nil
110 }
111 break
112 }
113 }
114 return c, err
115 }
116
117 // Seek is an implementation of the io.Seeker interface
118 func (b *WriteMem) Seek(offset int64, whence int) (int64, error) {
119 if b.data == nil {
120 return 0, ErrClosed
121 }
122 switch whence {
123 case seekSet:
124 b.pos = int(offset)
125 case seekCurr:
126 b.pos += int(offset)
127 case seekEnd:
128 b.pos = len(*b.data) + int(offset)
129 }
130 if b.pos < 0 {
131 b.pos = 0
132 }
133 return int64(b.pos), nil
134 }
135
136 // Close is an implementation of the io.Closer interface
137 func (b *WriteMem) Close() error {
138 b.data = nil
139 return nil
140 }
141
142 func (b *WriteMem) setSize(end int) {
143 if end > len(*b.data) {
144 if end < cap(*b.data) {
145 *b.data = (*b.data)[:end]
146 } else {
147 var newData []byte
148 if len(*b.data) < 512 {
149 newData = make([]byte, end, end<<1)
150 } else {
151 newData = make([]byte, end, end+(end>>2))
152 }
153 copy(newData, *b.data)
154 *b.data = newData
155 }
156 }
157 }
158
159 // Truncate changes the length of the byte slice to the given amount
160 func (b *WriteMem) Truncate(s int64) error {
161 if l := int64(len(*b.data)); l > s {
162 copy((*b.data)[s:], make([]byte, l-s))
163 *b.data = (*b.data)[:s]
164 } else if l < s {
165 b.setSize(int(s))
166 }
167 return nil
168 }
169
170 // WriteString writes a string to the underlying memory
171 func (b *WriteMem) WriteString(s string) (int, error) {
172 return b.Write([]byte(s))
173 }