Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(4)

Side by Side Diff: src/pkg/json/encode.go

Issue 953041: code review 953041: json: Marshal, Unmarshal using new scanner (Closed)
Patch Set: code review 953041: json: Marshal, Unmarshal using new scanner Created 14 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package json
6
7 import (
8 "os"
9 "bytes"
10 "reflect"
11 "runtime"
12 "sort"
13 "strconv"
14 "strings"
15 )
16
17 // Marshal returns the JSON encoding of v.
18 //
19 // Marshal traverses the value v recursively.
20 // If an encountered value implements the Marshaler interface,
21 // Marshal calls its MarshalJSON method to produce JSON.
22 //
23 // Otherwise, Marshal uses the following type-dependent default encodings:
24 //
25 // Boolean values encode as JSON booleans.
26 //
27 // Floating point and integer values encode as JSON numbers.
28 //
29 // String values encode as JSON strings, with each invalid UTF-8 sequence
30 // replaced by the encoding of the Unicode replacement character U+FFFD.
31 //
32 // Array and slice values encode as JSON arrays.
33 //
34 // Struct values encode as JSON objects. Each struct field becomes
35 // a member of the object. By default the object's key name is the
36 // struct field name converted to lower case. If the struct field
37 // has a tag, that tag will be used as the name instead.
38 //
39 // Map values encode as JSON objects.
40 // The map's key type must be string; the object keys are used directly
41 // as map keys.
42 //
43 // Pointer values encode as the value pointed at.
44 // A nil pointer encodes as the null JSON object.
45 //
46 // Interface values encode as the value contained in the interface.
47 // A nil interface value encodes as the null JSON object.
48 //
49 // Channel, complex, and function values cannot be encoded in JSON.
50 // Attempting to encode such a value causes Marshal to return
51 // an InvalidTypeError.
52 //
53 // JSON cannot represent cyclic data structures and Marshal does not
54 // handle them. Passing cyclic structures to Marshal will result in
55 // an infinite recursion.
56 //
57 func Marshal(v interface{}) ([]byte, os.Error) {
cw 2010/04/22 08:38:34 before this worked with an io.Writer, now it retur
58 e := &encodeState{}
59 err := e.marshal(v)
60 if err != nil {
61 return nil, err
62 }
63 return e.Bytes(), nil
64 }
65
66 // MarshalIndent is like Marshal but applies Indent to format the output.
67 func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
68 b, err := Marshal(v)
69 if err != nil {
70 return nil, err
71 }
72 var buf bytes.Buffer
73 err = Indent(&buf, b, prefix, indent)
74 if err != nil {
75 return nil, err
76 }
77 return buf.Bytes(), nil
78 }
79
80 // Marshaler is the interface implemented by objects that
81 // can marshal themselves into valid JSON.
82 type Marshaler interface {
83 MarshalJSON() ([]byte, os.Error)
84 }
85
86 type UnsupportedTypeError struct {
87 Type reflect.Type
88 }
89
90 func (e *UnsupportedTypeError) String() string {
91 return "json: unsupported type: " + e.Type.String()
92 }
93
94 type MarshalerError struct {
95 Type reflect.Type
96 Error os.Error
97 }
98
99 func (e *MarshalerError) String() string {
100 return "json: error calling MarshalJSON for type " + e.Type.String() + " : " + e.Error.String()
101 }
102
103 type interfaceOrPtrValue interface {
104 IsNil() bool
105 Elem() reflect.Value
106 }
107
108 var hex = "0123456789abcdef"
109
110 // An encodeState encodes JSON into a bytes.Buffer.
111 type encodeState struct {
112 bytes.Buffer // accumulated output
113 }
114
115 func (e *encodeState) marshal(v interface{}) (err os.Error) {
116 defer func() {
117 if r := recover(); r != nil {
118 if _, ok := r.(runtime.Error); ok {
119 panic(r)
120 }
121 err = r.(os.Error)
122 }
123 }()
124 e.reflectValue(reflect.NewValue(v))
125 return nil
126 }
127
128 func (e *encodeState) error(err os.Error) {
129 panic(err)
130 }
131
132 func (e *encodeState) reflectValue(v reflect.Value) {
133 if v == nil {
134 e.WriteString("null")
135 return
136 }
137
138 if j, ok := v.Interface().(Marshaler); ok {
139 b, err := j.MarshalJSON()
140 if err == nil {
141 // copy JSON into buffer, checking validity.
142 err = Compact(&e.Buffer, b)
143 }
144 if err != nil {
145 e.error(&MarshalerError{v.Type(), err})
146 }
147 return
148 }
149
150 switch v := v.(type) {
151 case *reflect.BoolValue:
152 x := v.Get()
153 if x {
154 e.WriteString("true")
155 } else {
156 e.WriteString("false")
157 }
158
159 case *reflect.IntValue:
160 e.WriteString(strconv.Itoa(v.Get()))
161 case *reflect.Int8Value:
162 e.WriteString(strconv.Itoa(int(v.Get())))
163 case *reflect.Int16Value:
164 e.WriteString(strconv.Itoa(int(v.Get())))
165 case *reflect.Int32Value:
166 e.WriteString(strconv.Itoa(int(v.Get())))
167 case *reflect.Int64Value:
168 e.WriteString(strconv.Itoa64(v.Get()))
169
170 case *reflect.UintValue:
171 e.WriteString(strconv.Uitoa(v.Get()))
172 case *reflect.Uint8Value:
173 e.WriteString(strconv.Uitoa(uint(v.Get())))
174 case *reflect.Uint16Value:
175 e.WriteString(strconv.Uitoa(uint(v.Get())))
176 case *reflect.Uint32Value:
177 e.WriteString(strconv.Uitoa(uint(v.Get())))
178 case *reflect.Uint64Value:
179 e.WriteString(strconv.Uitoa64(v.Get()))
180 case *reflect.UintptrValue:
181 e.WriteString(strconv.Uitoa64(uint64(v.Get())))
182
183 case *reflect.FloatValue:
184 e.WriteString(strconv.Ftoa(v.Get(), 'g', -1))
185 case *reflect.Float32Value:
186 e.WriteString(strconv.Ftoa32(v.Get(), 'g', -1))
187 case *reflect.Float64Value:
188 e.WriteString(strconv.Ftoa64(v.Get(), 'g', -1))
189
190 case *reflect.StringValue:
191 e.string(v.Get())
192
193 case *reflect.StructValue:
194 e.WriteByte('{')
195 t := v.Type().(*reflect.StructType)
196 n := v.NumField()
197 for i := 0; i < n; i++ {
198 if i > 0 {
199 e.WriteByte(',')
200 }
201 f := t.Field(i)
202 if f.Tag != "" {
203 e.string(f.Tag)
204 } else {
205 e.string(strings.ToLower(f.Name))
206 }
207 e.WriteByte(':')
208 e.reflectValue(v.Field(i))
209 }
210 e.WriteByte('}')
211
212 case *reflect.MapValue:
213 if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringTy pe); !ok {
214 e.error(&UnsupportedTypeError{v.Type()})
215 }
216 if v.IsNil() {
217 e.WriteString("null")
218 break
219 }
220 e.WriteByte('{')
221 var sv stringValues = v.Keys()
222 sort.Sort(sv)
223 for i, k := range sv {
224 if i > 0 {
225 e.WriteByte(',')
226 }
227 e.string(k.(*reflect.StringValue).Get())
228 e.WriteByte(':')
229 e.reflectValue(v.Elem(k))
230 }
231 e.WriteByte('}')
232
233 case reflect.ArrayOrSliceValue:
234 e.WriteByte('[')
235 n := v.Len()
236 for i := 0; i < n; i++ {
237 if i > 0 {
238 e.WriteByte(',')
239 }
240 e.reflectValue(v.Elem(i))
241 }
242 e.WriteByte(']')
243
244 case interfaceOrPtrValue:
245 if v.IsNil() {
246 e.WriteString("null")
247 return
248 }
249 e.reflectValue(v.Elem())
250
251 default:
252 e.error(&UnsupportedTypeError{v.Type()})
253 }
254 return
255 }
256
257 // stringValues is a slice of reflect.Value holding *reflect.StringValue.
258 // It implements the methods to sort by string.
259 type stringValues []reflect.Value
260
261 func (sv stringValues) Len() int { return len(sv) }
262 func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
263 func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
264 func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue) .Get() }
265
266 func (e *encodeState) string(s string) {
267 e.WriteByte('"')
268 for _, c := range s {
269 switch {
270 case c < 0x20:
271 e.WriteString(`\u00`)
272 e.WriteByte(hex[c>>4])
273 e.WriteByte(hex[c&0xF])
274 case c == '\\' || c == '"':
275 e.WriteByte('\\')
276 fallthrough
277 default:
278 e.WriteRune(c)
279 }
280 }
281 e.WriteByte('"')
282 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b