"strings";
)
-type _StructBuilder struct {
+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
+var nobuilder *structBuilder
func isfloat(v reflect.Value) bool {
switch v.(type) {
}
}
-func (b *_StructBuilder) Int64(i int64) {
+// 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;
}
}
}
-func (b *_StructBuilder) Uint64(i uint64) {
+func (b *structBuilder) Uint64(i uint64) {
if b == nil {
return;
}
}
}
-func (b *_StructBuilder) Float64(f float64) {
+func (b *structBuilder) Float64(f float64) {
if b == nil {
return;
}
}
}
-func (b *_StructBuilder) Null() {}
+func (b *structBuilder) Null() {}
-func (b *_StructBuilder) String(s string) {
+func (b *structBuilder) String(s string) {
if b == nil {
return;
}
}
}
-func (b *_StructBuilder) Bool(tf bool) {
+func (b *structBuilder) Bool(tf bool) {
if b == nil {
return;
}
}
}
-func (b *_StructBuilder) Array() {
+func (b *structBuilder) Array() {
if b == nil {
return;
}
}
}
-func (b *_StructBuilder) Elem(i int) Builder {
+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{v.Elem(i)};
+ return &structBuilder{val: v.Elem(i)};
}
case *reflect.SliceValue:
if i > v.Cap() {
v.SetLen(i+1);
}
if i < v.Len() {
- return &_StructBuilder{v.Elem(i)};
+ return &structBuilder{val: v.Elem(i)};
}
}
return nobuilder;
}
-func (b *_StructBuilder) Map() {
+func (b *structBuilder) Map() {
if b == nil {
return;
}
- if v, ok := b.val.(*reflect.PtrValue); ok {
+ 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 {
+func (b *structBuilder) Key(k string) Builder {
if b == nil {
return nobuilder;
}
- if v, ok := reflect.Indirect(b.val).(*reflect.StructValue); ok {
+ 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{v.Field(i)};
+ 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;
}
// 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) {
- b := &_StructBuilder{reflect.NewValue(val)};
+ b := &structBuilder{val: reflect.NewValue(val)};
ok, _, errtok = Parse(s, b);
if !ok {
return false, errtok;
package json
import (
+ "reflect";
"testing";
)
-type _MyStruct struct {
+type myStruct struct {
T bool;
F bool;
S string;
Fl32 float32;
Fl64 float64;
A []string;
- My *_MyStruct;
+ 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,`
+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"}}`
+ ` "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{}) {
+func check(t *testing.T, ok bool, name string, v interface{}) {
if !ok {
t.Errorf("%s = %v (BAD)", name, v);
} else {
}
func TestUnmarshal(t *testing.T) {
- var m _MyStruct;
+ var m myStruct;
m.F = true;
- ok, errtok := Unmarshal(_Encoded, &m);
+ 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);
+ 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.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);
+ 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, 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);
}