-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.go
92 lines (87 loc) · 2.42 KB
/
api.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
// Package jsonstream deals with streaming JSON input/output. Supports
// line delimited (NDJSON) JSON, length-prefixed JSON,
// record separator delimited JSON, and
// concatenated JSON streams.
//
// https://en.wikipedia.org/wiki/JSON_streaming
//
package jsonstream
import (
"encoding/json"
"fmt"
"io"
"reflect"
)
// Reader reads raw JSON data or unmarshals data from a JSON stream
type Reader interface {
// ReadRaw reads the next raw JSON document. The returned buffer is a
// copy of the read buffer, so subsequent read calls will not
// overwrite the buffer. If the end if the stream is reached, returns
// io.EOF
ReadRaw() ([]byte, error)
// Unmarshal the next JSON document from the input. Returns unmarshal
// error if there is any. If the end of stream is reached, returns
// io.EOF
Unmarshal(out interface{}) error
}
// Writer writes raw JSON data or marshals data to a JSON stream. The
// writer keeps the state, so you can call the write functions one
// after the other and the correct delimiter will be inserted between
// records.
type Writer interface {
// Write raw data to output stream.
WriteRaw([]byte) error
// Marshals a JSON document to output stream. This is a single
// document, if you pass an array, it will be marshaled as a JSON
// array, not as a series of documents.
Marshal(interface{}) error
}
// ReadAll reads all lines of the stream. Returns error for read
// errors except io.EOF
func ReadRawAll(r Reader) ([][]byte, error) {
out := make([][]byte, 0)
for {
o, err := r.ReadRaw()
if err == io.EOF {
break
}
if err != nil {
return out, err
}
out = append(out, o)
}
return out, nil
}
// UnmarshalAll unmarshals all JSON documents from the input to the
// pointer to slice 'out'. The 'out' must be a pointer to a slice:
//
// var out []MyStruct
// jsonstream.UnmarshalAll(rdr,&out)
//
func UnmarshalAll(r Reader, out interface{}) error {
ptr := reflect.ValueOf(out)
if ptr.Kind() != reflect.Ptr {
return fmt.Errorf("Pointer to slice required")
}
ptrElem := ptr.Type().Elem()
if ptrElem.Kind() != reflect.Slice {
return fmt.Errorf("Pointer is not pointing to a slice")
}
elemType := ptrElem.Elem()
for {
o, err := r.ReadRaw()
if err == io.EOF {
break
}
if err != nil {
return err
}
el := reflect.New(elemType)
err = json.Unmarshal(o, el.Interface())
if err != nil {
return err
}
ptr.Elem().Set(reflect.Append(ptr.Elem(), el.Elem()))
}
return nil
}