blob: aeff22225f18adfc34f0e88c23df8e8108e5106c [file] [log] [blame]
Joe Tsai879b18d2018-08-03 17:22:24 -07001// Copyright 2018 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 implements the JSON format.
6// This package has no semantic understanding for protocol buffers and is only
7// a parser and composer for the format.
8//
9// This follows RFC 7159, with some notable implementation specifics:
10// * numbers that are out of range result in a decoding error
11// * duplicate keys in objects are not rejected
12//
13// Reasons why the standard encoding/json package is not suitable:
14// * information about duplicate keys is lost
15// * invalid UTF-8 is silently coerced into utf8.RuneError
16package json
17
18import (
19 "fmt"
20 "strings"
21)
22
23// Type represents a type expressible in the JSON format.
24type Type uint8
25
26const (
27 _ Type = iota
28 // Null is the null literal (i.e., "null").
29 Null
30 // Bool is a boolean (i.e., "true" or "false").
31 Bool
32 // Number is a floating-point number (e.g., "1.234" or "1e100").
33 Number
34 // String is an escaped string (e.g., `"the quick brown fox"`).
35 String
36 // Array is an ordered list of values (e.g., `[0, "one", true]`).
37 Array
38 // Object is an ordered map of values (e.g., `{"key": null}`).
39 Object
40)
41
42func (t Type) String() string {
43 switch t {
44 case Null:
45 return "null"
46 case Bool:
47 return "bool"
48 case Number:
49 return "number"
50 case String:
51 return "string"
52 case Array:
53 return "array"
54 case Object:
55 return "object"
56 default:
57 return "<invalid>"
58 }
59}
60
61// Value contains a value of a given Type.
62type Value struct {
63 typ Type
64 raw []byte // raw bytes of the serialized data
65 str string // only for String
66 num float64 // only for Bool or Number
67 arr []Value // only for Array
68 obj [][2]Value // only for Object
69}
70
71// ValueOf returns a Value for a given Go value:
72// nil => Null
73// bool => Bool
74// int32, int64 => Number
75// uint32, uint64 => Number
76// float32, float64 => Number
77// string, []byte => String
78// []Value => Array
79// [][2]Value => Object
80//
81// ValueOf panics if the Go type is not one of the above.
82func ValueOf(v interface{}) Value {
83 switch v := v.(type) {
84 case nil:
85 return Value{typ: Null}
86 case bool:
87 if v {
88 return Value{typ: Bool, num: 1}
89 } else {
90 return Value{typ: Bool, num: 0}
91 }
92 case int32:
93 return Value{typ: Number, num: float64(v)}
94 case int64:
95 return Value{typ: Number, num: float64(v)} // possible loss of precision
96 case uint32:
97 return Value{typ: Number, num: float64(v)}
98 case uint64:
99 return Value{typ: Number, num: float64(v)} // possible loss of precision
100 case float32:
101 return Value{typ: Number, num: float64(v)}
102 case float64:
103 return Value{typ: Number, num: float64(v)}
104 case string:
105 return Value{typ: String, str: string(v)}
106 case []byte:
107 return Value{typ: String, str: string(v)}
108 case []Value:
109 return Value{typ: Array, arr: v}
110 case [][2]Value:
111 return Value{typ: Object, obj: v}
112 default:
113 panic(fmt.Sprintf("invalid type %T", v))
114 }
115}
116func rawValueOf(v interface{}, raw []byte) Value {
117 v2 := ValueOf(v)
118 v2.raw = raw
119 return v2
120}
121
122// Type is the type of the value.
123func (v Value) Type() Type {
124 return v.typ
125}
126
127// Bool returns v as a bool and panics if it is not a Bool.
128func (v Value) Bool() bool {
129 if v.typ != Bool {
130 panic("value is not a boolean")
131 }
132 return v.num != 0
133}
134
135// Number returns v as a float64 and panics if it is not a Number.
136func (v Value) Number() float64 {
137 if v.typ != Number {
138 panic("value is not a number")
139 }
140 return v.num
141}
142
143// String returns v as a string if the Type is String.
144// Otherwise, this returns a formatted string of v for debugging purposes.
145//
146// Since JSON strings must be UTF-8, the marshaler and unmarshaler will verify
147// for UTF-8 correctness.
148func (v Value) String() string {
149 if v.typ != String {
150 return v.stringValue()
151 }
152 return v.str
153}
154func (v Value) stringValue() string {
155 switch v.typ {
156 case Null, Bool, Number:
157 return string(v.Raw())
158 case Array:
159 var ss []string
160 for _, v := range v.Array() {
161 ss = append(ss, v.String())
162 }
163 return "[" + strings.Join(ss, ",") + "]"
164 case Object:
165 var ss []string
166 for _, v := range v.Object() {
167 ss = append(ss, v[0].String()+":"+v[1].String())
168 }
169 return "{" + strings.Join(ss, ",") + "}"
170 default:
171 return "<invalid>"
172 }
173}
174
175// Array returns the elements of v and panics if the Type is not Array.
176// Mutations on the return value may not be observable from the Raw method.
177func (v Value) Array() []Value {
178 if v.typ != Array {
179 panic("value is not an array")
180 }
181 return v.arr
182}
183
184// Object returns the items of v and panics if the Type is not Object.
185// The [2]Value represents a key (of type String) and value pair.
186//
187// Mutations on the return value may not be observable from the Raw method.
188func (v Value) Object() [][2]Value {
189 if v.typ != Object {
190 panic("value is not an object")
191 }
192 return v.obj
193}
194
195// Raw returns the raw representation of the value.
196// The returned value may alias the input given to Unmarshal.
197func (v Value) Raw() []byte {
198 if len(v.raw) > 0 {
199 return v.raw
200 }
201 p := encoder{}
202 if err := p.marshalValue(v); !p.nerr.Merge(err) {
203 return []byte("<invalid>")
204 }
205 return p.out
206}