Signed-off-by: Jessica Frazelle <acidburn@docker.com>
This commit is contained in:
Jessica Frazelle 2015-08-01 20:23:39 -07:00
Родитель b5eeb160cb
Коммит 561e20406c
8 изменённых файлов: 49 добавлений и 288 удалений

Просмотреть файл

@ -168,13 +168,12 @@ func (n Number) Int64() (int64, error) {
// decodeState represents the state while decoding a JSON value.
type decodeState struct {
data []byte
off int // read offset in data
scan scanner
nextscan scanner // for calls to nextValue
savedError error
useNumber bool
useOrderedObject bool
data []byte
off int // read offset in data
scan scanner
nextscan scanner // for calls to nextValue
savedError error
useNumber bool
}
// errPhase is used for errors that should not happen unless
@ -493,13 +492,9 @@ func (d *decodeState) object(v reflect.Value) {
}
v = pv
// If we are decoding into a OrderedObject then use an OrderedObject
// just for this particular object even if UseOrderedObject was not called.
forceOrderedObject := v.Type() == orderedObjectType
// Decoding into nil interface? Switch to non-reflect code.
if (v.Kind() == reflect.Interface && v.NumMethod() == 0) || forceOrderedObject {
v.Set(reflect.ValueOf(d.objectInterface(forceOrderedObject)))
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
v.Set(reflect.ValueOf(d.objectInterface()))
return
}
@ -836,7 +831,7 @@ func (d *decodeState) valueInterface() interface{} {
case scanBeginArray:
return d.arrayInterface()
case scanBeginObject:
return d.objectInterface(false)
return d.objectInterface()
case scanBeginLiteral:
return d.literalInterface()
}
@ -870,10 +865,9 @@ func (d *decodeState) arrayInterface() []interface{} {
return v
}
// objectInterface is like object but returns map[string]interface{} or []OrderedObject.
func (d *decodeState) objectInterface(forceOrderedObject bool) interface{} {
// objectInterface is like object but returns map[string]interface{}.
func (d *decodeState) objectInterface() map[string]interface{} {
m := make(map[string]interface{})
v := make(OrderedObject, 0)
for {
// Read opening " of string key or closing }.
op := d.scanWhile(scanSkipSpace)
@ -903,11 +897,7 @@ func (d *decodeState) objectInterface(forceOrderedObject bool) interface{} {
}
// Read value.
if d.useOrderedObject || forceOrderedObject {
v = append(v, Member{Key: key, Value: d.valueInterface()})
} else {
m[key] = d.valueInterface()
}
m[key] = d.valueInterface()
// Next token must be , or }.
op = d.scanWhile(scanSkipSpace)
@ -918,10 +908,6 @@ func (d *decodeState) objectInterface(forceOrderedObject bool) interface{} {
d.error(errPhase)
}
}
if d.useOrderedObject || forceOrderedObject {
return v
}
return m
}

Просмотреть файл

@ -36,14 +36,14 @@ type V struct {
var ifaceNumAsFloat64 = map[string]interface{}{
"k1": float64(1),
"k2": "s",
"k3": []interface{}{float64(1), float64(2.0), float64(3)},
"k3": []interface{}{float64(1), float64(2.0), float64(3e-3)},
"k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)},
}
var ifaceNumAsNumber = map[string]interface{}{
"k1": Number("1"),
"k2": "s",
"k3": []interface{}{Number("1"), Number("2.0"), Number("3")},
"k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")},
"k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")},
}
@ -197,12 +197,11 @@ type S13 struct {
}
type unmarshalTest struct {
in string
ptr interface{}
out interface{}
err error
useNumber bool
useOrderedObject bool
in string
ptr interface{}
out interface{}
err error
useNumber bool
}
type Ambig struct {
@ -221,7 +220,7 @@ var unmarshalTests = []unmarshalTest{
// basic types
{in: `true`, ptr: new(bool), out: true},
{in: `1`, ptr: new(int), out: 1},
{in: `1.0`, ptr: new(float64), out: 1.0},
{in: `1.2`, ptr: new(float64), out: 1.2},
{in: `-5`, ptr: new(int16), out: int16(-5)},
{in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
{in: `2`, ptr: new(Number), out: Number("2")},
@ -236,13 +235,13 @@ var unmarshalTests = []unmarshalTest{
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true},
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true},
// raw values with whitespace
{in: "\n true ", ptr: new(bool), out: true},
{in: "\t 1 ", ptr: new(int), out: 1},
{in: "\r 1.0 ", ptr: new(float64), out: 1.0},
{in: "\r 1.2 ", ptr: new(float64), out: 1.2},
{in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
{in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"},
@ -414,39 +413,6 @@ var unmarshalTests = []unmarshalTest{
ptr: &map[time.Time]string{},
err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
},
// OrderedObject tests - into interface{}
{in: `{"a":"1","b":2,"c":3}`, ptr: new(interface{}), useOrderedObject: true,
out: OrderedObject{{"a", "1"}, {"b", float64(2)}, {"c", float64(3)}}},
{in: `[{"a":"1","b":2}]`, ptr: new(interface{}), useOrderedObject: true,
out: []interface{}{OrderedObject{{"a", "1"}, {"b", float64(2)}}}},
{in: `{"a":null,"b": {"c":true} }`, ptr: new(interface{}), useOrderedObject: true,
out: OrderedObject{{"a", nil}, {"b", OrderedObject{{"c", true}}}}},
{in: `{"T":[]}`, ptr: new(interface{}), useOrderedObject: true,
out: OrderedObject{{Key: "T", Value: []interface{}{}}}},
{in: `{"T":null}`, ptr: new(interface{}), useOrderedObject: true,
out: OrderedObject{{Key: "T", Value: nil}}},
// OrderedObject tests - into map[string]interface{}
{in: `{"a":"1","b":2,"c":3}`, ptr: new(map[string]interface{}), useOrderedObject: true,
out: map[string]interface{}{"a": "1", "b": float64(2), "c": float64(3)}},
{in: `{"a":null,"b": {"c":true} }`, ptr: new(map[string]interface{}), useOrderedObject: true,
out: map[string]interface{}{"a": nil, "b": OrderedObject{{"c", true}}}},
{in: `{"T":[]}`, ptr: new(map[string]interface{}), useOrderedObject: true,
out: map[string]interface{}{"T": []interface{}{}}},
{in: `{"T":null}`, ptr: new(map[string]interface{}), useOrderedObject: true,
out: map[string]interface{}{"T": nil}},
// OrderedObject tests - into OrderedObject
{in: `{"a":"1","b":2,"c":3}`, ptr: new(OrderedObject), useOrderedObject: true,
out: OrderedObject{{"a", "1"}, {"b", float64(2)}, {"c", float64(3)}}},
{in: `{"a":"1","b":2,"c":3}`, ptr: new(OrderedObject),
out: OrderedObject{{"a", "1"}, {"b", float64(2)}, {"c", float64(3)}}},
{in: `{"a":null,"b": {"c":true} }`, ptr: new(OrderedObject), useOrderedObject: true,
out: OrderedObject{{"a", nil}, {"b", OrderedObject{{"c", true}}}}},
{in: `{"a":null,"b": {"c":true} }`, ptr: new(OrderedObject),
out: OrderedObject{{"a", nil}, {"b", map[string]interface{}{"c": true}}}},
// OrderedObject tests -into []OrderedObject
{in: `[{"a":"1","b":2},{"c":3}]`, ptr: &[]OrderedObject{},
out: []OrderedObject{{{"a", "1"}, {"b", float64(2)}}, {{"c", float64(3)}}}},
}
func TestMarshal(t *testing.T) {
@ -562,9 +528,6 @@ func TestUnmarshal(t *testing.T) {
if tt.useNumber {
dec.UseNumber()
}
if tt.useOrderedObject {
dec.UseOrderedObject()
}
if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%d: %v, want %v", i, err, tt.err)
continue
@ -592,9 +555,6 @@ func TestUnmarshal(t *testing.T) {
if tt.useNumber {
dec.UseNumber()
}
if tt.useOrderedObject {
dec.UseOrderedObject()
}
if err := dec.Decode(vv.Interface()); err != nil {
t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err)
continue
@ -836,8 +796,8 @@ var allValue = All{
Uint32: 10,
Uint64: 11,
Uintptr: 12,
Float32: 14,
Float64: 15,
Float32: 14.1,
Float64: 15.1,
Foo: "foo",
Foo2: "foo2",
IntStr: 42,
@ -858,7 +818,7 @@ var allValue = All{
ByteSlice: []byte{27, 28, 29},
Small: Small{Tag: "tag30"},
PSmall: &Small{Tag: "tag31"},
Interface: 5.0,
Interface: 5.2,
}
var pallValue = All{
@ -898,8 +858,8 @@ var allValueIndent = `{
"Uint32": 10,
"Uint64": 11,
"Uintptr": 12,
"Float32": 14,
"Float64": 15,
"Float32": 14.1,
"Float64": 15.1,
"bar": "foo",
"bar2": "foo2",
"IntStr": "42",
@ -971,7 +931,7 @@ var allValueIndent = `{
"Tag": "tag31"
},
"PPSmall": null,
"Interface": 5,
"Interface": 5.2,
"PInterface": null
}`
@ -1007,8 +967,8 @@ var pallValueIndent = `{
"PUint32": 10,
"PUint64": 11,
"PUintptr": 12,
"PFloat32": 14,
"PFloat64": 15,
"PFloat32": 14.1,
"PFloat64": 15.1,
"String": "",
"PString": "16",
"Map": null,
@ -1060,7 +1020,7 @@ var pallValueIndent = `{
"Tag": "tag31"
},
"Interface": null,
"PInterface": 5
"PInterface": 5.2
}`
var pallValueCompact = strings.Map(noSpace, pallValueIndent)
@ -1209,8 +1169,8 @@ func TestUnmarshalNulls(t *testing.T) {
Uint16: 9,
Uint32: 10,
Uint64: 11,
Float32: 12.0,
Float64: 13.0,
Float32: 12.1,
Float64: 13.1,
String: "14"}
err := Unmarshal(jsonData, &nulls)
@ -1219,7 +1179,7 @@ func TestUnmarshalNulls(t *testing.T) {
}
if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
nulls.Float32 != 12.0 || nulls.Float64 != 13.0 || nulls.String != "14" {
nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
t.Errorf("Unmarshal of null values affected primitives")
}
@ -1367,13 +1327,13 @@ func TestPrefilled(t *testing.T) {
}{
{
in: `{"X": 1, "Y": 2}`,
ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1},
out: &XYZ{X: float64(1), Y: float64(2), Z: 1},
ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5},
out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5},
},
{
in: `{"X": 1, "Y": 2}`,
ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1}),
out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1}),
ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}),
out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}),
},
}
@ -1411,22 +1371,3 @@ func TestInvalidUnmarshal(t *testing.T) {
}
}
}
type Obj struct {
A int
B OrderedObject
C string
}
func TestUnmarshalOrdered(t *testing.T) {
var v Obj
buf := []byte(`{"A": 3, "B": { "A": 5, "B": null}, "C": "C"}`)
exp := Obj{A: 3, B: OrderedObject{{"A", float64(5)}, {"B", nil}}, C: "C"}
err := Unmarshal(buf, &v)
if err != nil {
t.Errorf("Unmarshal unexpected error: %v", err)
}
if !reflect.DeepEqual(exp, v) {
t.Errorf("%v, want %v", v, exp)
}
}

Просмотреть файл

@ -14,7 +14,6 @@ import (
"bytes"
"encoding"
"encoding/base64"
"fmt"
"math"
"reflect"
"runtime"
@ -117,9 +116,6 @@ import (
// The map's key type must be string; the object keys are used directly
// as map keys.
//
// OrderedObject values encode as JSON objects.
// The JSON keys are encoded in the order in which they appear in the OrderedObject.
//
// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON object.
//
@ -354,7 +350,6 @@ func typeEncoder(t reflect.Type) encoderFunc {
var (
marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
orderedObjectType = reflect.TypeOf(new(OrderedObject)).Elem()
)
// newTypeEncoder constructs an encoderFunc for a type.
@ -378,10 +373,6 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
}
}
if t == orderedObjectType {
return orderedObjectEncoder
}
switch t.Kind() {
case reflect.Bool:
return boolEncoder
@ -520,11 +511,8 @@ type floatEncoder int // number of bits
func (bits floatEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
f := v.Float()
if math.IsInf(f, 0) || math.IsNaN(f) || math.Floor(f) != f {
e.error(&UnsupportedValueError{
v,
fmt.Sprintf("floating point number, %s", strconv.FormatFloat(f, 'g', -1, int(bits))),
})
if math.IsInf(f, 0) || math.IsNaN(f) {
e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
}
b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits))
if quoted {
@ -641,24 +629,6 @@ func newMapEncoder(t reflect.Type) encoderFunc {
return me.encode
}
func orderedObjectEncoder(e *encodeState, v reflect.Value, quoted bool) {
if v.IsNil() {
e.WriteString("null")
return
}
e.WriteByte('{')
var ov OrderedObject = v.Interface().(OrderedObject)
for i, o := range ov {
if i > 0 {
e.WriteByte(',')
}
e.string(o.Key)
e.WriteByte(':')
e.reflectValue(reflect.ValueOf(o.Value))
}
e.WriteByte('}')
}
func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) {
if v.IsNil() {
e.WriteString("null")

Просмотреть файл

@ -530,45 +530,3 @@ func TestEncodeString(t *testing.T) {
}
}
}
type ObjEnc struct {
A int
B OrderedObject
C interface{}
}
var orderedObjectTests = []struct {
in interface{}
out string
}{
{OrderedObject{}, `{}`},
{OrderedObject{Member{"A", []int{1, 2, 3}}, Member{"B", 23}, Member{"C", "C"}}, `{"A":[1,2,3],"B":23,"C":"C"}`},
{ObjEnc{A: 234, B: OrderedObject{Member{"K", "V"}, Member{"V", 4}}}, `{"A":234,"B":{"K":"V","V":4},"C":null}`},
{ObjEnc{A: 234, B: OrderedObject{}, C: OrderedObject{{"A", 0}}}, `{"A":234,"B":{},"C":{"A":0}}`},
{[]OrderedObject{{{"A", "Ay"}, {"B", "Bee"}}, {{"A", "Nay"}}}, `[{"A":"Ay","B":"Bee"},{"A":"Nay"}]`},
{map[string]OrderedObject{"A": {{"A", "Ay"}, {"B", "Bee"}}}, `{"A":{"A":"Ay","B":"Bee"}}`},
{map[string]interface{}{"A": OrderedObject{{"A", "Ay"}, {"B", "Bee"}}}, `{"A":{"A":"Ay","B":"Bee"}}`},
}
func TestEncodeOrderedObject(t *testing.T) {
for i, o := range orderedObjectTests {
d, err := Marshal(o.in)
if err != nil {
t.Errorf("Unexpected error %v", err)
continue
}
ds := string(d)
if o.out != ds {
t.Errorf("#%d expected '%v', was '%v'", i, o.out, ds)
}
}
}
func TestFloatError(t *testing.T) {
input := struct{ A float64 }{1.1}
_, err := Marshal(input)
if err == nil {
t.Errorf("want float error, got nil")
}
}

Просмотреть файл

@ -6,13 +6,12 @@ package json_test
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"os"
"strings"
"github.com/jfrazelle/go/canonical/json"
)
func ExampleMarshal() {
@ -160,43 +159,3 @@ func ExampleIndent() {
// = }
// =]
}
func ExampleOrderedObject() {
var jsonBlob = []byte(`[
{"name": "Issac Newton", "born": 1643, "died": 1727 },
{"name": "André-Marie Ampère", "born": 1777, "died": 1836 }
]`)
var people []json.OrderedObject
// Decode JSON while preserving the order of JSON key pairs.
err := json.Unmarshal(jsonBlob, &people)
if err != nil {
fmt.Println("unmarshalling error:", err)
}
fmt.Printf("Decoded:\n")
for _, v := range people {
for _, a := range v {
fmt.Printf(" %v=%v", a.Key, a.Value)
}
fmt.Printf("\n")
}
// Encode JSON keys in the order defined by the OrderedObject.
person := json.OrderedObject{
{Key: "name", Value: "Hans Christian Ørsted"},
{Key: "born", Value: 1777},
{Key: "died", Value: 1851},
{Key: "nationality", Value: "Danish"},
}
b, err := json.Marshal(person)
if err != nil {
fmt.Println("marshalling error:", err)
}
fmt.Printf("Encoded:\n %v", string(b))
// Output:
// Decoded:
// name=Issac Newton born=1643 died=1727
// name=André-Marie Ampère born=1777 died=1836
// Encoded:
// {"name":"Hans Christian Ørsted","born":1777,"died":1851,"nationality":"Danish"}
}

Просмотреть файл

@ -264,7 +264,7 @@ func genValue(n int) interface{} {
case 0:
return rand.Intn(2) == 0
case 1:
return math.Floor(rand.NormFloat64())
return rand.NormFloat64()
case 2:
return genString(30)
}

Просмотреть файл

@ -31,10 +31,6 @@ func NewDecoder(r io.Reader) *Decoder {
// Number instead of as a float64.
func (dec *Decoder) UseNumber() { dec.d.useNumber = true }
// UseOrderedObject causes the Decoder to unmarshal an object into an interface{}
// as a OrderedObject instead of as a map[string]interface{}.
func (dec *Decoder) UseOrderedObject() { dec.d.useOrderedObject = true }
// Decode reads the next JSON-encoded value from its
// input and stores it in the value pointed to by v.
//
@ -202,52 +198,3 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
var _ Marshaler = (*RawMessage)(nil)
var _ Unmarshaler = (*RawMessage)(nil)
// Member is used to store key/value pairs in an OrderedObject.
type Member struct {
Key string
Value interface{}
}
// OrderedObject stores the key/value pairs of a JSON object in the order
// in which they appeared in the original document. See the documentation for UseOrderedObject on the Decoder.
//
// OrderedObject is used to enable decoding of arbitrary JSON objects while preserving
// the order of the keys. Unmarshal and Decoder.Decode are supported.
//
// var o OrderedObject
// Unmarshal(json, &o) // decode JSON object, while preserving key order
//
// var oa []OrderedObject
// Unmarshal(json, &oa) // decode an array of JSON objects, while preserving key order
//
// var v interface{}
// d := new Decoder(json)
// d.UseOrderedObject() // decode all JSON objects as OrderedObject rather than map[string]interface{}
// d.Decode(&v)
//
// type A struct {
// B bool
// Inner OrderedObject
// I int
// }
// var a A
// Unmarshal(&a) // decode A as a JSON object with Inner as a nested object, preserving key order
//
// OrderedObject can also be used to encode a JSON object in
// a specified order. Marshal and Encoder.Encode are supported.
//
// var o OrderedObject
// Marshal(o) // encode JSON object, each with keys in OrderedObject order
//
// var oa []OrderedObject
// Marshal(oa) // encode an array of JSON objects, with keys in OrderedObject order
//
// type A struct {
// B bool
// Inner OrderedObject
// I int
// }
// var a A = createA()
// Marshal(a) // encode A as a JSON object with Inner as a nested object
type OrderedObject []Member

Просмотреть файл

@ -16,24 +16,24 @@ import (
// Test values for the stream test.
// One of each JSON kind.
var streamTest = []interface{}{
1.0,
0.1,
"hello",
nil,
true,
false,
[]interface{}{"a", "b", "c"},
map[string]interface{}{"": "Kelvin", "ß": "long s"},
3.0, // another value to make sure something can follow map
3.14, // another value to make sure something can follow map
}
var streamEncoded = `1
var streamEncoded = `0.1
"hello"
null
true
false
["a","b","c"]
{"ß":"long s","":"Kelvin"}
3
3.14
`
func TestEncoder(t *testing.T) {
@ -129,7 +129,7 @@ func TestRawMessage(t *testing.T) {
Y float32
}
const raw = `["\u0056",null]`
const msg = `{"X":1,"Id":["\u0056",null],"Y":2}`
const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
@ -154,7 +154,7 @@ func TestNullRawMessage(t *testing.T) {
Y float32
}
data.Id = new(RawMessage)
const msg = `{"X":1,"Id":null,"Y":2}`
const msg = `{"X":0.1,"Id":null,"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)