blob: 400bf8b6c974b2de654e517f5eef98a36b14992b [file] [log] [blame]
// 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, ""
}