Joe Tsai | 879b18d | 2018-08-03 17:22:24 -0700 | [diff] [blame^] | 1 | // 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 |
| 16 | package json |
| 17 | |
| 18 | import ( |
| 19 | "fmt" |
| 20 | "strings" |
| 21 | ) |
| 22 | |
| 23 | // Type represents a type expressible in the JSON format. |
| 24 | type Type uint8 |
| 25 | |
| 26 | const ( |
| 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 | |
| 42 | func (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. |
| 62 | type 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. |
| 82 | func 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 | } |
| 116 | func 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. |
| 123 | func (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. |
| 128 | func (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. |
| 136 | func (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. |
| 148 | func (v Value) String() string { |
| 149 | if v.typ != String { |
| 150 | return v.stringValue() |
| 151 | } |
| 152 | return v.str |
| 153 | } |
| 154 | func (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. |
| 177 | func (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. |
| 188 | func (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. |
| 197 | func (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 | } |