forked from ohler55/ojg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoj.go
240 lines (217 loc) · 6.5 KB
/
oj.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// Copyright (c) 2020, Peter Ohler, All rights reserved.
package oj
import (
"io"
"sync"
"github.com/ohler55/ojg"
"github.com/ohler55/ojg/alt"
)
// Options is an alias for ojg.Options
type Options = ojg.Options
// Builder is an aliase for alt.Builder.
type Builder = alt.Builder
var (
// DefaultOptions are the default options for the this package.
DefaultOptions = ojg.DefaultOptions
// BrightOptions are the bright color options.
BrightOptions = ojg.BrightOptions
// HTMLOptions are the options that can be used to encode as HTML JSON.
HTMLOptions = ojg.HTMLOptions
goOptions = ojg.GoOptions
writerPool = sync.Pool{
New: func() interface{} {
return &Writer{Options: DefaultOptions, buf: make([]byte, 0, 1024)}
},
}
marshalPool = sync.Pool{
New: func() interface{} {
return &Writer{Options: goOptions, buf: make([]byte, 0, 1024), strict: true}
},
}
parserPool = sync.Pool{
New: func() interface{} {
return &Parser{}
},
}
)
// Parse JSON into a simple type. Arguments are optional and can be a bool,
// func(interface{}) bool for callbacks, or a chan interface{} for chan based
// result delivery.
//
// A bool indicates the NoComment parser attribute should be set to the bool
// value.
//
// A func argument is the callback for the parser if processing multiple
// JSONs. If no callback function is provided the processing is limited to
// only one JSON.
//
// A chan argument will be used to deliver parse results.
func Parse(b []byte, args ...interface{}) (n interface{}, err error) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
return p.Parse(b, args...)
}
// MustParse JSON into a simple type. Arguments are optional and can be a bool,
// func(interface{}) bool for callbacks, or a chan interface{} for chan based
// result delivery. Panics on error
//
// A bool indicates the NoComment parser attribute should be set to the bool
// value.
//
// A func argument is the callback for the parser if processing multiple
// JSONs. If no callback function is provided the processing is limited to
// only one JSON.
//
// A chan argument will be used to deliver parse results.
func MustParse(b []byte, args ...interface{}) (n interface{}) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
var err error
if n, err = p.Parse(b, args...); err != nil {
panic(err)
}
return
}
// ParseString is similar to Parse except it takes a string
// argument to be parsed instead of a []byte.
func ParseString(s string, args ...interface{}) (n interface{}, err error) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
return p.Parse([]byte(s), args...)
}
// MustParseString is similar to MustParse except it takes a string
// argument to be parsed instead of a []byte.
func MustParseString(s string, args ...interface{}) (n interface{}) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
var err error
if n, err = p.Parse([]byte(s), args...); err != nil {
panic(err)
}
return
}
// Load a JSON from a io.Reader into a simple type. An error is returned
// if not valid JSON.
func Load(r io.Reader, args ...interface{}) (interface{}, error) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
return p.ParseReader(r, args...)
}
// MustLoad a JSON from a io.Reader into a simple type. Panics on error.
func MustLoad(r io.Reader, args ...interface{}) (n interface{}) {
p := parserPool.Get().(*Parser)
defer parserPool.Put(p)
var err error
if n, err = p.ParseReader(r, args...); err != nil {
panic(err)
}
return
}
// Validate a JSON string. An error is returned if not valid JSON.
func Validate(b []byte) error {
v := Validator{}
return v.Validate(b)
}
// ValidateString a JSON string. An error is returned if not valid JSON.
func ValidateString(s string) error {
v := Validator{}
return v.Validate([]byte(s))
}
// ValidateReader a JSON stream. An error is returned if not valid JSON.
func ValidateReader(r io.Reader) error {
v := Validator{}
return v.ValidateReader(r)
}
// Unmarshal parses the provided JSON and stores the result in the value
// pointed to by vp.
func Unmarshal(data []byte, vp interface{}, recomposer ...*alt.Recomposer) (err error) {
p := Parser{}
p.num.ForceFloat = true
var v interface{}
if v, err = p.Parse(data); err == nil {
if 0 < len(recomposer) {
_, err = recomposer[0].Recompose(v, vp)
} else {
_, err = alt.Recompose(v, vp)
}
}
return
}
// JSON returns a JSON string for the data provided. The data can be a
// simple type of nil, bool, int, floats, time.Time, []interface{}, or
// map[string]interface{} or a Node type, The args, if supplied can be an
// int as an indent or a *Options.
func JSON(data interface{}, args ...interface{}) string {
var wr *Writer
if 0 < len(args) {
wr = pickWriter(args[0], false)
}
if wr == nil {
wr, _ = writerPool.Get().(*Writer)
defer writerPool.Put(wr)
}
return wr.JSON(data)
}
// Marshal returns a JSON string for the data provided. The data can be a
// simple type of nil, bool, int, floats, time.Time, []interface{}, or
// map[string]interface{} or a gen.Node type, The args, if supplied can be an
// int as an indent, *ojg.Options, or a *Writer. An error will be returned if
// the Option.Strict flag is true and a value is encountered that can not be
// encoded other than by using the %v format of the fmt package.
func Marshal(data interface{}, args ...interface{}) (out []byte, err error) {
var wr *Writer
if 0 < len(args) {
wr = pickWriter(args[0], true)
}
if wr == nil {
wr, _ = marshalPool.Get().(*Writer)
defer marshalPool.Put(wr)
} else {
wr.strict = true
}
defer func() {
if r := recover(); r != nil {
wr.buf = wr.buf[:0]
err = ojg.NewError(r)
}
}()
wr.MustJSON(data)
out = make([]byte, len(wr.buf))
copy(out, wr.buf)
return
}
// Write a JSON string for the data provided. The data can be a simple type of
// nil, bool, int, floats, time.Time, []interface{}, or map[string]interface{}
// or a Node type, The args, if supplied can be an int as an indent or a
// *Options.
func Write(w io.Writer, data interface{}, args ...interface{}) (err error) {
var wr *Writer
if 0 < len(args) {
wr = pickWriter(args[0], false)
}
if wr == nil {
wr, _ = writerPool.Get().(*Writer)
defer writerPool.Put(wr)
}
return wr.Write(w, data)
}
func pickWriter(arg interface{}, strict bool) (wr *Writer) {
switch ta := arg.(type) {
case int:
wr = &Writer{
Options: ojg.GoOptions,
buf: make([]byte, 0, 1024),
strict: strict,
}
wr.Indent = ta
case *ojg.Options:
wr = &Writer{
Options: *ta,
buf: make([]byte, 0, 1024),
strict: strict,
}
case *Writer:
wr = ta
}
return
}