-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecoder.go
107 lines (95 loc) · 2.8 KB
/
decoder.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package tell
import (
"bufio"
"errors"
"fmt"
"io"
r "reflect"
"github.com/ionous/tell/collect"
"github.com/ionous/tell/collect/stdmap"
"github.com/ionous/tell/collect/stdseq"
"github.com/ionous/tell/decode"
"github.com/ionous/tell/note"
)
// Decoder - follows the pattern of encoding/json
type Decoder struct {
src io.RuneReader
inner decode.Decoder
}
// NewDecoder -
func NewDecoder(src io.Reader) *Decoder {
var rr io.RuneReader
if qr, ok := src.(io.RuneReader); ok {
rr = qr
} else {
rr = bufio.NewReader(src)
}
return &Decoder{src: rr, inner: makeDefaultDecoder()}
}
func makeDefaultDecoder() decode.Decoder {
var dec decode.Decoder
dec.SetMapper(stdmap.Make)
dec.SetSequencer(stdseq.Make)
return dec
}
// control the creation of mappings for the upcoming Decode.
// the default is to create native maps ( via stdmap.Make )
func (d *Decoder) SetMapper(maps collect.MapFactory) {
d.inner.SetMapper(maps)
}
// control the creation of sequences for the upcoming Decode.
// the default is to create native slices ( via stdseq.Make )
func (d *Decoder) SetSequencer(seq collect.SequenceFactory) {
d.inner.SetSequencer(seq)
}
// pass a valid target for collecting document level comments
// during an upcoming call to Decode.
// the default behavior is to discard comments.
// ( passing nil will also discard them. )
func (d *Decoder) UseNotes(b *note.Book) {
d.inner.UseNotes(b)
}
// configure the upcoming Decode to produce only floating point numbers.
// otherwise it will produce int for integers, and unit for hex specifications.
func (d *Decoder) UseFloats() {
d.inner.UseFloats = true
}
// read a tell document from the stream configured in NewDecoder,
// and store the result at the value pointed by pv.
func (dec *Decoder) Decode(pv any) (err error) {
out := r.ValueOf(pv)
if out.Kind() != r.Pointer || out.IsNil() {
err = &InvalidUnmarshalError{r.TypeOf(pv)}
} else if out := out.Elem(); !out.CanSet() {
err = errors.New("expected a settable value")
} else if raw, e := dec.inner.Decode(dec.src); e != nil {
err = e
} else if raw == nil {
out.SetZero()
} else {
res := r.ValueOf(raw)
if rt, ot := res.Type(), out.Type(); rt.AssignableTo(ot) {
out.Set(res)
} else if res.CanConvert(ot) {
out.Set(res.Convert(ot))
} else {
err = fmt.Errorf("result of %q cant be written to a pointer of %q", rt, ot)
}
}
return
}
// As per package encoding/json, describes an invalid argument passed to Unmarshal or Decode.
// Arguments must be non-nil pointers
type InvalidUnmarshalError struct {
Type r.Type
}
func (e *InvalidUnmarshalError) Error() (ret string) {
if e.Type == nil {
ret = "tell: Unmarshal(nil)"
} else if e.Type.Kind() != r.Pointer {
ret = "tell: Unmarshal(non-pointer " + e.Type.String() + ")"
} else {
ret = "tell: Unmarshal(nil " + e.Type.String() + ")"
}
return
}