diff options
Diffstat (limited to 'src/pkg/json/struct.go')
-rw-r--r-- | src/pkg/json/struct.go | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/pkg/json/struct.go b/src/pkg/json/struct.go new file mode 100644 index 000000000..ac2689557 --- /dev/null +++ b/src/pkg/json/struct.go @@ -0,0 +1,269 @@ +// 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.PtrKind { + pv := v.(reflect.PtrValue); + psubtype := pv.Type().(reflect.PtrType).Sub(); + if pv.Get() == nil && psubtype.Kind() == reflect.ArrayKind { + av := reflect.NewSliceValue(psubtype.(reflect.ArrayType), 0, 8); + pv.SetSub(av); + } + } +} + +func (b *_StructBuilder) Elem(i int) Builder { + if b == nil || i < 0 { + return nobuilder + } + v := b.val; + if v.Kind() == reflect.PtrKind { + // If we have a pointer to an array, allocate or grow + // the array as necessary. Then set v to the array itself. + pv := v.(reflect.PtrValue); + psub := pv.Sub(); + if psub.Kind() == reflect.ArrayKind { + av := psub.(reflect.ArrayValue); + if 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()); + pv.SetSub(av1); + av = av1; + } + } + v = psub; + } + if v.Kind() == reflect.ArrayKind { + // Array was grown above, or is fixed size. + av := v.(reflect.ArrayValue); + 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, "" +} |