// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package json implements the JSON format. // This package has no semantic understanding for protocol buffers and is only // a parser and composer for the format. // // This follows RFC 7159, with some notable implementation specifics: // * numbers that are out of range result in a decoding error // * duplicate keys in objects are not rejected // // Reasons why the standard encoding/json package is not suitable: // * information about duplicate keys is lost // * invalid UTF-8 is silently coerced into utf8.RuneError package json import ( "fmt" "strings" ) // Type represents a type expressible in the JSON format. type Type uint8 const ( _ Type = iota // Null is the null literal (i.e., "null"). Null // Bool is a boolean (i.e., "true" or "false"). Bool // Number is a floating-point number (e.g., "1.234" or "1e100"). Number // String is an escaped string (e.g., `"the quick brown fox"`). String // Array is an ordered list of values (e.g., `[0, "one", true]`). Array // Object is an ordered map of values (e.g., `{"key": null}`). Object ) func (t Type) String() string { switch t { case Null: return "null" case Bool: return "bool" case Number: return "number" case String: return "string" case Array: return "array" case Object: return "object" default: return "" } } // Value contains a value of a given Type. type Value struct { typ Type raw []byte // raw bytes of the serialized data str string // only for String num float64 // only for Bool or Number arr []Value // only for Array obj [][2]Value // only for Object } // ValueOf returns a Value for a given Go value: // nil => Null // bool => Bool // int32, int64 => Number // uint32, uint64 => Number // float32, float64 => Number // string, []byte => String // []Value => Array // [][2]Value => Object // // ValueOf panics if the Go type is not one of the above. func ValueOf(v interface{}) Value { switch v := v.(type) { case nil: return Value{typ: Null} case bool: if v { return Value{typ: Bool, num: 1} } else { return Value{typ: Bool, num: 0} } case int32: return Value{typ: Number, num: float64(v)} case int64: return Value{typ: Number, num: float64(v)} // possible loss of precision case uint32: return Value{typ: Number, num: float64(v)} case uint64: return Value{typ: Number, num: float64(v)} // possible loss of precision case float32: return Value{typ: Number, num: float64(v)} case float64: return Value{typ: Number, num: float64(v)} case string: return Value{typ: String, str: string(v)} case []byte: return Value{typ: String, str: string(v)} case []Value: return Value{typ: Array, arr: v} case [][2]Value: return Value{typ: Object, obj: v} default: panic(fmt.Sprintf("invalid type %T", v)) } } func rawValueOf(v interface{}, raw []byte) Value { v2 := ValueOf(v) v2.raw = raw return v2 } // Type is the type of the value. func (v Value) Type() Type { return v.typ } // Bool returns v as a bool and panics if it is not a Bool. func (v Value) Bool() bool { if v.typ != Bool { panic("value is not a boolean") } return v.num != 0 } // Number returns v as a float64 and panics if it is not a Number. func (v Value) Number() float64 { if v.typ != Number { panic("value is not a number") } return v.num } // String returns v as a string if the Type is String. // Otherwise, this returns a formatted string of v for debugging purposes. // // Since JSON strings must be UTF-8, the marshaler and unmarshaler will verify // for UTF-8 correctness. func (v Value) String() string { if v.typ != String { return v.stringValue() } return v.str } func (v Value) stringValue() string { switch v.typ { case Null, Bool, Number: return string(v.Raw()) case Array: var ss []string for _, v := range v.Array() { ss = append(ss, v.String()) } return "[" + strings.Join(ss, ",") + "]" case Object: var ss []string for _, v := range v.Object() { ss = append(ss, v[0].String()+":"+v[1].String()) } return "{" + strings.Join(ss, ",") + "}" default: return "" } } // Array returns the elements of v and panics if the Type is not Array. // Mutations on the return value may not be observable from the Raw method. func (v Value) Array() []Value { if v.typ != Array { panic("value is not an array") } return v.arr } // Object returns the items of v and panics if the Type is not Object. // The [2]Value represents a key (of type String) and value pair. // // Mutations on the return value may not be observable from the Raw method. func (v Value) Object() [][2]Value { if v.typ != Object { panic("value is not an object") } return v.obj } // Raw returns the raw representation of the value. // The returned value may alias the input given to Unmarshal. func (v Value) Raw() []byte { if len(v.raw) > 0 { return v.raw } p := encoder{} if err := p.marshalValue(v); !p.nerr.Merge(err) { return []byte("") } return p.out }