mirror of
https://github.com/golang/go
synced 2024-11-22 07:34:40 -07:00
json: Marshal, Unmarshal using new scanner
R=r CC=golang-dev https://golang.org/cl/953041
This commit is contained in:
parent
214a55b06a
commit
dba9d62bc2
@ -225,16 +225,13 @@ func expvarHandler(c *http.Conn, req *http.Request) {
|
||||
}
|
||||
|
||||
func memstats() string {
|
||||
var buf bytes.Buffer
|
||||
json.MarshalIndent(&buf, &runtime.MemStats, " ")
|
||||
s := buf.String()
|
||||
return s[0 : len(s)-1] // chop final \n
|
||||
b, _ := json.MarshalIndent(&runtime.MemStats, "", "\t")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func cmdline() string {
|
||||
var buf bytes.Buffer
|
||||
json.Marshal(&buf, os.Args)
|
||||
return buf.String()
|
||||
b, _ := json.Marshal(os.Args)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -61,7 +61,8 @@ func TestMapCounter(t *testing.T) {
|
||||
// colours.String() should be '{"red":3, "blue":4}',
|
||||
// though the order of red and blue could vary.
|
||||
s := colours.String()
|
||||
j, err := json.Decode(s)
|
||||
var j interface{}
|
||||
err := json.Unmarshal([]byte(s), &j)
|
||||
if err != nil {
|
||||
t.Errorf("colours.String() isn't valid JSON: %v", err)
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ include ../../Make.$(GOARCH)
|
||||
TARG=json
|
||||
GOFILES=\
|
||||
decode.go\
|
||||
encode.go\
|
||||
error.go\
|
||||
indent.go\
|
||||
parse.go\
|
||||
scanner.go\
|
||||
struct.go\
|
||||
|
||||
include ../../Make.pkg
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Copyright 2010 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.
|
||||
|
||||
@ -10,96 +10,888 @@ package json
|
||||
import (
|
||||
"container/vector"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"utf16"
|
||||
"utf8"
|
||||
)
|
||||
|
||||
// Decode a JSON string
|
||||
|
||||
// Decode parses the string s as a JSON-syntax string and returns the
|
||||
// generic JSON object representation. The object representation is a tree
|
||||
// of Go data types. The data return value may be one of float64, string,
|
||||
// bool, nil, []interface{} or map[string]interface{}. The array and map
|
||||
// elements may in turn contain any of the types listed above and so on.
|
||||
// Unmarshal parses the JSON-encoded data and stores the result
|
||||
// in the value pointed at by v.
|
||||
//
|
||||
// If Decode encounters a syntax error, it returns with err set to an
|
||||
// instance of ParseError. See ParseError documentation for details.
|
||||
func Decode(s string) (data interface{}, err os.Error) {
|
||||
jb := newDecoder(nil, nil)
|
||||
ok, errPos, errTok := Parse(s, jb)
|
||||
if ok {
|
||||
data = jb.Data()
|
||||
// Unmarshal traverses the value v recursively.
|
||||
// If an encountered value implements the Unmarshaler interface,
|
||||
// Unmarshal calls its UnmarshalJSON method with a well-formed
|
||||
// JSON encoding.
|
||||
//
|
||||
// Otherwise, Unmarshal uses the inverse of the encodings that
|
||||
// Marshal uses, allocating maps, slices, and pointers as necessary,
|
||||
// with the following additional rules:
|
||||
//
|
||||
// To unmarshal a JSON value into a nil interface value, the
|
||||
// type stored in the interface value is one of:
|
||||
//
|
||||
// bool, for JSON booleans
|
||||
// float64, for JSON numbers
|
||||
// string, for JSON strings
|
||||
// []interface{}, for JSON arrays
|
||||
// map[string]interface{}, for JSON objects
|
||||
// nil for JSON null
|
||||
//
|
||||
// If a JSON value is not appropriate for a given target type,
|
||||
// or if a JSON number overflows the target type, Unmarshal
|
||||
// skips that field and completes the unmarshalling as best it can.
|
||||
// If no more serious errors are encountered, Unmarshal returns
|
||||
// an UnmarshalTypeError describing the earliest such error.
|
||||
//
|
||||
func Unmarshal(data []byte, v interface{}) os.Error {
|
||||
d := new(decodeState).init(data)
|
||||
|
||||
// Quick check for well-formedness.
|
||||
// Avoids filling out half a data structure
|
||||
// before discovering a JSON syntax error.
|
||||
err := checkValid(data, &d.scan)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.unmarshal(v)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by objects
|
||||
// that can unmarshal a JSON description of themselves.
|
||||
// The input can be assumed to be a valid JSON object
|
||||
// encoding. UnmarshalJSON must copy the JSON data
|
||||
// if it wishes to retain the data after returning.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalJSON([]byte) os.Error
|
||||
}
|
||||
|
||||
|
||||
// An UnmarshalTypeError describes a JSON value that was
|
||||
// not appropriate for a value of a specific Go type.
|
||||
type UnmarshalTypeError struct {
|
||||
Value string // description of JSON value - "bool", "array", "number -5"
|
||||
Type reflect.Type // type of Go value it could not be assigned to
|
||||
}
|
||||
|
||||
func (e *UnmarshalTypeError) String() string {
|
||||
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
|
||||
}
|
||||
|
||||
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
|
||||
// (The argument to Unmarshal must be a non-nil pointer.)
|
||||
type InvalidUnmarshalError struct {
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
func (e *InvalidUnmarshalError) String() string {
|
||||
if e.Type == nil {
|
||||
return "json: Unmarshal(nil)"
|
||||
}
|
||||
|
||||
if _, ok := e.Type.(*reflect.PtrType); !ok {
|
||||
return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
|
||||
}
|
||||
return "json: Unmarshal(nil " + e.Type.String() + ")"
|
||||
}
|
||||
|
||||
func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
err = r.(os.Error)
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.NewValue(v)
|
||||
pv, ok := rv.(*reflect.PtrValue)
|
||||
if !ok || pv.IsNil() {
|
||||
return &InvalidUnmarshalError{reflect.Typeof(v)}
|
||||
}
|
||||
|
||||
d.scan.reset()
|
||||
d.value(pv.Elem())
|
||||
return d.savedError
|
||||
}
|
||||
|
||||
// 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 os.Error
|
||||
}
|
||||
|
||||
// errPhase is used for errors that should not happen unless
|
||||
// there is a bug in the JSON decoder or something is editing
|
||||
// the data slice while the decoder executes.
|
||||
var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
|
||||
|
||||
func (d *decodeState) init(data []byte) *decodeState {
|
||||
d.data = data
|
||||
d.off = 0
|
||||
d.savedError = nil
|
||||
return d
|
||||
}
|
||||
|
||||
// error aborts the decoding by panicking with err.
|
||||
func (d *decodeState) error(err os.Error) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// saveError saves the first err it is called with,
|
||||
// for reporting at the end of the unmarshal.
|
||||
func (d *decodeState) saveError(err os.Error) {
|
||||
if d.savedError == nil {
|
||||
d.savedError = err
|
||||
}
|
||||
}
|
||||
|
||||
// next cuts off and returns the next full JSON value in d.data[d.off:].
|
||||
// The next value is known to be an object or array, not a literal.
|
||||
func (d *decodeState) next() []byte {
|
||||
c := d.data[d.off]
|
||||
item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
|
||||
if err != nil {
|
||||
d.error(err)
|
||||
}
|
||||
d.off = len(d.data) - len(rest)
|
||||
|
||||
// Our scanner has seen the opening brace/bracket
|
||||
// and thinks we're still in the middle of the object.
|
||||
// invent a closing brace/bracket to get it out.
|
||||
if c == '{' {
|
||||
d.scan.step(&d.scan, '}')
|
||||
} else {
|
||||
err = &ParseError{Index: errPos, Token: errTok}
|
||||
d.scan.step(&d.scan, ']')
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// scanWhile processes bytes in d.data[d.off:] until it
|
||||
// receives a scan code not equal to op.
|
||||
// It updates d.off and returns the new scan code.
|
||||
func (d *decodeState) scanWhile(op int) int {
|
||||
var newOp int
|
||||
for {
|
||||
if d.off >= len(d.data) {
|
||||
newOp = d.scan.eof()
|
||||
d.off = len(d.data) + 1 // mark processed EOF with len+1
|
||||
} else {
|
||||
c := int(d.data[d.off])
|
||||
d.off++
|
||||
newOp = d.scan.step(&d.scan, c)
|
||||
}
|
||||
if newOp != op {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newOp
|
||||
}
|
||||
|
||||
// value decodes a JSON value from d.data[d.off:] into the value.
|
||||
// it updates d.off to point past the decoded value.
|
||||
func (d *decodeState) value(v reflect.Value) {
|
||||
if v == nil {
|
||||
_, rest, err := nextValue(d.data[d.off:], &d.nextscan)
|
||||
if err != nil {
|
||||
d.error(err)
|
||||
}
|
||||
d.off = len(d.data) - len(rest)
|
||||
|
||||
// d.scan thinks we're still at the beginning of the item.
|
||||
// Feed in an empty string - the shortest, simplest value -
|
||||
// so that it knows we got to the end of the value.
|
||||
if d.scan.step == stateRedo {
|
||||
panic("redo")
|
||||
}
|
||||
d.scan.step(&d.scan, '"')
|
||||
d.scan.step(&d.scan, '"')
|
||||
return
|
||||
}
|
||||
|
||||
switch op := d.scanWhile(scanSkipSpace); op {
|
||||
default:
|
||||
d.error(errPhase)
|
||||
|
||||
case scanBeginArray:
|
||||
d.array(v)
|
||||
|
||||
case scanBeginObject:
|
||||
d.object(v)
|
||||
|
||||
case scanBeginLiteral:
|
||||
d.literal(v)
|
||||
}
|
||||
}
|
||||
|
||||
// indirect walks down v allocating pointers as needed,
|
||||
// until it gets to a non-pointer.
|
||||
// if it encounters an Unmarshaler, indirect stops and returns that.
|
||||
// if wantptr is true, indirect stops at the last pointer.
|
||||
func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
|
||||
for {
|
||||
var isUnmarshaler bool
|
||||
if v.Type().NumMethod() > 0 {
|
||||
// Remember that this is an unmarshaler,
|
||||
// but wait to return it until after allocating
|
||||
// the pointer (if necessary).
|
||||
_, isUnmarshaler = v.Interface().(Unmarshaler)
|
||||
}
|
||||
|
||||
pv, ok := v.(*reflect.PtrValue)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
_, isptrptr := pv.Elem().(*reflect.PtrValue)
|
||||
if !isptrptr && wantptr && !isUnmarshaler {
|
||||
return nil, pv
|
||||
}
|
||||
pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
|
||||
if isUnmarshaler {
|
||||
// Using v.Interface().(Unmarshaler)
|
||||
// here means that we have to use a pointer
|
||||
// as the struct field. We cannot use a value inside
|
||||
// a pointer to a struct, because in that case
|
||||
// v.Interface() is the value (x.f) not the pointer (&x.f).
|
||||
// This is an unfortunate consequence of reflect.
|
||||
// An alternative would be to look up the
|
||||
// UnmarshalJSON method and return a FuncValue.
|
||||
return v.Interface().(Unmarshaler), nil
|
||||
}
|
||||
v = pv.Elem()
|
||||
}
|
||||
return nil, v
|
||||
}
|
||||
|
||||
// array consumes an array from d.data[d.off-1:], decoding into the value v.
|
||||
// the first byte of the array ('[') has been read already.
|
||||
func (d *decodeState) array(v reflect.Value) {
|
||||
// Check for unmarshaler.
|
||||
unmarshaler, pv := d.indirect(v, false)
|
||||
if unmarshaler != nil {
|
||||
d.off--
|
||||
err := unmarshaler.UnmarshalJSON(d.next())
|
||||
if err != nil {
|
||||
d.error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
v = pv
|
||||
|
||||
type decoder struct {
|
||||
// A value being constructed.
|
||||
value interface{}
|
||||
// Container entity to flush into. Can be either vector.Vector or
|
||||
// map[string]interface{}.
|
||||
container interface{}
|
||||
// The index into the container interface. Either int or string.
|
||||
index interface{}
|
||||
}
|
||||
// Decoding into nil interface? Switch to non-reflect code.
|
||||
iv, ok := v.(*reflect.InterfaceValue)
|
||||
if ok {
|
||||
iv.Set(reflect.NewValue(d.arrayInterface()))
|
||||
return
|
||||
}
|
||||
|
||||
func newDecoder(container interface{}, key interface{}) *decoder {
|
||||
return &decoder{container: container, index: key}
|
||||
}
|
||||
|
||||
func (j *decoder) Int64(i int64) { j.value = float64(i) }
|
||||
|
||||
func (j *decoder) Uint64(i uint64) { j.value = float64(i) }
|
||||
|
||||
func (j *decoder) Float64(f float64) { j.value = float64(f) }
|
||||
|
||||
func (j *decoder) String(s string) { j.value = s }
|
||||
|
||||
func (j *decoder) Bool(b bool) { j.value = b }
|
||||
|
||||
func (j *decoder) Null() { j.value = nil }
|
||||
|
||||
func (j *decoder) Array() { j.value = new(vector.Vector) }
|
||||
|
||||
func (j *decoder) Map() { j.value = make(map[string]interface{}) }
|
||||
|
||||
func (j *decoder) Elem(i int) Builder {
|
||||
v, ok := j.value.(*vector.Vector)
|
||||
// Check type of target.
|
||||
av, ok := v.(reflect.ArrayOrSliceValue)
|
||||
if !ok {
|
||||
v = new(vector.Vector)
|
||||
j.value = v
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||
}
|
||||
|
||||
sv, _ := v.(*reflect.SliceValue)
|
||||
|
||||
i := 0
|
||||
for {
|
||||
// Look ahead for ] - can only happen on first iteration.
|
||||
op := d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndArray {
|
||||
break
|
||||
}
|
||||
|
||||
// Back up so d.value can have the byte we just read.
|
||||
d.off--
|
||||
d.scan.undo(op)
|
||||
|
||||
// Get element of array, growing if necessary.
|
||||
if i >= av.Cap() && sv != nil {
|
||||
newcap := sv.Cap() + sv.Cap()/2
|
||||
if newcap < 4 {
|
||||
newcap = 4
|
||||
}
|
||||
newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
|
||||
reflect.ArrayCopy(newv, sv)
|
||||
sv.Set(newv)
|
||||
}
|
||||
if i >= av.Len() && sv != nil {
|
||||
// Must be slice; gave up on array during i >= av.Cap().
|
||||
sv.SetLen(i + 1)
|
||||
}
|
||||
|
||||
// Decode into element.
|
||||
if i < av.Len() {
|
||||
d.value(av.Elem(i))
|
||||
} else {
|
||||
// Ran out of fixed array: skip.
|
||||
d.value(nil)
|
||||
}
|
||||
i++
|
||||
|
||||
// Next token must be , or ].
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndArray {
|
||||
break
|
||||
}
|
||||
if op != scanArrayValue {
|
||||
d.error(errPhase)
|
||||
}
|
||||
}
|
||||
if i < av.Len() {
|
||||
if sv == nil {
|
||||
// Array. Zero the rest.
|
||||
z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
|
||||
for ; i < av.Len(); i++ {
|
||||
av.Elem(i).SetValue(z)
|
||||
}
|
||||
} else {
|
||||
sv.SetLen(i)
|
||||
}
|
||||
if v.Len() <= i {
|
||||
v.Resize(i+1, (i+1)*2)
|
||||
}
|
||||
return newDecoder(v, i)
|
||||
}
|
||||
|
||||
func (j *decoder) Key(s string) Builder {
|
||||
m, ok := j.value.(map[string]interface{})
|
||||
// matchName returns true if key should be written to a field named name.
|
||||
func matchName(key, name string) bool {
|
||||
return strings.ToLower(key) == strings.ToLower(name)
|
||||
}
|
||||
|
||||
// object consumes an object from d.data[d.off-1:], decoding into the value v.
|
||||
// the first byte of the object ('{') has been read already.
|
||||
func (d *decodeState) object(v reflect.Value) {
|
||||
// Check for unmarshaler.
|
||||
unmarshaler, pv := d.indirect(v, false)
|
||||
if unmarshaler != nil {
|
||||
d.off--
|
||||
err := unmarshaler.UnmarshalJSON(d.next())
|
||||
if err != nil {
|
||||
d.error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
v = pv
|
||||
|
||||
// Decoding into nil interface? Switch to non-reflect code.
|
||||
iv, ok := v.(*reflect.InterfaceValue)
|
||||
if ok {
|
||||
iv.Set(reflect.NewValue(d.objectInterface()))
|
||||
return
|
||||
}
|
||||
|
||||
// Check type of target: struct or map[string]T
|
||||
var (
|
||||
mv *reflect.MapValue
|
||||
sv *reflect.StructValue
|
||||
)
|
||||
switch v := v.(type) {
|
||||
case *reflect.MapValue:
|
||||
// map must have string type
|
||||
t := v.Type().(*reflect.MapType)
|
||||
if t.Key() != reflect.Typeof("") {
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||
break
|
||||
}
|
||||
mv = v
|
||||
if mv.IsNil() {
|
||||
mv.SetValue(reflect.MakeMap(t))
|
||||
}
|
||||
case *reflect.StructValue:
|
||||
sv = v
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||
}
|
||||
|
||||
if mv == nil && sv == nil {
|
||||
d.off--
|
||||
d.next() // skip over { } in input
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
// Read opening " of string key or closing }.
|
||||
op := d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndObject {
|
||||
// closing } - can only happen on first iteration.
|
||||
break
|
||||
}
|
||||
if op != scanBeginLiteral {
|
||||
d.error(errPhase)
|
||||
}
|
||||
|
||||
// Read string key.
|
||||
start := d.off - 1
|
||||
op = d.scanWhile(scanContinue)
|
||||
item := d.data[start : d.off-1]
|
||||
key, ok := unquote(item)
|
||||
if !ok {
|
||||
m = make(map[string]interface{})
|
||||
j.value = m
|
||||
d.error(errPhase)
|
||||
}
|
||||
return newDecoder(m, s)
|
||||
}
|
||||
|
||||
func (j *decoder) Flush() {
|
||||
switch c := j.container.(type) {
|
||||
case *vector.Vector:
|
||||
index := j.index.(int)
|
||||
c.Set(index, j.Data())
|
||||
case map[string]interface{}:
|
||||
index := j.index.(string)
|
||||
c[index] = j.Data()
|
||||
// Figure out
|
||||
var subv reflect.Value
|
||||
if mv != nil {
|
||||
subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
|
||||
} else {
|
||||
for i := 0; i < sv.NumField(); i++ {
|
||||
f := sv.Type().(*reflect.StructType).Field(i)
|
||||
if f.Tag == key {
|
||||
subv = sv.Field(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
if subv == nil {
|
||||
subv = sv.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
|
||||
}
|
||||
}
|
||||
|
||||
// Read : before value.
|
||||
if op == scanSkipSpace {
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
}
|
||||
if op != scanObjectKey {
|
||||
d.error(errPhase)
|
||||
}
|
||||
|
||||
// Read value.
|
||||
d.value(subv)
|
||||
|
||||
// Write value back to map;
|
||||
// if using struct, subv points into struct already.
|
||||
if mv != nil {
|
||||
mv.SetElem(reflect.NewValue(key), subv)
|
||||
}
|
||||
|
||||
// Next token must be , or }.
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndObject {
|
||||
break
|
||||
}
|
||||
if op != scanObjectValue {
|
||||
d.error(errPhase)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the value built by this builder.
|
||||
func (j *decoder) Data() interface{} {
|
||||
switch v := j.value.(type) {
|
||||
case *vector.Vector:
|
||||
return v.Data()
|
||||
// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
|
||||
// The first byte of the literal has been read already
|
||||
// (that's how the caller knows it's a literal).
|
||||
func (d *decodeState) literal(v reflect.Value) {
|
||||
// All bytes inside literal return scanContinue op code.
|
||||
start := d.off - 1
|
||||
op := d.scanWhile(scanContinue)
|
||||
|
||||
// Scan read one byte too far; back up.
|
||||
d.off--
|
||||
d.scan.undo(op)
|
||||
item := d.data[start:d.off]
|
||||
|
||||
// Check for unmarshaler.
|
||||
wantptr := item[0] == 'n' // null
|
||||
unmarshaler, pv := d.indirect(v, wantptr)
|
||||
if unmarshaler != nil {
|
||||
err := unmarshaler.UnmarshalJSON(item)
|
||||
if err != nil {
|
||||
d.error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
v = pv
|
||||
|
||||
switch c := item[0]; c {
|
||||
case 'n': // null
|
||||
switch v.(type) {
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"null", v.Type()})
|
||||
case *reflect.InterfaceValue, *reflect.PtrValue, *reflect.MapValue:
|
||||
v.SetValue(nil)
|
||||
}
|
||||
|
||||
case 't', 'f': // true, false
|
||||
value := c == 't'
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"bool", v.Type()})
|
||||
case *reflect.BoolValue:
|
||||
v.Set(value)
|
||||
case *reflect.InterfaceValue:
|
||||
v.Set(reflect.NewValue(value))
|
||||
}
|
||||
|
||||
case '"': // string
|
||||
s, ok := unquote(item)
|
||||
if !ok {
|
||||
d.error(errPhase)
|
||||
}
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type()})
|
||||
case *reflect.StringValue:
|
||||
v.Set(s)
|
||||
case *reflect.InterfaceValue:
|
||||
v.Set(reflect.NewValue(s))
|
||||
}
|
||||
|
||||
default: // number
|
||||
if c != '-' && (c < '0' || c > '9') {
|
||||
d.error(errPhase)
|
||||
}
|
||||
s := string(item)
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
d.error(&UnmarshalTypeError{"number", v.Type()})
|
||||
case *reflect.InterfaceValue:
|
||||
n, err := strconv.Atof64(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(reflect.NewValue(n))
|
||||
|
||||
case *reflect.IntValue:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
case *reflect.Int8Value:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil || int(int8(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(int8(n))
|
||||
case *reflect.Int16Value:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil || int(int16(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(int16(n))
|
||||
case *reflect.Int32Value:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil || int(int32(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(int32(n))
|
||||
case *reflect.Int64Value:
|
||||
n, err := strconv.Atoi64(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
|
||||
case *reflect.UintValue:
|
||||
n, err := strconv.Atoui(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
case *reflect.Uint8Value:
|
||||
n, err := strconv.Atoui(s)
|
||||
if err != nil || uint(uint8(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(uint8(n))
|
||||
case *reflect.Uint16Value:
|
||||
n, err := strconv.Atoui(s)
|
||||
if err != nil || uint(uint16(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(uint16(n))
|
||||
case *reflect.Uint32Value:
|
||||
n, err := strconv.Atoui(s)
|
||||
if err != nil || uint(uint32(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(uint32(n))
|
||||
case *reflect.Uint64Value:
|
||||
n, err := strconv.Atoui64(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
case *reflect.UintptrValue:
|
||||
n, err := strconv.Atoui64(s)
|
||||
if err != nil || uint64(uintptr(n)) != n {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(uintptr(n))
|
||||
|
||||
case *reflect.FloatValue:
|
||||
n, err := strconv.Atof(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
case *reflect.Float32Value:
|
||||
n, err := strconv.Atof32(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
case *reflect.Float64Value:
|
||||
n, err := strconv.Atof64(s)
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
break
|
||||
}
|
||||
v.Set(n)
|
||||
}
|
||||
}
|
||||
return j.value
|
||||
}
|
||||
|
||||
// The xxxInterface routines build up a value to be stored
|
||||
// in an empty interface. They are not strictly necessary,
|
||||
// but they avoid the weight of reflection in this common case.
|
||||
|
||||
// valueInterface is like value but returns interface{}
|
||||
func (d *decodeState) valueInterface() interface{} {
|
||||
switch d.scanWhile(scanSkipSpace) {
|
||||
default:
|
||||
d.error(errPhase)
|
||||
case scanBeginArray:
|
||||
return d.arrayInterface()
|
||||
case scanBeginObject:
|
||||
return d.objectInterface()
|
||||
case scanBeginLiteral:
|
||||
return d.literalInterface()
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// arrayInterface is like array but returns []interface{}.
|
||||
func (d *decodeState) arrayInterface() []interface{} {
|
||||
var v vector.Vector
|
||||
for {
|
||||
// Look ahead for ] - can only happen on first iteration.
|
||||
op := d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndArray {
|
||||
break
|
||||
}
|
||||
|
||||
// Back up so d.value can have the byte we just read.
|
||||
d.off--
|
||||
d.scan.undo(op)
|
||||
|
||||
v.Push(d.valueInterface())
|
||||
|
||||
// Next token must be , or ].
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndArray {
|
||||
break
|
||||
}
|
||||
if op != scanArrayValue {
|
||||
d.error(errPhase)
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// objectInterface is like object but returns map[string]interface{}.
|
||||
func (d *decodeState) objectInterface() map[string]interface{} {
|
||||
m := make(map[string]interface{})
|
||||
for {
|
||||
// Read opening " of string key or closing }.
|
||||
op := d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndObject {
|
||||
// closing } - can only happen on first iteration.
|
||||
break
|
||||
}
|
||||
if op != scanBeginLiteral {
|
||||
d.error(errPhase)
|
||||
}
|
||||
|
||||
// Read string key.
|
||||
start := d.off - 1
|
||||
op = d.scanWhile(scanContinue)
|
||||
item := d.data[start : d.off-1]
|
||||
key, ok := unquote(item)
|
||||
if !ok {
|
||||
d.error(errPhase)
|
||||
}
|
||||
|
||||
// Read : before value.
|
||||
if op == scanSkipSpace {
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
}
|
||||
if op != scanObjectKey {
|
||||
d.error(errPhase)
|
||||
}
|
||||
|
||||
// Read value.
|
||||
m[key] = d.valueInterface()
|
||||
|
||||
// Next token must be , or }.
|
||||
op = d.scanWhile(scanSkipSpace)
|
||||
if op == scanEndObject {
|
||||
break
|
||||
}
|
||||
if op != scanObjectValue {
|
||||
d.error(errPhase)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
|
||||
// literalInterface is like literal but returns an interface value.
|
||||
func (d *decodeState) literalInterface() interface{} {
|
||||
// All bytes inside literal return scanContinue op code.
|
||||
start := d.off - 1
|
||||
op := d.scanWhile(scanContinue)
|
||||
|
||||
// Scan read one byte too far; back up.
|
||||
d.off--
|
||||
d.scan.undo(op)
|
||||
item := d.data[start:d.off]
|
||||
|
||||
switch c := item[0]; c {
|
||||
case 'n': // null
|
||||
return nil
|
||||
|
||||
case 't', 'f': // true, false
|
||||
return c == 't'
|
||||
|
||||
case '"': // string
|
||||
s, ok := unquote(item)
|
||||
if !ok {
|
||||
d.error(errPhase)
|
||||
}
|
||||
return s
|
||||
|
||||
default: // number
|
||||
if c != '-' && (c < '0' || c > '9') {
|
||||
d.error(errPhase)
|
||||
}
|
||||
n, err := strconv.Atof64(string(item))
|
||||
if err != nil {
|
||||
d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(float64(0))})
|
||||
}
|
||||
return n
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
||||
// or it returns -1.
|
||||
func getu4(s []byte) int {
|
||||
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
|
||||
return -1
|
||||
}
|
||||
rune, err := strconv.Btoui64(string(s[2:6]), 16)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return int(rune)
|
||||
}
|
||||
|
||||
// unquote converts a quoted JSON string literal s into an actual string t.
|
||||
// The rules are different than for Go, so cannot use strconv.Unquote.
|
||||
func unquote(s []byte) (t string, ok bool) {
|
||||
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
||||
return
|
||||
}
|
||||
b := make([]byte, len(s)+2*utf8.UTFMax)
|
||||
w := 0
|
||||
for r := 1; r < len(s)-1; {
|
||||
// Out of room? Can only happen if s is full of
|
||||
// malformed UTF-8 and we're replacing each
|
||||
// byte with RuneError.
|
||||
if w >= len(b)-2*utf8.UTFMax {
|
||||
nb := make([]byte, (len(b)+utf8.UTFMax)*2)
|
||||
copy(nb, b[0:w])
|
||||
b = nb
|
||||
}
|
||||
switch c := s[r]; {
|
||||
case c == '\\':
|
||||
r++
|
||||
if r >= len(s)-1 {
|
||||
return
|
||||
}
|
||||
switch s[r] {
|
||||
default:
|
||||
return
|
||||
case '"', '\\', '/', '\'':
|
||||
b[w] = s[r]
|
||||
r++
|
||||
w++
|
||||
case 'b':
|
||||
b[w] = '\b'
|
||||
r++
|
||||
w++
|
||||
case 'f':
|
||||
b[w] = '\f'
|
||||
r++
|
||||
w++
|
||||
case 'n':
|
||||
b[w] = '\n'
|
||||
r++
|
||||
w++
|
||||
case 'r':
|
||||
b[w] = '\r'
|
||||
r++
|
||||
w++
|
||||
case 't':
|
||||
b[w] = '\t'
|
||||
r++
|
||||
w++
|
||||
case 'u':
|
||||
r--
|
||||
rune := getu4(s[r:])
|
||||
if rune < 0 {
|
||||
return
|
||||
}
|
||||
r += 6
|
||||
if utf16.IsSurrogate(rune) {
|
||||
rune1 := getu4(s[r:])
|
||||
if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
|
||||
// A valid pair; consume.
|
||||
r += 6
|
||||
w += utf8.EncodeRune(dec, b[w:])
|
||||
break
|
||||
}
|
||||
// Invalid surrogate; fall back to replacement rune.
|
||||
rune = unicode.ReplacementChar
|
||||
}
|
||||
w += utf8.EncodeRune(rune, b[w:])
|
||||
}
|
||||
|
||||
// Quote, control characters are invalid.
|
||||
case c == '"', c < ' ':
|
||||
return
|
||||
|
||||
// ASCII
|
||||
case c < utf8.RuneSelf:
|
||||
b[w] = c
|
||||
r++
|
||||
w++
|
||||
|
||||
// Coerce to well-formed UTF-8.
|
||||
default:
|
||||
rune, size := utf8.DecodeRune(s[r:])
|
||||
r += size
|
||||
w += utf8.EncodeRune(rune, b[w:])
|
||||
}
|
||||
}
|
||||
return string(b[0:w]), true
|
||||
}
|
||||
|
@ -1,133 +1,427 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Copyright 2010 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
|
||||
|
||||
import (
|
||||
"container/vector"
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeInt64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Int64(-15)
|
||||
assertResult(t, nb.Data(), float64(-15))
|
||||
type unmarshalTest struct {
|
||||
in string
|
||||
ptr interface{}
|
||||
out interface{}
|
||||
}
|
||||
|
||||
func TestDecodeUint64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Uint64(15)
|
||||
assertResult(t, nb.Data(), float64(15))
|
||||
var unmarshalTests = []unmarshalTest{
|
||||
// basic types
|
||||
unmarshalTest{`true`, new(bool), true},
|
||||
unmarshalTest{`1`, new(int), 1},
|
||||
unmarshalTest{`1.2`, new(float), 1.2},
|
||||
unmarshalTest{`-5`, new(int16), int16(-5)},
|
||||
unmarshalTest{`"a\u1234"`, new(string), "a\u1234"},
|
||||
unmarshalTest{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E"},
|
||||
unmarshalTest{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD"},
|
||||
unmarshalTest{"null", new(interface{}), nil},
|
||||
|
||||
// composite tests
|
||||
unmarshalTest{allValueIndent, new(All), allValue},
|
||||
unmarshalTest{allValueCompact, new(All), allValue},
|
||||
unmarshalTest{allValueIndent, new(*All), &allValue},
|
||||
unmarshalTest{allValueCompact, new(*All), &allValue},
|
||||
unmarshalTest{pallValueIndent, new(All), pallValue},
|
||||
unmarshalTest{pallValueCompact, new(All), pallValue},
|
||||
unmarshalTest{pallValueIndent, new(*All), &pallValue},
|
||||
unmarshalTest{pallValueCompact, new(*All), &pallValue},
|
||||
}
|
||||
|
||||
func TestDecodeFloat64(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Float64(3.14159)
|
||||
assertResult(t, nb.Data(), float64(3.14159))
|
||||
}
|
||||
func TestMarshal(t *testing.T) {
|
||||
b, err := Marshal(allValue)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal allValue: %v", err)
|
||||
}
|
||||
if string(b) != allValueCompact {
|
||||
t.Errorf("Marshal allValueCompact")
|
||||
diff(t, b, []byte(allValueCompact))
|
||||
return
|
||||
}
|
||||
|
||||
func TestDecodeString(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.String("Some string")
|
||||
assertResult(t, nb.Data(), "Some string")
|
||||
}
|
||||
|
||||
func TestDecodeBool(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Bool(true)
|
||||
assertResult(t, nb.Data(), true)
|
||||
}
|
||||
|
||||
func TestDecodeNull(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Null()
|
||||
assertResult(t, nb.Data(), nil)
|
||||
}
|
||||
|
||||
func TestDecodeEmptyArray(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Array()
|
||||
assertResult(t, nb.Data(), []interface{}{})
|
||||
}
|
||||
|
||||
func TestDecodeEmptyMap(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Map()
|
||||
assertResult(t, nb.Data(), map[string]interface{}{})
|
||||
}
|
||||
|
||||
func TestDecodeFlushElem(t *testing.T) {
|
||||
testVec := new(vector.Vector).Resize(2, 2)
|
||||
nb := newDecoder(testVec, 1)
|
||||
nb.Float64(3.14159)
|
||||
nb.Flush()
|
||||
assertResult(t, testVec.Data(), []interface{}{nil, float64(3.14159)})
|
||||
}
|
||||
|
||||
func TestDecodeFlushKey(t *testing.T) {
|
||||
testMap := make(map[string]interface{})
|
||||
nb := newDecoder(testMap, "key")
|
||||
nb.Float64(3.14159)
|
||||
nb.Flush()
|
||||
assertResult(t, testMap, map[string]interface{}{"key": float64(3.14159)})
|
||||
}
|
||||
|
||||
// Elem() and Key() are hard to test in isolation because all they do
|
||||
// is create a new, properly initialized, decoder, and modify state of
|
||||
// the underlying decoder. I'm testing them through already tested
|
||||
// Array(), String(), and Flush().
|
||||
|
||||
func TestDecodeElem(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Array()
|
||||
var b Builder = nb.Elem(0)
|
||||
b.String("0")
|
||||
b.Flush()
|
||||
assertResult(t, nb.Data(), []interface{}{"0"})
|
||||
}
|
||||
|
||||
func TestDecodeKey(t *testing.T) {
|
||||
nb := newDecoder(nil, nil)
|
||||
nb.Map()
|
||||
var b Builder = nb.Key("a")
|
||||
b.String("0")
|
||||
b.Flush()
|
||||
assertResult(t, nb.Data(), map[string]interface{}{"a": "0"})
|
||||
}
|
||||
|
||||
func assertResult(t *testing.T, results, expected interface{}) {
|
||||
if !reflect.DeepEqual(results, expected) {
|
||||
t.Fatalf("have %T(%#v) want %T(%#v)", results, results, expected, expected)
|
||||
b, err = Marshal(pallValue)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal pallValue: %v", err)
|
||||
}
|
||||
if string(b) != pallValueCompact {
|
||||
t.Errorf("Marshal pallValueCompact")
|
||||
diff(t, b, []byte(pallValueCompact))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type decodeTest struct {
|
||||
s string
|
||||
r interface{}
|
||||
}
|
||||
|
||||
var tests = []decodeTest{
|
||||
decodeTest{`null`, nil},
|
||||
decodeTest{`true`, true},
|
||||
decodeTest{`false`, false},
|
||||
decodeTest{`"abc"`, "abc"},
|
||||
decodeTest{`123`, float64(123)},
|
||||
decodeTest{`0.1`, float64(0.1)},
|
||||
decodeTest{`1e-10`, float64(1e-10)},
|
||||
decodeTest{`[]`, []interface{}{}},
|
||||
decodeTest{`[1,2,3,4]`, []interface{}{float64(1), float64(2), float64(3), float64(4)}},
|
||||
decodeTest{`[1,2,"abc",null,true,false]`, []interface{}{float64(1), float64(2), "abc", nil, true, false}},
|
||||
decodeTest{`{}`, map[string]interface{}{}},
|
||||
decodeTest{`{"a":1}`, map[string]interface{}{"a": float64(1)}},
|
||||
decodeTest{`"q\u0302"`, "q\u0302"},
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
if val, err := Decode(test.s); err != nil || !reflect.DeepEqual(val, test.r) {
|
||||
t.Errorf("Decode(%#q) = %v, %v want %v, nil", test.s, val, err, test.r)
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
var scan scanner
|
||||
for i, tt := range unmarshalTests {
|
||||
in := []byte(tt.in)
|
||||
if err := checkValid(in, &scan); err != nil {
|
||||
t.Errorf("#%d: checkValid: %v", i, err)
|
||||
continue
|
||||
}
|
||||
// v = new(right-type)
|
||||
v := reflect.NewValue(tt.ptr).(*reflect.PtrValue)
|
||||
v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
|
||||
if err := Unmarshal([]byte(in), v.Interface()); err != nil {
|
||||
t.Errorf("#%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
|
||||
t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
|
||||
data, _ := Marshal(v.Elem().Interface())
|
||||
println(string(data))
|
||||
data, _ = Marshal(tt.out)
|
||||
println(string(data))
|
||||
return
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalMarshal(t *testing.T) {
|
||||
var v interface{}
|
||||
if err := Unmarshal(jsonBig, &v); err != nil {
|
||||
t.Fatalf("Unmarshal: %v", err)
|
||||
}
|
||||
b, err := Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal: %v", err)
|
||||
}
|
||||
if bytes.Compare(jsonBig, b) != 0 {
|
||||
t.Errorf("Marshal jsonBig")
|
||||
diff(t, b, jsonBig)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func noSpace(c int) int {
|
||||
if isSpace(c) {
|
||||
return -1
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type All struct {
|
||||
Bool bool
|
||||
Int int
|
||||
Int8 int8
|
||||
Int16 int16
|
||||
Int32 int32
|
||||
Int64 int64
|
||||
Uint uint
|
||||
Uint8 uint8
|
||||
Uint16 uint16
|
||||
Uint32 uint32
|
||||
Uint64 uint64
|
||||
Uintptr uintptr
|
||||
Float float
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
|
||||
Foo string "bar"
|
||||
|
||||
PBool *bool
|
||||
PInt *int
|
||||
PInt8 *int8
|
||||
PInt16 *int16
|
||||
PInt32 *int32
|
||||
PInt64 *int64
|
||||
PUint *uint
|
||||
PUint8 *uint8
|
||||
PUint16 *uint16
|
||||
PUint32 *uint32
|
||||
PUint64 *uint64
|
||||
PUintptr *uintptr
|
||||
PFloat *float
|
||||
PFloat32 *float32
|
||||
PFloat64 *float64
|
||||
|
||||
String string
|
||||
PString *string
|
||||
|
||||
Map map[string]Small
|
||||
MapP map[string]*Small
|
||||
PMap *map[string]Small
|
||||
PMapP *map[string]*Small
|
||||
|
||||
EmptyMap map[string]Small
|
||||
NilMap map[string]Small
|
||||
|
||||
Slice []Small
|
||||
SliceP []*Small
|
||||
PSlice *[]Small
|
||||
PSliceP *[]*Small
|
||||
|
||||
EmptySlice []Small
|
||||
NilSlice []Small
|
||||
|
||||
StringSlice []string
|
||||
ByteSlice []byte
|
||||
|
||||
Small Small
|
||||
PSmall *Small
|
||||
PPSmall **Small
|
||||
|
||||
Interface interface{}
|
||||
PInterface *interface{}
|
||||
}
|
||||
|
||||
type Small struct {
|
||||
Tag string
|
||||
}
|
||||
|
||||
var allValue = All{
|
||||
Bool: true,
|
||||
Int: 2,
|
||||
Int8: 3,
|
||||
Int16: 4,
|
||||
Int32: 5,
|
||||
Int64: 6,
|
||||
Uint: 7,
|
||||
Uint8: 8,
|
||||
Uint16: 9,
|
||||
Uint32: 10,
|
||||
Uint64: 11,
|
||||
Uintptr: 12,
|
||||
Float: 13.1,
|
||||
Float32: 14.1,
|
||||
Float64: 15.1,
|
||||
Foo: "foo",
|
||||
String: "16",
|
||||
Map: map[string]Small{
|
||||
"17": Small{Tag: "tag17"},
|
||||
"18": Small{Tag: "tag18"},
|
||||
},
|
||||
MapP: map[string]*Small{
|
||||
"19": &Small{Tag: "tag19"},
|
||||
"20": nil,
|
||||
},
|
||||
EmptyMap: map[string]Small{},
|
||||
Slice: []Small{Small{Tag: "tag20"}, Small{Tag: "tag21"}},
|
||||
SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
|
||||
EmptySlice: []Small{},
|
||||
StringSlice: []string{"str24", "str25", "str26"},
|
||||
ByteSlice: []byte{27, 28, 29},
|
||||
Small: Small{Tag: "tag30"},
|
||||
PSmall: &Small{Tag: "tag31"},
|
||||
Interface: float64(5.2),
|
||||
}
|
||||
|
||||
var pallValue = All{
|
||||
PBool: &allValue.Bool,
|
||||
PInt: &allValue.Int,
|
||||
PInt8: &allValue.Int8,
|
||||
PInt16: &allValue.Int16,
|
||||
PInt32: &allValue.Int32,
|
||||
PInt64: &allValue.Int64,
|
||||
PUint: &allValue.Uint,
|
||||
PUint8: &allValue.Uint8,
|
||||
PUint16: &allValue.Uint16,
|
||||
PUint32: &allValue.Uint32,
|
||||
PUint64: &allValue.Uint64,
|
||||
PUintptr: &allValue.Uintptr,
|
||||
PFloat: &allValue.Float,
|
||||
PFloat32: &allValue.Float32,
|
||||
PFloat64: &allValue.Float64,
|
||||
PString: &allValue.String,
|
||||
PMap: &allValue.Map,
|
||||
PMapP: &allValue.MapP,
|
||||
PSlice: &allValue.Slice,
|
||||
PSliceP: &allValue.SliceP,
|
||||
PPSmall: &allValue.PSmall,
|
||||
PInterface: &allValue.Interface,
|
||||
}
|
||||
|
||||
var allValueIndent = `{
|
||||
"bool": true,
|
||||
"int": 2,
|
||||
"int8": 3,
|
||||
"int16": 4,
|
||||
"int32": 5,
|
||||
"int64": 6,
|
||||
"uint": 7,
|
||||
"uint8": 8,
|
||||
"uint16": 9,
|
||||
"uint32": 10,
|
||||
"uint64": 11,
|
||||
"uintptr": 12,
|
||||
"float": 13.1,
|
||||
"float32": 14.1,
|
||||
"float64": 15.1,
|
||||
"bar": "foo",
|
||||
"pbool": null,
|
||||
"pint": null,
|
||||
"pint8": null,
|
||||
"pint16": null,
|
||||
"pint32": null,
|
||||
"pint64": null,
|
||||
"puint": null,
|
||||
"puint8": null,
|
||||
"puint16": null,
|
||||
"puint32": null,
|
||||
"puint64": null,
|
||||
"puintptr": null,
|
||||
"pfloat": null,
|
||||
"pfloat32": null,
|
||||
"pfloat64": null,
|
||||
"string": "16",
|
||||
"pstring": null,
|
||||
"map": {
|
||||
"17": {
|
||||
"tag": "tag17"
|
||||
},
|
||||
"18": {
|
||||
"tag": "tag18"
|
||||
}
|
||||
},
|
||||
"mapp": {
|
||||
"19": {
|
||||
"tag": "tag19"
|
||||
},
|
||||
"20": null
|
||||
},
|
||||
"pmap": null,
|
||||
"pmapp": null,
|
||||
"emptymap": {},
|
||||
"nilmap": null,
|
||||
"slice": [
|
||||
{
|
||||
"tag": "tag20"
|
||||
},
|
||||
{
|
||||
"tag": "tag21"
|
||||
}
|
||||
],
|
||||
"slicep": [
|
||||
{
|
||||
"tag": "tag22"
|
||||
},
|
||||
null,
|
||||
{
|
||||
"tag": "tag23"
|
||||
}
|
||||
],
|
||||
"pslice": null,
|
||||
"pslicep": null,
|
||||
"emptyslice": [],
|
||||
"nilslice": [],
|
||||
"stringslice": [
|
||||
"str24",
|
||||
"str25",
|
||||
"str26"
|
||||
],
|
||||
"byteslice": [
|
||||
27,
|
||||
28,
|
||||
29
|
||||
],
|
||||
"small": {
|
||||
"tag": "tag30"
|
||||
},
|
||||
"psmall": {
|
||||
"tag": "tag31"
|
||||
},
|
||||
"ppsmall": null,
|
||||
"interface": 5.2,
|
||||
"pinterface": null
|
||||
}`
|
||||
|
||||
var allValueCompact = strings.Map(noSpace, allValueIndent)
|
||||
|
||||
var pallValueIndent = `{
|
||||
"bool": false,
|
||||
"int": 0,
|
||||
"int8": 0,
|
||||
"int16": 0,
|
||||
"int32": 0,
|
||||
"int64": 0,
|
||||
"uint": 0,
|
||||
"uint8": 0,
|
||||
"uint16": 0,
|
||||
"uint32": 0,
|
||||
"uint64": 0,
|
||||
"uintptr": 0,
|
||||
"float": 0,
|
||||
"float32": 0,
|
||||
"float64": 0,
|
||||
"bar": "",
|
||||
"pbool": true,
|
||||
"pint": 2,
|
||||
"pint8": 3,
|
||||
"pint16": 4,
|
||||
"pint32": 5,
|
||||
"pint64": 6,
|
||||
"puint": 7,
|
||||
"puint8": 8,
|
||||
"puint16": 9,
|
||||
"puint32": 10,
|
||||
"puint64": 11,
|
||||
"puintptr": 12,
|
||||
"pfloat": 13.1,
|
||||
"pfloat32": 14.1,
|
||||
"pfloat64": 15.1,
|
||||
"string": "",
|
||||
"pstring": "16",
|
||||
"map": null,
|
||||
"mapp": null,
|
||||
"pmap": {
|
||||
"17": {
|
||||
"tag": "tag17"
|
||||
},
|
||||
"18": {
|
||||
"tag": "tag18"
|
||||
}
|
||||
},
|
||||
"pmapp": {
|
||||
"19": {
|
||||
"tag": "tag19"
|
||||
},
|
||||
"20": null
|
||||
},
|
||||
"emptymap": null,
|
||||
"nilmap": null,
|
||||
"slice": [],
|
||||
"slicep": [],
|
||||
"pslice": [
|
||||
{
|
||||
"tag": "tag20"
|
||||
},
|
||||
{
|
||||
"tag": "tag21"
|
||||
}
|
||||
],
|
||||
"pslicep": [
|
||||
{
|
||||
"tag": "tag22"
|
||||
},
|
||||
null,
|
||||
{
|
||||
"tag": "tag23"
|
||||
}
|
||||
],
|
||||
"emptyslice": [],
|
||||
"nilslice": [],
|
||||
"stringslice": [],
|
||||
"byteslice": [],
|
||||
"small": {
|
||||
"tag": ""
|
||||
},
|
||||
"psmall": null,
|
||||
"ppsmall": {
|
||||
"tag": "tag31"
|
||||
},
|
||||
"interface": null,
|
||||
"pinterface": 5.2
|
||||
}`
|
||||
|
||||
var pallValueCompact = strings.Map(noSpace, pallValueIndent)
|
||||
|
282
src/pkg/json/encode.go
Normal file
282
src/pkg/json/encode.go
Normal file
@ -0,0 +1,282 @@
|
||||
// Copyright 2010 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
|
||||
|
||||
import (
|
||||
"os"
|
||||
"bytes"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Marshal returns the JSON encoding of v.
|
||||
//
|
||||
// Marshal traverses the value v recursively.
|
||||
// If an encountered value implements the Marshaler interface,
|
||||
// Marshal calls its MarshalJSON method to produce JSON.
|
||||
//
|
||||
// Otherwise, Marshal uses the following type-dependent default encodings:
|
||||
//
|
||||
// Boolean values encode as JSON booleans.
|
||||
//
|
||||
// Floating point and integer values encode as JSON numbers.
|
||||
//
|
||||
// String values encode as JSON strings, with each invalid UTF-8 sequence
|
||||
// replaced by the encoding of the Unicode replacement character U+FFFD.
|
||||
//
|
||||
// Array and slice values encode as JSON arrays.
|
||||
//
|
||||
// Struct values encode as JSON objects. Each struct field becomes
|
||||
// a member of the object. By default the object's key name is the
|
||||
// struct field name converted to lower case. If the struct field
|
||||
// has a tag, that tag will be used as the name instead.
|
||||
//
|
||||
// Map values encode as JSON objects.
|
||||
// The map's key type must be string; the object keys are used directly
|
||||
// as map keys.
|
||||
//
|
||||
// Pointer values encode as the value pointed at.
|
||||
// A nil pointer encodes as the null JSON object.
|
||||
//
|
||||
// Interface values encode as the value contained in the interface.
|
||||
// A nil interface value encodes as the null JSON object.
|
||||
//
|
||||
// Channel, complex, and function values cannot be encoded in JSON.
|
||||
// Attempting to encode such a value causes Marshal to return
|
||||
// an InvalidTypeError.
|
||||
//
|
||||
// JSON cannot represent cyclic data structures and Marshal does not
|
||||
// handle them. Passing cyclic structures to Marshal will result in
|
||||
// an infinite recursion.
|
||||
//
|
||||
func Marshal(v interface{}) ([]byte, os.Error) {
|
||||
e := &encodeState{}
|
||||
err := e.marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
|
||||
b, err := Marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = Indent(&buf, b, prefix, indent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Marshaler is the interface implemented by objects that
|
||||
// can marshal themselves into valid JSON.
|
||||
type Marshaler interface {
|
||||
MarshalJSON() ([]byte, os.Error)
|
||||
}
|
||||
|
||||
type UnsupportedTypeError struct {
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
func (e *UnsupportedTypeError) String() string {
|
||||
return "json: unsupported type: " + e.Type.String()
|
||||
}
|
||||
|
||||
type MarshalerError struct {
|
||||
Type reflect.Type
|
||||
Error os.Error
|
||||
}
|
||||
|
||||
func (e *MarshalerError) String() string {
|
||||
return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
|
||||
}
|
||||
|
||||
type interfaceOrPtrValue interface {
|
||||
IsNil() bool
|
||||
Elem() reflect.Value
|
||||
}
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
// An encodeState encodes JSON into a bytes.Buffer.
|
||||
type encodeState struct {
|
||||
bytes.Buffer // accumulated output
|
||||
}
|
||||
|
||||
func (e *encodeState) marshal(v interface{}) (err os.Error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
err = r.(os.Error)
|
||||
}
|
||||
}()
|
||||
e.reflectValue(reflect.NewValue(v))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *encodeState) error(err os.Error) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
func (e *encodeState) reflectValue(v reflect.Value) {
|
||||
if v == nil {
|
||||
e.WriteString("null")
|
||||
return
|
||||
}
|
||||
|
||||
if j, ok := v.Interface().(Marshaler); ok {
|
||||
b, err := j.MarshalJSON()
|
||||
if err == nil {
|
||||
// copy JSON into buffer, checking validity.
|
||||
err = Compact(&e.Buffer, b)
|
||||
}
|
||||
if err != nil {
|
||||
e.error(&MarshalerError{v.Type(), err})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch v := v.(type) {
|
||||
case *reflect.BoolValue:
|
||||
x := v.Get()
|
||||
if x {
|
||||
e.WriteString("true")
|
||||
} else {
|
||||
e.WriteString("false")
|
||||
}
|
||||
|
||||
case *reflect.IntValue:
|
||||
e.WriteString(strconv.Itoa(v.Get()))
|
||||
case *reflect.Int8Value:
|
||||
e.WriteString(strconv.Itoa(int(v.Get())))
|
||||
case *reflect.Int16Value:
|
||||
e.WriteString(strconv.Itoa(int(v.Get())))
|
||||
case *reflect.Int32Value:
|
||||
e.WriteString(strconv.Itoa(int(v.Get())))
|
||||
case *reflect.Int64Value:
|
||||
e.WriteString(strconv.Itoa64(v.Get()))
|
||||
|
||||
case *reflect.UintValue:
|
||||
e.WriteString(strconv.Uitoa(v.Get()))
|
||||
case *reflect.Uint8Value:
|
||||
e.WriteString(strconv.Uitoa(uint(v.Get())))
|
||||
case *reflect.Uint16Value:
|
||||
e.WriteString(strconv.Uitoa(uint(v.Get())))
|
||||
case *reflect.Uint32Value:
|
||||
e.WriteString(strconv.Uitoa(uint(v.Get())))
|
||||
case *reflect.Uint64Value:
|
||||
e.WriteString(strconv.Uitoa64(v.Get()))
|
||||
case *reflect.UintptrValue:
|
||||
e.WriteString(strconv.Uitoa64(uint64(v.Get())))
|
||||
|
||||
case *reflect.FloatValue:
|
||||
e.WriteString(strconv.Ftoa(v.Get(), 'g', -1))
|
||||
case *reflect.Float32Value:
|
||||
e.WriteString(strconv.Ftoa32(v.Get(), 'g', -1))
|
||||
case *reflect.Float64Value:
|
||||
e.WriteString(strconv.Ftoa64(v.Get(), 'g', -1))
|
||||
|
||||
case *reflect.StringValue:
|
||||
e.string(v.Get())
|
||||
|
||||
case *reflect.StructValue:
|
||||
e.WriteByte('{')
|
||||
t := v.Type().(*reflect.StructType)
|
||||
n := v.NumField()
|
||||
for i := 0; i < n; i++ {
|
||||
if i > 0 {
|
||||
e.WriteByte(',')
|
||||
}
|
||||
f := t.Field(i)
|
||||
if f.Tag != "" {
|
||||
e.string(f.Tag)
|
||||
} else {
|
||||
e.string(strings.ToLower(f.Name))
|
||||
}
|
||||
e.WriteByte(':')
|
||||
e.reflectValue(v.Field(i))
|
||||
}
|
||||
e.WriteByte('}')
|
||||
|
||||
case *reflect.MapValue:
|
||||
if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok {
|
||||
e.error(&UnsupportedTypeError{v.Type()})
|
||||
}
|
||||
if v.IsNil() {
|
||||
e.WriteString("null")
|
||||
break
|
||||
}
|
||||
e.WriteByte('{')
|
||||
var sv stringValues = v.Keys()
|
||||
sort.Sort(sv)
|
||||
for i, k := range sv {
|
||||
if i > 0 {
|
||||
e.WriteByte(',')
|
||||
}
|
||||
e.string(k.(*reflect.StringValue).Get())
|
||||
e.WriteByte(':')
|
||||
e.reflectValue(v.Elem(k))
|
||||
}
|
||||
e.WriteByte('}')
|
||||
|
||||
case reflect.ArrayOrSliceValue:
|
||||
e.WriteByte('[')
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
if i > 0 {
|
||||
e.WriteByte(',')
|
||||
}
|
||||
e.reflectValue(v.Elem(i))
|
||||
}
|
||||
e.WriteByte(']')
|
||||
|
||||
case interfaceOrPtrValue:
|
||||
if v.IsNil() {
|
||||
e.WriteString("null")
|
||||
return
|
||||
}
|
||||
e.reflectValue(v.Elem())
|
||||
|
||||
default:
|
||||
e.error(&UnsupportedTypeError{v.Type()})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
|
||||
// It implements the methods to sort by string.
|
||||
type stringValues []reflect.Value
|
||||
|
||||
func (sv stringValues) Len() int { return len(sv) }
|
||||
func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
|
||||
func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
|
||||
func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue).Get() }
|
||||
|
||||
func (e *encodeState) string(s string) {
|
||||
e.WriteByte('"')
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case c < 0x20:
|
||||
e.WriteString(`\u00`)
|
||||
e.WriteByte(hex[c>>4])
|
||||
e.WriteByte(hex[c&0xF])
|
||||
case c == '\\' || c == '"':
|
||||
e.WriteByte('\\')
|
||||
fallthrough
|
||||
default:
|
||||
e.WriteRune(c)
|
||||
}
|
||||
}
|
||||
e.WriteByte('"')
|
||||
}
|
@ -181,6 +181,10 @@ func (s *scanner) popParseState() {
|
||||
}
|
||||
}
|
||||
|
||||
func isSpace(c int) bool {
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
|
||||
}
|
||||
|
||||
// NOTE(rsc): The various instances of
|
||||
//
|
||||
// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||
@ -590,7 +594,7 @@ func stateError(s *scanner, c int) int {
|
||||
// error records an error and switches to the error state.
|
||||
func (s *scanner) error(c int, context string) int {
|
||||
s.step = stateError
|
||||
s.err = SyntaxError("invalid character '" + quoteChar(c) + "' " + context)
|
||||
s.err = SyntaxError("invalid character " + quoteChar(c) + " " + context)
|
||||
return scanError
|
||||
}
|
||||
|
||||
|
@ -175,6 +175,7 @@ func diff(t *testing.T, a, b []byte) {
|
||||
j = 0
|
||||
}
|
||||
t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,9 +192,11 @@ func trim(b []byte) []byte {
|
||||
var jsonBig []byte
|
||||
|
||||
func init() {
|
||||
var buf bytes.Buffer
|
||||
Marshal(&buf, genValue(100000))
|
||||
jsonBig = buf.Bytes()
|
||||
b, err := Marshal(genValue(10000))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
jsonBig = b
|
||||
}
|
||||
|
||||
func genValue(n int) interface{} {
|
||||
|
@ -1,481 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Marshalling and unmarshalling of
|
||||
// JSON data into Go structs using reflection.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type structBuilder struct {
|
||||
val reflect.Value
|
||||
|
||||
// if map_ != nil, write val to map_[key] on each change
|
||||
map_ *reflect.MapValue
|
||||
key reflect.Value
|
||||
}
|
||||
|
||||
var nobuilder *structBuilder
|
||||
|
||||
func isfloat(v reflect.Value) bool {
|
||||
switch v.(type) {
|
||||
case *reflect.FloatValue, *reflect.Float32Value, *reflect.Float64Value:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setfloat(v reflect.Value, f float64) {
|
||||
switch v := v.(type) {
|
||||
case *reflect.FloatValue:
|
||||
v.Set(float(f))
|
||||
case *reflect.Float32Value:
|
||||
v.Set(float32(f))
|
||||
case *reflect.Float64Value:
|
||||
v.Set(float64(f))
|
||||
}
|
||||
}
|
||||
|
||||
func setint(v reflect.Value, i int64) {
|
||||
switch v := v.(type) {
|
||||
case *reflect.IntValue:
|
||||
v.Set(int(i))
|
||||
case *reflect.Int8Value:
|
||||
v.Set(int8(i))
|
||||
case *reflect.Int16Value:
|
||||
v.Set(int16(i))
|
||||
case *reflect.Int32Value:
|
||||
v.Set(int32(i))
|
||||
case *reflect.Int64Value:
|
||||
v.Set(int64(i))
|
||||
case *reflect.UintValue:
|
||||
v.Set(uint(i))
|
||||
case *reflect.Uint8Value:
|
||||
v.Set(uint8(i))
|
||||
case *reflect.Uint16Value:
|
||||
v.Set(uint16(i))
|
||||
case *reflect.Uint32Value:
|
||||
v.Set(uint32(i))
|
||||
case *reflect.Uint64Value:
|
||||
v.Set(uint64(i))
|
||||
}
|
||||
}
|
||||
|
||||
// If updating b.val is not enough to update the original,
|
||||
// copy a changed b.val out to the original.
|
||||
func (b *structBuilder) Flush() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if b.map_ != nil {
|
||||
b.map_.SetElem(b.key, b.val)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Int64(i int64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, float64(i))
|
||||
} else {
|
||||
setint(v, i)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Uint64(i uint64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, float64(i))
|
||||
} else {
|
||||
setint(v, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Float64(f float64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, f)
|
||||
} else {
|
||||
setint(v, int64(f))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Null() {}
|
||||
|
||||
func (b *structBuilder) String(s string) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v, ok := b.val.(*reflect.StringValue); ok {
|
||||
v.Set(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Bool(tf bool) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v, ok := b.val.(*reflect.BoolValue); ok {
|
||||
v.Set(tf)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Array() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v, ok := b.val.(*reflect.SliceValue); ok {
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Elem(i int) Builder {
|
||||
if b == nil || i < 0 {
|
||||
return nobuilder
|
||||
}
|
||||
switch v := b.val.(type) {
|
||||
case *reflect.ArrayValue:
|
||||
if i < v.Len() {
|
||||
return &structBuilder{val: v.Elem(i)}
|
||||
}
|
||||
case *reflect.SliceValue:
|
||||
if i >= v.Cap() {
|
||||
n := v.Cap()
|
||||
if n < 8 {
|
||||
n = 8
|
||||
}
|
||||
for n <= i {
|
||||
n *= 2
|
||||
}
|
||||
nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n)
|
||||
reflect.ArrayCopy(nv, v)
|
||||
v.Set(nv)
|
||||
}
|
||||
if v.Len() <= i && i < v.Cap() {
|
||||
v.SetLen(i + 1)
|
||||
}
|
||||
if i < v.Len() {
|
||||
return &structBuilder{val: v.Elem(i)}
|
||||
}
|
||||
}
|
||||
return nobuilder
|
||||
}
|
||||
|
||||
func (b *structBuilder) Map() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v, ok := b.val.(*reflect.PtrValue); ok && v.IsNil() {
|
||||
if v.IsNil() {
|
||||
v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
|
||||
b.Flush()
|
||||
}
|
||||
b.map_ = nil
|
||||
b.val = v.Elem()
|
||||
}
|
||||
if v, ok := b.val.(*reflect.MapValue); ok && v.IsNil() {
|
||||
v.Set(reflect.MakeMap(v.Type().(*reflect.MapType)))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Key(k string) Builder {
|
||||
if b == nil {
|
||||
return nobuilder
|
||||
}
|
||||
switch v := reflect.Indirect(b.val).(type) {
|
||||
case *reflect.StructValue:
|
||||
t := v.Type().(*reflect.StructType)
|
||||
// Case-insensitive field lookup.
|
||||
k = strings.ToLower(k)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
if strings.ToLower(t.Field(i).Name) == k {
|
||||
return &structBuilder{val: v.Field(i)}
|
||||
}
|
||||
}
|
||||
case *reflect.MapValue:
|
||||
t := v.Type().(*reflect.MapType)
|
||||
if t.Key() != reflect.Typeof(k) {
|
||||
break
|
||||
}
|
||||
key := reflect.NewValue(k)
|
||||
elem := v.Elem(key)
|
||||
if elem == nil {
|
||||
v.SetElem(key, reflect.MakeZero(t.Elem()))
|
||||
elem = v.Elem(key)
|
||||
}
|
||||
return &structBuilder{val: elem, map_: v, key: key}
|
||||
}
|
||||
return nobuilder
|
||||
}
|
||||
|
||||
// Unmarshal parses the JSON syntax string s and fills in
|
||||
// an arbitrary struct or slice pointed at by val.
|
||||
// It uses the reflect package to assign to fields
|
||||
// and arrays embedded in val. Well-formed data that does not fit
|
||||
// into the struct is discarded.
|
||||
//
|
||||
// For example, given these definitions:
|
||||
//
|
||||
// type Email struct {
|
||||
// Where string
|
||||
// Addr string
|
||||
// }
|
||||
//
|
||||
// type Result struct {
|
||||
// Name string
|
||||
// Phone string
|
||||
// Email []Email
|
||||
// }
|
||||
//
|
||||
// var r = Result{ "name", "phone", nil }
|
||||
//
|
||||
// unmarshalling the JSON syntax string
|
||||
//
|
||||
// {
|
||||
// "email": [
|
||||
// {
|
||||
// "where": "home",
|
||||
// "addr": "gre@example.com"
|
||||
// },
|
||||
// {
|
||||
// "where": "work",
|
||||
// "addr": "gre@work.com"
|
||||
// }
|
||||
// ],
|
||||
// "name": "Grace R. Emlin",
|
||||
// "address": "123 Main Street"
|
||||
// }
|
||||
//
|
||||
// via Unmarshal(s, &r) is equivalent to assigning
|
||||
//
|
||||
// r = Result{
|
||||
// "Grace R. Emlin", // name
|
||||
// "phone", // no phone given
|
||||
// []Email{
|
||||
// Email{ "home", "gre@example.com" },
|
||||
// Email{ "work", "gre@work.com" },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// Note that the field r.Phone has not been modified and
|
||||
// that the JSON field "address" was discarded.
|
||||
//
|
||||
// Because Unmarshal uses the reflect package, it can only
|
||||
// assign to upper case fields. Unmarshal uses a case-insensitive
|
||||
// comparison to match JSON field names to struct field names.
|
||||
//
|
||||
// To unmarshal a top-level JSON array, pass in a pointer to an empty
|
||||
// slice of the correct type.
|
||||
//
|
||||
// On success, Unmarshal returns with ok set to true.
|
||||
// On a syntax error, it returns with ok set to false and errtok
|
||||
// set to the offending token.
|
||||
func Unmarshal(s string, val interface{}) (ok bool, errtok string) {
|
||||
v := reflect.NewValue(val)
|
||||
var b *structBuilder
|
||||
|
||||
// If val is a pointer to a slice, we append to the slice.
|
||||
if ptr, ok := v.(*reflect.PtrValue); ok {
|
||||
if slice, ok := ptr.Elem().(*reflect.SliceValue); ok {
|
||||
b = &structBuilder{val: slice}
|
||||
}
|
||||
}
|
||||
|
||||
if b == nil {
|
||||
b = &structBuilder{val: v}
|
||||
}
|
||||
|
||||
ok, _, errtok = Parse(s, b)
|
||||
if !ok {
|
||||
return false, errtok
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
type MarshalError struct {
|
||||
T reflect.Type
|
||||
}
|
||||
|
||||
func (e *MarshalError) String() string {
|
||||
return "json cannot encode value of type " + e.T.String()
|
||||
}
|
||||
|
||||
type writeState struct {
|
||||
bytes.Buffer
|
||||
indent string
|
||||
newlines bool
|
||||
depth int
|
||||
}
|
||||
|
||||
func (s *writeState) descend(bra byte) {
|
||||
s.depth++
|
||||
s.WriteByte(bra)
|
||||
}
|
||||
|
||||
func (s *writeState) ascend(ket byte) {
|
||||
s.depth--
|
||||
s.writeIndent()
|
||||
s.WriteByte(ket)
|
||||
}
|
||||
|
||||
func (s *writeState) writeIndent() {
|
||||
if s.newlines {
|
||||
s.WriteByte('\n')
|
||||
}
|
||||
for i := 0; i < s.depth; i++ {
|
||||
s.WriteString(s.indent)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *writeState) writeArrayOrSlice(val reflect.ArrayOrSliceValue) {
|
||||
s.descend('[')
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
s.writeIndent()
|
||||
s.writeValue(val.Elem(i))
|
||||
if i < val.Len()-1 {
|
||||
s.WriteByte(',')
|
||||
}
|
||||
}
|
||||
|
||||
s.ascend(']')
|
||||
}
|
||||
|
||||
func (s *writeState) writeMap(val *reflect.MapValue) {
|
||||
key := val.Type().(*reflect.MapType).Key()
|
||||
if _, ok := key.(*reflect.StringType); !ok {
|
||||
panic(&MarshalError{val.Type()})
|
||||
}
|
||||
|
||||
s.descend('{')
|
||||
|
||||
keys := val.Keys()
|
||||
for i := 0; i < len(keys); i++ {
|
||||
s.writeIndent()
|
||||
fmt.Fprintf(s, "%s:", Quote(keys[i].(*reflect.StringValue).Get()))
|
||||
s.writeValue(val.Elem(keys[i]))
|
||||
if i < len(keys)-1 {
|
||||
s.WriteByte(',')
|
||||
}
|
||||
}
|
||||
|
||||
s.ascend('}')
|
||||
}
|
||||
|
||||
func (s *writeState) writeStruct(val *reflect.StructValue) {
|
||||
s.descend('{')
|
||||
|
||||
typ := val.Type().(*reflect.StructType)
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
s.writeIndent()
|
||||
fmt.Fprintf(s, "%s:", Quote(typ.Field(i).Name))
|
||||
s.writeValue(val.Field(i))
|
||||
if i < val.NumField()-1 {
|
||||
s.WriteByte(',')
|
||||
}
|
||||
}
|
||||
|
||||
s.ascend('}')
|
||||
}
|
||||
|
||||
func (s *writeState) writeValue(val reflect.Value) {
|
||||
if val == nil {
|
||||
fmt.Fprint(s, "null")
|
||||
return
|
||||
}
|
||||
|
||||
switch v := val.(type) {
|
||||
case *reflect.StringValue:
|
||||
fmt.Fprint(s, Quote(v.Get()))
|
||||
case *reflect.ArrayValue:
|
||||
s.writeArrayOrSlice(v)
|
||||
case *reflect.SliceValue:
|
||||
s.writeArrayOrSlice(v)
|
||||
case *reflect.MapValue:
|
||||
s.writeMap(v)
|
||||
case *reflect.StructValue:
|
||||
s.writeStruct(v)
|
||||
case *reflect.ChanValue,
|
||||
*reflect.UnsafePointerValue,
|
||||
*reflect.FuncValue:
|
||||
panic(&MarshalError{val.Type()})
|
||||
case *reflect.InterfaceValue:
|
||||
if v.IsNil() {
|
||||
fmt.Fprint(s, "null")
|
||||
} else {
|
||||
s.writeValue(v.Elem())
|
||||
}
|
||||
case *reflect.PtrValue:
|
||||
if v.IsNil() {
|
||||
fmt.Fprint(s, "null")
|
||||
} else {
|
||||
s.writeValue(v.Elem())
|
||||
}
|
||||
case *reflect.UintptrValue:
|
||||
fmt.Fprintf(s, "%d", v.Get())
|
||||
case *reflect.Uint64Value:
|
||||
fmt.Fprintf(s, "%d", v.Get())
|
||||
case *reflect.Uint32Value:
|
||||
fmt.Fprintf(s, "%d", v.Get())
|
||||
case *reflect.Uint16Value:
|
||||
fmt.Fprintf(s, "%d", v.Get())
|
||||
case *reflect.Uint8Value:
|
||||
fmt.Fprintf(s, "%d", v.Get())
|
||||
default:
|
||||
value := val.(reflect.Value)
|
||||
fmt.Fprintf(s, "%#v", value.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *writeState) marshal(w io.Writer, val interface{}) (err os.Error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = e.(*MarshalError)
|
||||
}
|
||||
}()
|
||||
s.writeValue(reflect.NewValue(val))
|
||||
if s.newlines {
|
||||
s.WriteByte('\n')
|
||||
}
|
||||
_, err = s.WriteTo(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Marshal writes the JSON encoding of val to w.
|
||||
//
|
||||
// Due to limitations in JSON, val cannot include cyclic data
|
||||
// structures, channels, functions, or maps.
|
||||
func Marshal(w io.Writer, val interface{}) os.Error {
|
||||
s := &writeState{indent: "", newlines: false, depth: 0}
|
||||
return s.marshal(w, val)
|
||||
}
|
||||
|
||||
// MarshalIndent writes the JSON encoding of val to w,
|
||||
// indenting nested values using the indent string.
|
||||
//
|
||||
// Due to limitations in JSON, val cannot include cyclic data
|
||||
// structures, channels, functions, or maps.
|
||||
func MarshalIndent(w io.Writer, val interface{}, indent string) os.Error {
|
||||
s := &writeState{indent: indent, newlines: true, depth: 0}
|
||||
return s.marshal(w, val)
|
||||
}
|
@ -1,375 +0,0 @@
|
||||
// Copyright 2009 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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type myStruct struct {
|
||||
T bool
|
||||
F bool
|
||||
S string
|
||||
I8 int8
|
||||
I16 int16
|
||||
I32 int32
|
||||
I64 int64
|
||||
U8 uint8
|
||||
U16 uint16
|
||||
U32 uint32
|
||||
U64 uint64
|
||||
I int
|
||||
U uint
|
||||
Fl float
|
||||
Fl32 float32
|
||||
Fl64 float64
|
||||
A []string
|
||||
My *myStruct
|
||||
Map map[string][]int
|
||||
MapStruct map[string]myStruct
|
||||
MapPtrStruct map[string]*myStruct
|
||||
}
|
||||
|
||||
const encoded = `{"t":true,"f":false,"s":"abc","i8":1,"i16":2,"i32":3,"i64":4,` +
|
||||
` "u8":5,"u16":6,"u32":7,"u64":8,` +
|
||||
` "i":-9,"u":10,"bogusfield":"should be ignored",` +
|
||||
` "fl":11.5,"fl32":12.25,"fl64":13.75,` +
|
||||
` "a":["x","y","z"],"my":{"s":"subguy"},` +
|
||||
`"map":{"k1":[1,2,3],"k2":[],"k3":[3,4]},` +
|
||||
`"mapstruct":{"m1":{"u8":8}},` +
|
||||
`"mapptrstruct":{"m1":{"u8":8}}}`
|
||||
|
||||
var decodedMap = map[string][]int{
|
||||
"k1": []int{1, 2, 3},
|
||||
"k2": []int{},
|
||||
"k3": []int{3, 4},
|
||||
}
|
||||
|
||||
var decodedMapStruct = map[string]myStruct{
|
||||
"m1": myStruct{U8: 8},
|
||||
}
|
||||
|
||||
var decodedMapPtrStruct = map[string]*myStruct{
|
||||
"m1": &myStruct{U8: 8},
|
||||
}
|
||||
|
||||
func check(t *testing.T, ok bool, name string, v interface{}) {
|
||||
if !ok {
|
||||
t.Errorf("%s = %v (BAD)", name, v)
|
||||
} else {
|
||||
t.Logf("%s = %v (good)", name, v)
|
||||
}
|
||||
}
|
||||
|
||||
const whiteSpaceEncoded = " \t{\n\"s\"\r:\"string\"\v}"
|
||||
|
||||
func TestUnmarshalWhitespace(t *testing.T) {
|
||||
var m myStruct
|
||||
ok, errtok := Unmarshal(whiteSpaceEncoded, &m)
|
||||
if !ok {
|
||||
t.Fatalf("Unmarshal failed near %s", errtok)
|
||||
}
|
||||
check(t, m.S == "string", "string", m.S)
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
var m myStruct
|
||||
m.F = true
|
||||
ok, errtok := Unmarshal(encoded, &m)
|
||||
if !ok {
|
||||
t.Fatalf("Unmarshal failed near %s", errtok)
|
||||
}
|
||||
check(t, m.T == true, "t", m.T)
|
||||
check(t, m.F == false, "f", m.F)
|
||||
check(t, m.S == "abc", "s", m.S)
|
||||
check(t, m.I8 == 1, "i8", m.I8)
|
||||
check(t, m.I16 == 2, "i16", m.I16)
|
||||
check(t, m.I32 == 3, "i32", m.I32)
|
||||
check(t, m.I64 == 4, "i64", m.I64)
|
||||
check(t, m.U8 == 5, "u8", m.U8)
|
||||
check(t, m.U16 == 6, "u16", m.U16)
|
||||
check(t, m.U32 == 7, "u32", m.U32)
|
||||
check(t, m.U64 == 8, "u64", m.U64)
|
||||
check(t, m.I == -9, "i", m.I)
|
||||
check(t, m.U == 10, "u", m.U)
|
||||
check(t, m.Fl == 11.5, "fl", m.Fl)
|
||||
check(t, m.Fl32 == 12.25, "fl32", m.Fl32)
|
||||
check(t, m.Fl64 == 13.75, "fl64", m.Fl64)
|
||||
check(t, m.A != nil, "a", m.A)
|
||||
if m.A != nil {
|
||||
check(t, m.A[0] == "x", "a[0]", m.A[0])
|
||||
check(t, m.A[1] == "y", "a[1]", m.A[1])
|
||||
check(t, m.A[2] == "z", "a[2]", m.A[2])
|
||||
}
|
||||
check(t, m.My != nil, "my", m.My)
|
||||
if m.My != nil {
|
||||
check(t, m.My.S == "subguy", "my.s", m.My.S)
|
||||
}
|
||||
check(t, reflect.DeepEqual(m.Map, decodedMap), "map", m.Map)
|
||||
check(t, reflect.DeepEqual(m.MapStruct, decodedMapStruct), "mapstruct", m.MapStruct)
|
||||
check(t, reflect.DeepEqual(m.MapPtrStruct, decodedMapPtrStruct), "mapptrstruct", m.MapPtrStruct)
|
||||
}
|
||||
|
||||
type Issue147Text struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
type Issue147 struct {
|
||||
Test []Issue147Text
|
||||
}
|
||||
|
||||
const issue147Input = `{"test": [{"text":"0"},{"text":"1"},{"text":"2"},
|
||||
{"text":"3"},{"text":"4"},{"text":"5"},
|
||||
{"text":"6"},{"text":"7"},{"text":"8"},
|
||||
{"text":"9"},{"text":"10"},{"text":"11"},
|
||||
{"text":"12"},{"text":"13"},{"text":"14"},
|
||||
{"text":"15"},{"text":"16"},{"text":"17"},
|
||||
{"text":"18"},{"text":"19"},{"text":"20"},
|
||||
{"text":"21"},{"text":"22"},{"text":"23"},
|
||||
{"text":"24"},{"text":"25"},{"text":"26"},
|
||||
{"text":"27"},{"text":"28"},{"text":"29"}]}`
|
||||
|
||||
func TestIssue147(t *testing.T) {
|
||||
var timeline Issue147
|
||||
Unmarshal(issue147Input, &timeline)
|
||||
|
||||
if len(timeline.Test) != 30 {
|
||||
t.Errorf("wrong length: got %d want 30", len(timeline.Test))
|
||||
}
|
||||
|
||||
for i, e := range timeline.Test {
|
||||
if e.Text != strconv.Itoa(i) {
|
||||
t.Errorf("index: %d got: %s want: %d", i, e.Text, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Issue114 struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
const issue114Input = `[{"text" : "0"}, {"text" : "1"}, {"text" : "2"}, {"text" : "3"}]`
|
||||
|
||||
func TestIssue114(t *testing.T) {
|
||||
var items []Issue114
|
||||
Unmarshal(issue114Input, &items)
|
||||
|
||||
if len(items) != 4 {
|
||||
t.Errorf("wrong length: got %d want 4", len(items))
|
||||
}
|
||||
|
||||
for i, e := range items {
|
||||
if e.Text != strconv.Itoa(i) {
|
||||
t.Errorf("index: %d got: %s want: %d", i, e.Text, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type marshalTest struct {
|
||||
val interface{}
|
||||
out string
|
||||
}
|
||||
|
||||
type MTE string
|
||||
|
||||
type OneField struct {
|
||||
a int
|
||||
}
|
||||
|
||||
type ScalarWithString int
|
||||
|
||||
const (
|
||||
AA ScalarWithString = iota
|
||||
BB
|
||||
CC
|
||||
)
|
||||
|
||||
var scalarStrings = []string{"AA", "BB", "CC"}
|
||||
|
||||
func (x ScalarWithString) String() string { return scalarStrings[x] }
|
||||
|
||||
var marshalTests = []marshalTest{
|
||||
// basic string
|
||||
marshalTest{nil, "null"},
|
||||
marshalTest{true, "true"},
|
||||
marshalTest{false, "false"},
|
||||
marshalTest{123, "123"},
|
||||
marshalTest{0.1, "0.1"},
|
||||
marshalTest{1e-10, "1e-10"},
|
||||
marshalTest{"teststring", `"teststring"`},
|
||||
marshalTest{[4]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||
marshalTest{[]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||
marshalTest{[]interface{}{nil}, "[null]"},
|
||||
marshalTest{[][]int{[]int{1, 2}, []int{3, 4}}, "[[1,2],[3,4]]"},
|
||||
marshalTest{map[string]string{"one": "one"}, `{"one":"one"}`},
|
||||
marshalTest{map[string]int{"one": 1}, `{"one":1}`},
|
||||
marshalTest{map[string]interface{}{"null": nil}, `{"null":null}`},
|
||||
marshalTest{struct{}{}, "{}"},
|
||||
marshalTest{struct{ a int }{1}, `{"a":1}`},
|
||||
marshalTest{struct{ a interface{} }{nil}, `{"a":null}`},
|
||||
marshalTest{struct {
|
||||
a int
|
||||
b string
|
||||
}{1, "hello"},
|
||||
`{"a":1,"b":"hello"}`,
|
||||
},
|
||||
marshalTest{map[string][]int{"3": []int{1, 2, 3}}, `{"3":[1,2,3]}`},
|
||||
marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`},
|
||||
marshalTest{map[string]interface{}{"hi": 3}, `{"hi":3}`},
|
||||
marshalTest{&OneField{3}, `{"a":3}`},
|
||||
marshalTest{"\x05\x06", `"\u0005\u0006"`},
|
||||
marshalTest{uintptr(50000), "50000"},
|
||||
marshalTest{uint64(50000), "50000"},
|
||||
marshalTest{uint32(50000), "50000"},
|
||||
marshalTest{uint16(50000), "50000"},
|
||||
marshalTest{uint8(50), "50"},
|
||||
marshalTest{int64(50000), "50000"},
|
||||
marshalTest{int32(50000), "50000"},
|
||||
marshalTest{int16(10000), "10000"},
|
||||
marshalTest{int8(50), "50"},
|
||||
marshalTest{BB, "1"},
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
for _, tt := range marshalTests {
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := Marshal(&buf, tt.val)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal(%T): %s", tt.val, err)
|
||||
}
|
||||
|
||||
s := buf.String()
|
||||
if s != tt.out {
|
||||
t.Errorf("Marshal(%T) = %q, want %q\n", tt.val, s, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type marshalIndentTest struct {
|
||||
val interface{}
|
||||
indent string
|
||||
out string
|
||||
}
|
||||
|
||||
const marshalIndentTest1 = `[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
`
|
||||
const marshalIndentTest2 = `[
|
||||
[
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
3,
|
||||
4
|
||||
]
|
||||
]
|
||||
`
|
||||
const marshalIndentTest3 = `[
|
||||
[
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
3,
|
||||
4
|
||||
]
|
||||
]
|
||||
`
|
||||
const marshalIndentTest4 = `[
|
||||
[
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
3,
|
||||
4
|
||||
]
|
||||
]
|
||||
`
|
||||
const marshalIndentTest5 = `{
|
||||
"a":1,
|
||||
"b":"hello"
|
||||
}
|
||||
`
|
||||
const marshalIndentTest6 = `{
|
||||
"3":[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
var marshalIndentTests = []marshalIndentTest{
|
||||
marshalIndentTest{[]int{1, 2, 3, 4}, " ", marshalIndentTest1},
|
||||
marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, "", marshalIndentTest2},
|
||||
marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, " ", marshalIndentTest3},
|
||||
marshalIndentTest{[][]int{[]int{1, 2}, []int{3, 4}}, " ", marshalIndentTest4},
|
||||
marshalIndentTest{struct {
|
||||
a int
|
||||
b string
|
||||
}{1, "hello"},
|
||||
" ",
|
||||
marshalIndentTest5,
|
||||
},
|
||||
marshalIndentTest{map[string][]int{"3": []int{1, 2, 3}}, " ", marshalIndentTest6},
|
||||
}
|
||||
|
||||
func TestMarshalIndent(t *testing.T) {
|
||||
for _, tt := range marshalIndentTests {
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := MarshalIndent(&buf, tt.val, tt.indent)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalIndent(%v): %s", tt.val, err)
|
||||
}
|
||||
|
||||
s := buf.String()
|
||||
if s != tt.out {
|
||||
t.Errorf("MarshalIndent(%v) = %q, want %q\n", tt.val, s, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type marshalErrorTest struct {
|
||||
val interface{}
|
||||
error string
|
||||
}
|
||||
|
||||
type ChanVal struct {
|
||||
C chan int
|
||||
}
|
||||
|
||||
var marshalErrorTests = []marshalErrorTest{
|
||||
marshalErrorTest{map[chan int]string{make(chan int): "one"}, "json cannot encode value of type map[chan int] string"},
|
||||
marshalErrorTest{make(chan int, 100), "json cannot encode value of type chan int"},
|
||||
marshalErrorTest{new(ChanVal), "json cannot encode value of type chan int"},
|
||||
}
|
||||
|
||||
func TestMarshalError(t *testing.T) {
|
||||
for _, tt := range marshalErrorTests {
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := Marshal(&buf, tt.val)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("Marshal(%T): no error, want error %s", tt.val, tt.error)
|
||||
}
|
||||
|
||||
if err.String() != tt.error {
|
||||
t.Fatalf("Marshal(%T) = error %s, want error %s", tt.val, err, tt.error)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -415,7 +415,7 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
|
||||
s.false = false
|
||||
s.mp = make(map[string]string)
|
||||
s.mp["mapkey"] = "Ahoy!"
|
||||
s.json, _ = json.Decode("{\"maps\":[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]}")
|
||||
json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.json)
|
||||
s.innermap.mp = make(map[string]int)
|
||||
s.innermap.mp["innerkey"] = 55
|
||||
s.stringmap = make(map[string]string)
|
||||
|
Loading…
Reference in New Issue
Block a user