| // 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 ( | |
| "json"; | |
| "reflect"; | |
| ) | |
| type _StructBuilder struct { | |
| val reflect.Value | |
| } | |
| var nobuilder *_StructBuilder | |
| func setfloat(v reflect.Value, f float64) { | |
| switch v.Kind() { | |
| case reflect.FloatKind: | |
| v.(reflect.FloatValue).Set(float(f)); | |
| case reflect.Float32Kind: | |
| v.(reflect.Float32Value).Set(float32(f)); | |
| case reflect.Float64Kind: | |
| v.(reflect.Float64Value).Set(float64(f)); | |
| } | |
| } | |
| func setint(v reflect.Value, i int64) { | |
| switch v.Kind() { | |
| case reflect.IntKind: | |
| v.(reflect.IntValue).Set(int(i)); | |
| case reflect.Int8Kind: | |
| v.(reflect.Int8Value).Set(int8(i)); | |
| case reflect.Int16Kind: | |
| v.(reflect.Int16Value).Set(int16(i)); | |
| case reflect.Int32Kind: | |
| v.(reflect.Int32Value).Set(int32(i)); | |
| case reflect.Int64Kind: | |
| v.(reflect.Int64Value).Set(int64(i)); | |
| case reflect.UintKind: | |
| v.(reflect.UintValue).Set(uint(i)); | |
| case reflect.Uint8Kind: | |
| v.(reflect.Uint8Value).Set(uint8(i)); | |
| case reflect.Uint16Kind: | |
| v.(reflect.Uint16Value).Set(uint16(i)); | |
| case reflect.Uint32Kind: | |
| v.(reflect.Uint32Value).Set(uint32(i)); | |
| case reflect.Uint64Kind: | |
| v.(reflect.Uint64Value).Set(uint64(i)); | |
| } | |
| } | |
| func (b *_StructBuilder) Int64(i int64) { | |
| if b == nil { | |
| return | |
| } | |
| v := b.val; | |
| switch v.Kind() { | |
| case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: | |
| setfloat(v, float64(i)); | |
| default: | |
| setint(v, i); | |
| } | |
| } | |
| func (b *_StructBuilder) Uint64(i uint64) { | |
| if b == nil { | |
| return | |
| } | |
| v := b.val; | |
| switch v.Kind() { | |
| case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: | |
| setfloat(v, float64(i)); | |
| default: | |
| setint(v, int64(i)); | |
| } | |
| } | |
| func (b *_StructBuilder) Float64(f float64) { | |
| if b == nil { | |
| return | |
| } | |
| v := b.val; | |
| switch v.Kind() { | |
| case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: | |
| setfloat(v, f); | |
| default: | |
| setint(v, int64(f)); | |
| } | |
| } | |
| func (b *_StructBuilder) Null() { | |
| } | |
| func (b *_StructBuilder) String(s string) { | |
| if b == nil { | |
| return | |
| } | |
| if v := b.val; v.Kind() == reflect.StringKind { | |
| v.(reflect.StringValue).Set(s); | |
| } | |
| } | |
| func (b *_StructBuilder) Bool(tf bool) { | |
| if b == nil { | |
| return | |
| } | |
| if v := b.val; v.Kind() == reflect.BoolKind { | |
| v.(reflect.BoolValue).Set(tf); | |
| } | |
| } | |
| func (b *_StructBuilder) Array() { | |
| if b == nil { | |
| return | |
| } | |
| if v := b.val; v.Kind() == reflect.ArrayKind { | |
| av := v.(reflect.ArrayValue); | |
| if av.IsSlice() && av.IsNil() { | |
| av.Set(reflect.NewSliceValue(av.Type().(reflect.ArrayType), 0, 8)); | |
| } | |
| } | |
| } | |
| func (b *_StructBuilder) Elem(i int) Builder { | |
| if b == nil || i < 0 { | |
| return nobuilder | |
| } | |
| v := b.val; | |
| if v.Kind() != reflect.ArrayKind { | |
| return nobuilder | |
| } | |
| av := v.(reflect.ArrayValue); | |
| if av.IsSlice() && i > av.Cap() { | |
| n := av.Cap(); | |
| if n < 8 { | |
| n = 8 | |
| } | |
| for n <= i { | |
| n *= 2 | |
| } | |
| av1 := reflect.NewSliceValue(av.Type().(reflect.ArrayType), av.Len(), n); | |
| av1.CopyFrom(av, av.Len()); | |
| av.Set(av1); | |
| } | |
| // Array was grown above, or is fixed size. | |
| if av.Len() <= i && i < av.Cap() { | |
| av.SetLen(i+1); | |
| } | |
| if i < av.Len() { | |
| return &_StructBuilder{ av.Elem(i) } | |
| } | |
| return nobuilder | |
| } | |
| func (b *_StructBuilder) Map() { | |
| if b == nil { | |
| return | |
| } | |
| if v := b.val; v.Kind() == reflect.PtrKind { | |
| pv := v.(reflect.PtrValue); | |
| if pv.Get() == nil { | |
| pv.SetSub(reflect.NewZeroValue(pv.Type().(reflect.PtrType).Sub())) | |
| } | |
| } | |
| } | |
| func (b *_StructBuilder) Key(k string) Builder { | |
| if b == nil { | |
| return nobuilder | |
| } | |
| v := b.val; | |
| if v.Kind() == reflect.PtrKind { | |
| v = v.(reflect.PtrValue).Sub(); | |
| } | |
| if v.Kind() == reflect.StructKind { | |
| sv := v.(reflect.StructValue); | |
| t := v.Type().(reflect.StructType); | |
| for i := 0; i < t.Len(); i++ { | |
| name, typ, tag, off := t.Field(i); | |
| if k == name { | |
| return &_StructBuilder{ sv.Field(i) } | |
| } | |
| } | |
| } | |
| return nobuilder | |
| } | |
| // Unmarshal parses the JSON syntax string s and fills in | |
| // an arbitrary struct or array pointed at by val. | |
| // It uses the reflection library to assign to fields | |
| // and arrays embedded in val. Well-formed data that does not fit | |
| // into the struct is discarded. | |
| // | |
| // For example, given the following definitions: | |
| // | |
| // type Email struct { | |
| // where string; | |
| // addr string; | |
| // } | |
| // | |
| // type Result struct { | |
| // name string; | |
| // phone string; | |
| // emails []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. | |
| // | |
| // 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) { | |
| var errindx int; | |
| var val1 interface{}; | |
| b := &_StructBuilder{ reflect.NewValue(val) }; | |
| ok, errindx, errtok = Parse(s, b); | |
| if !ok { | |
| return false, errtok | |
| } | |
| return true, "" | |
| } |