source: code/trunk/vendor/git.sr.ht/~sircmpwn/go-bare/reader.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 3.7 KB
RevLine 
[822]1package bare
2
3import (
4 "encoding/binary"
5 "fmt"
6 "io"
7 "math"
8 "unicode/utf8"
9)
10
11type byteReader interface {
12 io.Reader
13 io.ByteReader
14}
15
16// A Reader for BARE primitive types.
17type Reader struct {
18 base byteReader
19 scratch [8]byte
20}
21
22type simpleByteReader struct {
23 io.Reader
24 scratch [1]byte
25}
26
27func (r simpleByteReader) ReadByte() (byte, error) {
28 // using reference type here saves us allocations
29 _, err := r.Read(r.scratch[:])
30 return r.scratch[0], err
31}
32
33// Returns a new BARE primitive reader wrapping the given io.Reader.
34func NewReader(base io.Reader) *Reader {
35 br, ok := base.(byteReader)
36 if !ok {
37 br = simpleByteReader{Reader: base}
38 }
39 return &Reader{base: br}
40}
41
42func (r *Reader) ReadUint() (uint64, error) {
43 x, err := binary.ReadUvarint(r.base)
44 if err != nil {
45 return x, err
46 }
47 return x, nil
48}
49
50func (r *Reader) ReadU8() (uint8, error) {
51 return r.base.ReadByte()
52}
53
54func (r *Reader) ReadU16() (uint16, error) {
55 var i uint16
56 if _, err := io.ReadAtLeast(r.base, r.scratch[:2], 2); err != nil {
57 return i, err
58 }
59 return binary.LittleEndian.Uint16(r.scratch[:]), nil
60}
61
62func (r *Reader) ReadU32() (uint32, error) {
63 var i uint32
64 if _, err := io.ReadAtLeast(r.base, r.scratch[:4], 4); err != nil {
65 return i, err
66 }
67 return binary.LittleEndian.Uint32(r.scratch[:]), nil
68}
69
70func (r *Reader) ReadU64() (uint64, error) {
71 var i uint64
72 if _, err := io.ReadAtLeast(r.base, r.scratch[:8], 8); err != nil {
73 return i, err
74 }
75 return binary.LittleEndian.Uint64(r.scratch[:]), nil
76}
77
78func (r *Reader) ReadInt() (int64, error) {
79 return binary.ReadVarint(r.base)
80}
81
82func (r *Reader) ReadI8() (int8, error) {
83 b, err := r.base.ReadByte()
84 return int8(b), err
85}
86
87func (r *Reader) ReadI16() (int16, error) {
88 var i int16
89 if _, err := io.ReadAtLeast(r.base, r.scratch[:2], 2); err != nil {
90 return i, err
91 }
92 return int16(binary.LittleEndian.Uint16(r.scratch[:])), nil
93}
94
95func (r *Reader) ReadI32() (int32, error) {
96 var i int32
97 if _, err := io.ReadAtLeast(r.base, r.scratch[:4], 4); err != nil {
98 return i, err
99 }
100 return int32(binary.LittleEndian.Uint32(r.scratch[:])), nil
101}
102
103func (r *Reader) ReadI64() (int64, error) {
104 var i int64
105 if _, err := io.ReadAtLeast(r.base, r.scratch[:], 8); err != nil {
106 return i, err
107 }
108 return int64(binary.LittleEndian.Uint64(r.scratch[:])), nil
109}
110
111func (r *Reader) ReadF32() (float32, error) {
112 u, err := r.ReadU32()
113 f := math.Float32frombits(u)
114 if math.IsNaN(float64(f)) {
115 return 0.0, fmt.Errorf("NaN is not permitted in BARE floats")
116 }
117 return f, err
118}
119
120func (r *Reader) ReadF64() (float64, error) {
121 u, err := r.ReadU64()
122 f := math.Float64frombits(u)
123 if math.IsNaN(f) {
124 return 0.0, fmt.Errorf("NaN is not permitted in BARE floats")
125 }
126 return f, err
127}
128
129func (r *Reader) ReadBool() (bool, error) {
130 b, err := r.ReadU8()
131 if err != nil {
132 return false, err
133 }
134
135 if b > 1 {
136 return false, fmt.Errorf("Invalid bool value: %#x", b)
137 }
138
139 return b == 1, nil
140}
141
142func (r *Reader) ReadString() (string, error) {
143 buf, err := r.ReadData()
144 if err != nil {
145 return "", err
146 }
147 if !utf8.Valid(buf) {
148 return "", ErrInvalidStr
149 }
150 return string(buf), nil
151}
152
153// Reads a fixed amount of arbitrary data, defined by the length of the slice.
154func (r *Reader) ReadDataFixed(dest []byte) error {
155 var amt int = 0
156 for amt < len(dest) {
157 n, err := r.base.Read(dest[amt:])
158 if err != nil {
159 return err
160 }
161 amt += n
162 }
163 return nil
164}
165
166// Reads arbitrary data whose length is read from the message.
167func (r *Reader) ReadData() ([]byte, error) {
168 l, err := r.ReadUint()
169 if err != nil {
170 return nil, err
171 }
172 if l >= maxUnmarshalBytes {
173 return nil, ErrLimitExceeded
174 }
175 buf := make([]byte, l)
176 var amt uint64 = 0
177 for amt < l {
178 n, err := r.base.Read(buf[amt:])
179 if err != nil {
180 return nil, err
181 }
182 amt += uint64(n)
183 }
184 return buf, nil
185}
Note: See TracBrowser for help on using the repository browser.