forked from ipfs/go-ipfs-cmds
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathencoding.go
132 lines (109 loc) · 3.18 KB
/
encoding.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package cmds
import (
"encoding/json"
"encoding/xml"
"fmt"
"io"
"reflect"
)
// Encoder encodes values onto e.g. an io.Writer. Examples are json.Encoder and xml.Encoder.
type Encoder interface {
Encode(value interface{}) error
}
// Decoder decodes values into value (which should be a pointer).
type Decoder interface {
Decode(value interface{}) error
}
// EncodingType defines a supported encoding
type EncodingType string
// PostRunType defines which PostRunFunc should be used
type PostRunType string
// Supported EncodingType constants.
const (
// General purpose
Undefined = ""
// EncodingTypes
JSON = "json"
XML = "xml"
Protobuf = "protobuf"
Text = "text"
TextNewline = "textnl"
// PostRunTypes
CLI = "cli"
)
var Decoders = map[EncodingType]func(w io.Reader) Decoder{
XML: func(r io.Reader) Decoder {
return xml.NewDecoder(r)
},
JSON: func(r io.Reader) Decoder {
return json.NewDecoder(r)
},
}
type EncoderFunc func(req *Request) func(w io.Writer) Encoder
type EncoderMap map[EncodingType]EncoderFunc
var Encoders = EncoderMap{
XML: func(req *Request) func(io.Writer) Encoder {
return func(w io.Writer) Encoder { return xml.NewEncoder(w) }
},
JSON: func(req *Request) func(io.Writer) Encoder {
return func(w io.Writer) Encoder { return json.NewEncoder(w) }
},
Text: func(req *Request) func(io.Writer) Encoder {
return func(w io.Writer) Encoder { return TextEncoder{w: w} }
},
TextNewline: func(req *Request) func(io.Writer) Encoder {
return func(w io.Writer) Encoder { return TextEncoder{w: w, suffix: "\n"} }
},
}
func MakeEncoder(f func(*Request, io.Writer, interface{}) error) func(*Request) func(io.Writer) Encoder {
return func(req *Request) func(io.Writer) Encoder {
return func(w io.Writer) Encoder { return &genericEncoder{f: f, w: w, req: req} }
}
}
func MakeTypedEncoder(f interface{}) func(*Request) func(io.Writer) Encoder {
val := reflect.ValueOf(f)
t := val.Type()
if t.Kind() != reflect.Func || t.NumIn() != 3 {
panic("MakeTypedEncoder must receive a function with three parameters")
}
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
if t.NumOut() != 1 || !t.Out(0).Implements(errorInterface) {
panic("MakeTypedEncoder must return an error")
}
writerInt := reflect.TypeOf((*io.Writer)(nil)).Elem()
if t.In(0) != reflect.TypeOf(&Request{}) || !t.In(1).Implements(writerInt) {
panic("MakeTypedEncoder must receive a function matching func(*Request, io.Writer, ...)")
}
valType := t.In(2)
return MakeEncoder(func(req *Request, w io.Writer, i interface{}) error {
if reflect.TypeOf(i) != valType {
return fmt.Errorf("unexpected type: %T", i)
}
out := val.Call([]reflect.Value{
reflect.ValueOf(req),
reflect.ValueOf(w),
reflect.ValueOf(i),
})
err, ok := out[0].Interface().(error)
if ok {
return err
}
return nil
})
}
type genericEncoder struct {
f func(*Request, io.Writer, interface{}) error
w io.Writer
req *Request
}
func (e *genericEncoder) Encode(v interface{}) error {
return e.f(e.req, e.w, v)
}
type TextEncoder struct {
w io.Writer
suffix string
}
func (e TextEncoder) Encode(v interface{}) error {
_, err := fmt.Fprintf(e.w, "%s%s", v, e.suffix)
return err
}