Browse Source

codec: Support embedded non-struct values, and clean up fast-path for specific container types.

Fix support for embedded pointer and non-struct embedded values

Clean up short circuit, to cover only specific scenarios which have a high chance of happening.

Fix Issue 19 .
Ugorji Nwoke 12 years ago
parent
commit
8eedb40111
4 changed files with 352 additions and 151 deletions
  1. 50 4
      codec/codecs_test.go
  2. 144 82
      codec/decode.go
  3. 80 29
      codec/encode.go
  4. 78 36
      codec/helper.go

+ 50 - 4
codec/codecs_test.go

@@ -574,9 +574,9 @@ func testCodecTableOne(t *testing.T, h Handle) {
 	var oldMapType reflect.Type
 	var oldMapType reflect.Type
 	switch v := h.(type) {
 	switch v := h.(type) {
 	case *MsgpackHandle:
 	case *MsgpackHandle:
-		oldMapType, v.MapType = v.MapType, mapStringIntfTyp
+		oldMapType, v.MapType = v.MapType, mapStrIntfTyp
 	case *BincHandle:
 	case *BincHandle:
-		oldMapType, v.MapType = v.MapType, mapStringIntfTyp
+		oldMapType, v.MapType = v.MapType, mapStrIntfTyp
 	}
 	}
 	//skip time.Time, []interface{} containing time.Time, last map, and newStruc
 	//skip time.Time, []interface{} containing time.Time, last map, and newStruc
 	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
 	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
@@ -696,8 +696,46 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	}
 	}
 }
 }
 
 
+func testCodecEmbeddedPointer(t *testing.T, h Handle) {
+	type Z int
+	type A struct {
+		AnInt int
+	}
+	type B struct {
+		*Z
+		*A
+		MoreInt int
+	}
+	var err error
+	var buf bytes.Buffer
+	var z Z = 4
+	x1 := &B{&z, &A{5}, 6}
+	err = NewEncoder(&buf, h).Encode(x1)
+	if err != nil {
+		logT(t, "Error encoding %v, Err: %v", x1, err)
+		t.FailNow()
+	}
+	// fmt.Printf("buf: len(%v): %x\n", buf.Len(), buf.Bytes())
+	var x2 = new(B)
+	err = NewDecoder(&buf, h).Decode(x2)
+	if err != nil {
+		logT(t, "Error decoding into %v, Err: %v", x2, err)
+		t.FailNow()
+	}
+	if !reflect.DeepEqual(x1, x2) {
+		logT(t, "Error: NOT MATCH: x1: %v, x2: %v", x1, x2)
+		t.FailNow()
+	}
+
+}
+
 func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs time.Duration,
 func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs time.Duration,
 ) (port int) {
 ) (port int) {
+	// rpc needs EOF, which is sent via a panic, and so must be recovered.
+	if !recoverPanicToErr {
+		logT(t, "EXPECTED. set recoverPanicToErr=true, since rpc needs EOF")
+		t.FailNow()
+	}
 	srv := rpc.NewServer()
 	srv := rpc.NewServer()
 	srv.Register(testRpcInt)
 	srv.Register(testRpcInt)
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
@@ -706,7 +744,7 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs ti
 	port = (ln.Addr().(*net.TCPAddr)).Port
 	port = (ln.Addr().(*net.TCPAddr)).Port
 	// var opts *DecoderOptions
 	// var opts *DecoderOptions
 	// opts := testDecOpts
 	// opts := testDecOpts
-	// opts.MapType = mapStringIntfTyp
+	// opts.MapType = mapStrIntfTyp
 	// opts.RawToString = false
 	// opts.RawToString = false
 	serverExitChan := make(chan bool, 1)
 	serverExitChan := make(chan bool, 1)
 	var serverExitFlag uint64 = 0
 	var serverExitFlag uint64 = 0
@@ -825,7 +863,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 			failT(t)
 			failT(t)
 			continue
 			continue
 		}
 		}
-		testMsgpackH.MapType = mapStringIntfTyp
+		testMsgpackH.MapType = mapStrIntfTyp
 
 
 		var v1 interface{}
 		var v1 interface{}
 		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {
 		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {
@@ -921,6 +959,10 @@ func TestMsgpackCodecsMisc(t *testing.T) {
 	testCodecMiscOne(t, testMsgpackH)
 	testCodecMiscOne(t, testMsgpackH)
 }
 }
 
 
+func TestMsgpackCodecsEmbeddedPointer(t *testing.T) {
+	testCodecEmbeddedPointer(t, testMsgpackH)
+}
+
 func TestBincCodecsTable(t *testing.T) {
 func TestBincCodecsTable(t *testing.T) {
 	testCodecTableOne(t, testBincH)
 	testCodecTableOne(t, testBincH)
 }
 }
@@ -929,6 +971,10 @@ func TestBincCodecsMisc(t *testing.T) {
 	testCodecMiscOne(t, testBincH)
 	testCodecMiscOne(t, testBincH)
 }
 }
 
 
+func TestBincCodecsEmbeddedPointer(t *testing.T) {
+	testCodecEmbeddedPointer(t, testBincH)
+}
+
 func TestMsgpackRpcGo(t *testing.T) {
 func TestMsgpackRpcGo(t *testing.T) {
 	doTestRpcOne(t, GoRpc, testMsgpackH, true, 0)
 	doTestRpcOne(t, GoRpc, testMsgpackH, true, 0)
 }
 }

+ 144 - 82
codec/decode.go

@@ -10,9 +10,10 @@ import (
 )
 )
 
 
 // Some tagging information for error messages.
 // Some tagging information for error messages.
-var (
-	msgTagDec  = "codec.decoder"
-	msgBadDesc = "Unrecognized descriptor byte"
+const (
+	msgTagDec             = "codec.decoder"
+	msgBadDesc            = "Unrecognized descriptor byte"
+	msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v"
 )
 )
 
 
 // decReader abstracts the reading source, allowing implementations that can
 // decReader abstracts the reading source, allowing implementations that can
@@ -175,6 +176,7 @@ type decFnInfo struct {
 	dd    decDriver
 	dd    decDriver
 	xfFn  func(reflect.Value, []byte) error
 	xfFn  func(reflect.Value, []byte) error
 	xfTag byte
 	xfTag byte
+	array bool
 }
 }
 
 
 func (f *decFnInfo) builtin(rv reflect.Value) {
 func (f *decFnInfo) builtin(rv reflect.Value) {
@@ -369,7 +371,20 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 				if sfik.i != -1 {
 				if sfik.i != -1 {
 					f.d.decodeValue(rv.Field(int(sfik.i)))
 					f.d.decodeValue(rv.Field(int(sfik.i)))
 				} else {
 				} else {
-					f.d.decodeValue(rv.FieldByIndex(sfik.is))
+					// f.d.decodeValue(rv.FieldByIndex(sfik.is))
+					// nil pointers may be here; so reproduce FieldByIndex logic + enhancements
+					var rv2 = rv
+					for _, x2 := range sfik.is {
+						if rv2.Kind() == reflect.Ptr {
+							if rv2.IsNil() {
+								rv2.Set(reflect.New(rv2.Type().Elem()))
+							}
+							// If a pointer, it must be a pointer to struct (based on typeInfo contract)
+							rv2 = rv2.Elem()
+						}
+						rv2 = rv2.Field(x2)
+					}
+					f.d.decodeValue(rv2)
 				}
 				}
 				// f.d.decodeValue(ti.field(k, rv))
 				// f.d.decodeValue(ti.field(k, rv))
 			} else {
 			} else {
@@ -411,29 +426,26 @@ func (f *decFnInfo) kStruct(rv reflect.Value) {
 }
 }
 
 
 func (f *decFnInfo) kSlice(rv reflect.Value) {
 func (f *decFnInfo) kSlice(rv reflect.Value) {
-	// Be more careful calling Set() here, because a reflect.Value from an array
-	// may have come in here (which may not be settable).
-	// In places where the slice got from an array could be, we should guard with CanSet() calls.
-
 	// A slice can be set from a map or array in stream.
 	// A slice can be set from a map or array in stream.
 
 
-	if shortCircuitReflectToFastPath {
-		if rv.CanAddr() {
-			switch f.ti.rtid {
-			case intfSliceTypId:
-				f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}))
-				return
-			case intSliceTypId:
-				f.d.decSliceInt(rv.Addr().Interface().(*[]int))
-				return
-			case strSliceTypId:
-				f.d.decSliceStr(rv.Addr().Interface().(*[]string))
-				return
-			}
+	if shortCircuitReflectToFastPath && rv.CanAddr() {
+		switch f.ti.rtid {
+		case intfSliceTypId:
+			f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), f.array)
+			return
+		case uint64SliceTypId:
+			f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), f.array)
+			return
+		case int64SliceTypId:
+			f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), f.array)
+			return
+		case strSliceTypId:
+			f.d.decSliceStr(rv.Addr().Interface().(*[]string), f.array)
+			return
 		}
 		}
 	}
 	}
 
 
-	if f.ti.rtid == byteSliceTypId { // rawbytes
+	if f.ti.rtid == uint8SliceTypId { // rawbytes
 		if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 {
 		if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 {
 			rv.SetBytes(bs2)
 			rv.SetBytes(bs2)
 		}
 		}
@@ -442,6 +454,8 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
 
 
 	containerLen, containerLenS := decContLens(f.dd)
 	containerLen, containerLenS := decContLens(f.dd)
 
 
+	// an array can never return a nil slice. so no need to check f.array here.
+
 	if rv.IsNil() {
 	if rv.IsNil() {
 		rv.Set(reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS))
 		rv.Set(reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS))
 	}
 	}
@@ -449,19 +463,15 @@ func (f *decFnInfo) kSlice(rv reflect.Value) {
 		return
 		return
 	}
 	}
 
 
-	// if we need to reset rv but it cannot be set, we should err out.
-	// for example, if slice is got from unaddressable array, CanSet = false
 	if rvcap, rvlen := rv.Len(), rv.Cap(); containerLenS > rvcap {
 	if rvcap, rvlen := rv.Len(), rv.Cap(); containerLenS > rvcap {
-		if rv.CanSet() {
-			rvn := reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS)
-			if rvlen > 0 {
-				reflect.Copy(rvn, rv)
-			}
-			rv.Set(rvn)
-		} else {
-			decErr("Cannot reset slice with less cap: %v than stream contents: %v",
-				rvcap, containerLenS)
+		if f.array { // !rv.CanSet()
+			decErr(msgDecCannotExpandArr, rvcap, containerLenS)
 		}
 		}
+		rvn := reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS)
+		if rvlen > 0 {
+			reflect.Copy(rvn, rv)
+		}
+		rv.Set(rvn)
 	} else if containerLenS > rvlen {
 	} else if containerLenS > rvlen {
 		rv.SetLen(containerLenS)
 		rv.SetLen(containerLenS)
 	}
 	}
@@ -477,29 +487,24 @@ func (f *decFnInfo) kArray(rv reflect.Value) {
 }
 }
 
 
 func (f *decFnInfo) kMap(rv reflect.Value) {
 func (f *decFnInfo) kMap(rv reflect.Value) {
-	// debugf("\t=> kMap: rv: %v", rv)
-	if shortCircuitReflectToFastPath {
-		if rv.CanAddr() {
-			switch f.ti.rtid {
-			case mapStringIntfTypId:
-				f.d.decMapStrIntf(rv.Addr().Interface().(*map[string]interface{}))
-				return
-			case mapIntfIntfTypId:
-				f.d.decMapIntfIntf(rv.Addr().Interface().(*map[interface{}]interface{}))
-				return
-			case mapIntIntfTypId:
-				f.d.decMapIntIntf(rv.Addr().Interface().(*map[int]interface{}))
-				return
-			}
+	if shortCircuitReflectToFastPath && rv.CanAddr() {
+		switch f.ti.rtid {
+		case mapStrIntfTypId:
+			f.d.decMapStrIntf(rv.Addr().Interface().(*map[string]interface{}))
+			return
+		case mapIntfIntfTypId:
+			f.d.decMapIntfIntf(rv.Addr().Interface().(*map[interface{}]interface{}))
+			return
+		case mapInt64IntfTypId:
+			f.d.decMapInt64Intf(rv.Addr().Interface().(*map[int64]interface{}))
+			return
+		case mapUint64IntfTypId:
+			f.d.decMapUint64Intf(rv.Addr().Interface().(*map[uint64]interface{}))
+			return
 		}
 		}
 	}
 	}
 
 
 	containerLen := f.dd.readMapLen()
 	containerLen := f.dd.readMapLen()
-	// defer func() {
-	// 	if rv.CanInterface() {
-	// 		debugf("\t=> kMap: containerLen: %v, rv.I: %v", containerLen, rv.Interface())
-	// 	}
-	// }()
 
 
 	if rv.IsNil() {
 	if rv.IsNil() {
 		rv.Set(reflect.MakeMap(f.ti.rt))
 		rv.Set(reflect.MakeMap(f.ti.rt))
@@ -519,7 +524,7 @@ func (f *decFnInfo) kMap(rv reflect.Value) {
 		// if ktype == intfTyp {
 		// if ktype == intfTyp {
 		if ktypeId == intfTypId {
 		if ktypeId == intfTypId {
 			rvk = rvk.Elem()
 			rvk = rvk.Elem()
-			if rvk.Type() == byteSliceTyp {
+			if rvk.Type() == uint8SliceTyp {
 				rvk = reflect.ValueOf(string(rvk.Bytes()))
 				rvk = reflect.ValueOf(string(rvk.Bytes()))
 			}
 			}
 		}
 		}
@@ -672,17 +677,21 @@ func (d *Decoder) decode(iv interface{}) {
 		*v, _ = d.d.decodeBytes(v2)
 		*v, _ = d.d.decodeBytes(v2)
 
 
 	case *[]interface{}:
 	case *[]interface{}:
-		d.decSliceIntf(v)
-	case *[]int:
-		d.decSliceInt(v)
+		d.decSliceIntf(v, false)
+	case *[]uint64:
+		d.decSliceUint64(v, false)
+	case *[]int64:
+		d.decSliceInt64(v, false)
 	case *[]string:
 	case *[]string:
-		d.decSliceStr(v)
+		d.decSliceStr(v, false)
 	case *map[string]interface{}:
 	case *map[string]interface{}:
 		d.decMapStrIntf(v)
 		d.decMapStrIntf(v)
 	case *map[interface{}]interface{}:
 	case *map[interface{}]interface{}:
 		d.decMapIntfIntf(v)
 		d.decMapIntfIntf(v)
-	case *map[int]interface{}:
-		d.decMapIntIntf(v)
+	case *map[uint64]interface{}:
+		d.decMapUint64Intf(v)
+	case *map[int64]interface{}:
+		d.decMapInt64Intf(v)
 
 
 	case *interface{}:
 	case *interface{}:
 		d.decodeValue(reflect.ValueOf(iv).Elem())
 		d.decodeValue(reflect.ValueOf(iv).Elem())
@@ -698,11 +707,11 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 	d.d.initReadNext()
 	d.d.initReadNext()
 
 
 	if d.d.tryDecodeAsNil() {
 	if d.d.tryDecodeAsNil() {
-		// If value in stream is nil, set the dereferenced value to its "zero" value (if settable).
+		// If value in stream is nil, set the dereferenced value to its "zero" value (if settable)
 		for rv.Kind() == reflect.Ptr {
 		for rv.Kind() == reflect.Ptr {
 			rv = rv.Elem()
 			rv = rv.Elem()
 		}
 		}
-		if rv.CanSet() {
+		if rv.IsValid() { // rv.CanSet() // always settable, except it's invalid
 			rv.Set(reflect.Zero(rv.Type()))
 			rv.Set(reflect.Zero(rv.Type()))
 		}
 		}
 		return
 		return
@@ -797,6 +806,7 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 			case reflect.Slice:
 			case reflect.Slice:
 				fn.f = (*decFnInfo).kSlice
 				fn.f = (*decFnInfo).kSlice
 			case reflect.Array:
 			case reflect.Array:
+				fi.array = true
 				fn.f = (*decFnInfo).kArray
 				fn.f = (*decFnInfo).kArray
 			case reflect.Map:
 			case reflect.Map:
 				fn.f = (*decFnInfo).kMap
 				fn.f = (*decFnInfo).kMap
@@ -821,71 +831,107 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 }
 }
 
 
 func (d *Decoder) chkPtrValue(rv reflect.Value) {
 func (d *Decoder) chkPtrValue(rv reflect.Value) {
-	// We cannot marshal into a non-pointer or a nil pointer
-	// (at least pass a nil interface so we can marshal into it)
-	if rv.Kind() != reflect.Ptr || rv.IsNil() {
-		var rvi interface{} = rv
-		if rv.IsValid() && rv.CanInterface() {
-			rvi = rv.Interface()
-		}
-		decErr("Decode: Expecting valid pointer to decode into. Got: %v, %T, %v",
-			rv.Kind(), rvi, rvi)
+	// We can only decode into a non-nil pointer
+	if rv.Kind() == reflect.Ptr && !rv.IsNil() {
+		return
 	}
 	}
+	if !rv.IsValid() {
+		decErr("Cannot decode into a zero (ie invalid) reflect.Value")
+	}
+	if !rv.CanInterface() {
+		decErr("Cannot decode into a value without an interface: %v", rv)
+	}
+	rvi := rv.Interface()
+	decErr("Cannot decode into non-pointer or nil pointer. Got: %v, %T, %v",
+		rv.Kind(), rvi, rvi)
 }
 }
 
 
 // --------------------------------------------------
 // --------------------------------------------------
 
 
 // short circuit functions for common maps and slices
 // short circuit functions for common maps and slices
 
 
-func (d *Decoder) decSliceIntf(v *[]interface{}) {
+func (d *Decoder) decSliceIntf(v *[]interface{}, doNotReset bool) {
 	_, containerLenS := decContLens(d.d)
 	_, containerLenS := decContLens(d.d)
 	s := *v
 	s := *v
 	if s == nil {
 	if s == nil {
 		s = make([]interface{}, containerLenS, containerLenS)
 		s = make([]interface{}, containerLenS, containerLenS)
 	} else if containerLenS > cap(s) {
 	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
 		s = make([]interface{}, containerLenS, containerLenS)
 		s = make([]interface{}, containerLenS, containerLenS)
 		copy(s, *v)
 		copy(s, *v)
 	} else if containerLenS > len(s) {
 	} else if containerLenS > len(s) {
 		s = s[:containerLenS]
 		s = s[:containerLenS]
 	}
 	}
-	// debugf("\t=> decSliceIntf: containerLenS: %v", containerLenS)
 	for j := 0; j < containerLenS; j++ {
 	for j := 0; j < containerLenS; j++ {
-		// debugf("\t=> decSliceIntf: j: %v", j)
 		d.decode(&s[j])
 		d.decode(&s[j])
 	}
 	}
 	*v = s
 	*v = s
 }
 }
 
 
-func (d *Decoder) decSliceInt(v *[]int) {
+func (d *Decoder) decSliceInt64(v *[]int64, doNotReset bool) {
 	_, containerLenS := decContLens(d.d)
 	_, containerLenS := decContLens(d.d)
 	s := *v
 	s := *v
 	if s == nil {
 	if s == nil {
-		s = make([]int, containerLenS, containerLenS)
+		s = make([]int64, containerLenS, containerLenS)
 	} else if containerLenS > cap(s) {
 	} else if containerLenS > cap(s) {
-		s = make([]int, containerLenS, containerLenS)
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int64, containerLenS, containerLenS)
 		copy(s, *v)
 		copy(s, *v)
 	} else if containerLenS > len(s) {
 	} else if containerLenS > len(s) {
 		s = s[:containerLenS]
 		s = s[:containerLenS]
 	}
 	}
 	for j := 0; j < containerLenS; j++ {
 	for j := 0; j < containerLenS; j++ {
-		d.decode(&s[j])
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeInt(intBitsize)
 	}
 	}
 	*v = s
 	*v = s
 }
 }
 
 
-func (d *Decoder) decSliceStr(v *[]string) {
+func (d *Decoder) decSliceUint64(v *[]uint64, doNotReset bool) {
+	_, containerLenS := decContLens(d.d)
+	s := *v
+	if s == nil {
+		s = make([]uint64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeUint(intBitsize)
+	}
+	*v = s
+}
+
+func (d *Decoder) decSliceStr(v *[]string, doNotReset bool) {
 	_, containerLenS := decContLens(d.d)
 	_, containerLenS := decContLens(d.d)
 	s := *v
 	s := *v
 	if s == nil {
 	if s == nil {
 		s = make([]string, containerLenS, containerLenS)
 		s = make([]string, containerLenS, containerLenS)
 	} else if containerLenS > cap(s) {
 	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
 		s = make([]string, containerLenS, containerLenS)
 		s = make([]string, containerLenS, containerLenS)
 		copy(s, *v)
 		copy(s, *v)
 	} else if containerLenS > len(s) {
 	} else if containerLenS > len(s) {
 		s = s[:containerLenS]
 		s = s[:containerLenS]
 	}
 	}
 	for j := 0; j < containerLenS; j++ {
 	for j := 0; j < containerLenS; j++ {
-		d.decode(&s[j])
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeString()
 	}
 	}
 	*v = s
 	*v = s
 }
 }
@@ -910,16 +956,32 @@ func (d *Decoder) decMapIntfIntf(v *map[interface{}]interface{}) {
 	}
 	}
 }
 }
 
 
-func (d *Decoder) decMapIntIntf(v *map[int]interface{}) {
+func (d *Decoder) decMapInt64Intf(v *map[int64]interface{}) {
+	containerLen := d.d.readMapLen()
+	m := *v
+	if m == nil {
+		m = make(map[int64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		d.d.initReadNext()
+		mk := d.d.decodeInt(intBitsize)
+		mv := m[mk]
+		d.decode(&mv)
+		m[mk] = mv
+	}
+}
+
+func (d *Decoder) decMapUint64Intf(v *map[uint64]interface{}) {
 	containerLen := d.d.readMapLen()
 	containerLen := d.d.readMapLen()
 	m := *v
 	m := *v
 	if m == nil {
 	if m == nil {
-		m = make(map[int]interface{}, containerLen)
+		m = make(map[uint64]interface{}, containerLen)
 		*v = m
 		*v = m
 	}
 	}
 	for j := 0; j < containerLen; j++ {
 	for j := 0; j < containerLen; j++ {
 		d.d.initReadNext()
 		d.d.initReadNext()
-		mk := int(d.d.decodeInt(intBitsize))
+		mk := d.d.decodeUint(intBitsize)
 		mv := m[mk]
 		mv := m[mk]
 		d.decode(&mv)
 		d.decode(&mv)
 		m[mk] = mv
 		m[mk] = mv

+ 80 - 29
codec/encode.go

@@ -367,16 +367,19 @@ func (f *encFnInfo) kSlice(rv reflect.Value) {
 		case intfSliceTypId:
 		case intfSliceTypId:
 			f.e.encSliceIntf(rv.Interface().([]interface{}))
 			f.e.encSliceIntf(rv.Interface().([]interface{}))
 			return
 			return
-		case intSliceTypId:
-			f.e.encSliceInt(rv.Interface().([]int))
-			return
 		case strSliceTypId:
 		case strSliceTypId:
 			f.e.encSliceStr(rv.Interface().([]string))
 			f.e.encSliceStr(rv.Interface().([]string))
 			return
 			return
+		case uint64SliceTypId:
+			f.e.encSliceUint64(rv.Interface().([]uint64))
+			return
+		case int64SliceTypId:
+			f.e.encSliceInt64(rv.Interface().([]int64))
+			return
 		}
 		}
 	}
 	}
 
 
-	if f.ti.rtid == byteSliceTypId {
+	if f.ti.rtid == uint8SliceTypId {
 		f.ee.encodeStringBytes(c_RAW, rv.Bytes())
 		f.ee.encodeStringBytes(c_RAW, rv.Bytes())
 		return
 		return
 	}
 	}
@@ -483,14 +486,20 @@ func (f *encFnInfo) kMap(rv reflect.Value) {
 
 
 	if shortCircuitReflectToFastPath {
 	if shortCircuitReflectToFastPath {
 		switch f.ti.rtid {
 		switch f.ti.rtid {
-		case mapStringIntfTypId:
-			f.e.encMapStrIntf(rv.Interface().(map[string]interface{}))
-			return
 		case mapIntfIntfTypId:
 		case mapIntfIntfTypId:
 			f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{}))
 			f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{}))
 			return
 			return
-		case mapIntIntfTypId:
-			f.e.encMapIntIntf(rv.Interface().(map[int]interface{}))
+		case mapStrIntfTypId:
+			f.e.encMapStrIntf(rv.Interface().(map[string]interface{}))
+			return
+		case mapStrStrTypId:
+			f.e.encMapStrStr(rv.Interface().(map[string]string))
+			return
+		case mapInt64IntfTypId:
+			f.e.encMapInt64Intf(rv.Interface().(map[int64]interface{}))
+			return
+		case mapUint64IntfTypId:
+			f.e.encMapUint64Intf(rv.Interface().(map[uint64]interface{}))
 			return
 			return
 		}
 		}
 	}
 	}
@@ -679,21 +688,28 @@ func (e *Encoder) encode(iv interface{}) {
 		e.e.encodeFloat32(v)
 		e.e.encodeFloat32(v)
 	case float64:
 	case float64:
 		e.e.encodeFloat64(v)
 		e.e.encodeFloat64(v)
-	case []byte:
-		e.e.encodeStringBytes(c_RAW, v)
 
 
 	case []interface{}:
 	case []interface{}:
 		e.encSliceIntf(v)
 		e.encSliceIntf(v)
 	case []string:
 	case []string:
 		e.encSliceStr(v)
 		e.encSliceStr(v)
-	case []int:
-		e.encSliceInt(v)
-	case map[int]interface{}:
-		e.encMapIntIntf(v)
-	case map[string]interface{}:
-		e.encMapStrIntf(v)
+	case []int64:
+		e.encSliceInt64(v)
+	case []uint64:
+		e.encSliceUint64(v)
+	case []uint8:
+		e.e.encodeStringBytes(c_RAW, v)
+
 	case map[interface{}]interface{}:
 	case map[interface{}]interface{}:
 		e.encMapIntfIntf(v)
 		e.encMapIntfIntf(v)
+	case map[string]interface{}:
+		e.encMapStrIntf(v)
+	case map[string]string:
+		e.encMapStrStr(v)
+	case map[int64]interface{}:
+		e.encMapInt64Intf(v)
+	case map[uint64]interface{}:
+		e.encMapUint64Intf(v)
 
 
 	case *string:
 	case *string:
 		e.e.encodeString(c_UTF8, *v)
 		e.e.encodeString(c_UTF8, *v)
@@ -723,21 +739,28 @@ func (e *Encoder) encode(iv interface{}) {
 		e.e.encodeFloat32(*v)
 		e.e.encodeFloat32(*v)
 	case *float64:
 	case *float64:
 		e.e.encodeFloat64(*v)
 		e.e.encodeFloat64(*v)
-	case *[]byte:
-		e.e.encodeStringBytes(c_RAW, *v)
 
 
 	case *[]interface{}:
 	case *[]interface{}:
 		e.encSliceIntf(*v)
 		e.encSliceIntf(*v)
 	case *[]string:
 	case *[]string:
 		e.encSliceStr(*v)
 		e.encSliceStr(*v)
-	case *[]int:
-		e.encSliceInt(*v)
-	case *map[int]interface{}:
-		e.encMapIntIntf(*v)
-	case *map[string]interface{}:
-		e.encMapStrIntf(*v)
+	case *[]int64:
+		e.encSliceInt64(*v)
+	case *[]uint64:
+		e.encSliceUint64(*v)
+	case *[]uint8:
+		e.e.encodeStringBytes(c_RAW, *v)
+
 	case *map[interface{}]interface{}:
 	case *map[interface{}]interface{}:
 		e.encMapIntfIntf(*v)
 		e.encMapIntfIntf(*v)
+	case *map[string]interface{}:
+		e.encMapStrIntf(*v)
+	case *map[string]string:
+		e.encMapStrStr(*v)
+	case *map[int64]interface{}:
+		e.encMapInt64Intf(*v)
+	case *map[uint64]interface{}:
+		e.encMapUint64Intf(*v)
 
 
 	default:
 	default:
 		e.encodeValue(reflect.ValueOf(iv))
 		e.encodeValue(reflect.ValueOf(iv))
@@ -859,10 +882,30 @@ func (e *Encoder) encSliceStr(v []string) {
 	}
 	}
 }
 }
 
 
-func (e *Encoder) encSliceInt(v []int) {
+func (e *Encoder) encSliceInt64(v []int64) {
 	e.e.encodeArrayPreamble(len(v))
 	e.e.encodeArrayPreamble(len(v))
 	for _, v2 := range v {
 	for _, v2 := range v {
-		e.e.encodeInt(int64(v2))
+		e.e.encodeInt(v2)
+	}
+}
+
+func (e *Encoder) encSliceUint64(v []uint64) {
+	e.e.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		e.e.encodeUint(v2)
+	}
+}
+
+func (e *Encoder) encMapStrStr(v map[string]string) {
+	e.e.encodeMapPreamble(len(v))
+	asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	for k2, v2 := range v {
+		if asSymbols {
+			e.e.encodeSymbol(k2)
+		} else {
+			e.e.encodeString(c_UTF8, k2)
+		}
+		e.e.encodeString(c_UTF8, v2)
 	}
 	}
 }
 }
 
 
@@ -879,10 +922,18 @@ func (e *Encoder) encMapStrIntf(v map[string]interface{}) {
 	}
 	}
 }
 }
 
 
-func (e *Encoder) encMapIntIntf(v map[int]interface{}) {
+func (e *Encoder) encMapInt64Intf(v map[int64]interface{}) {
+	e.e.encodeMapPreamble(len(v))
+	for k2, v2 := range v {
+		e.e.encodeInt(k2)
+		e.encode(v2)
+	}
+}
+
+func (e *Encoder) encMapUint64Intf(v map[uint64]interface{}) {
 	e.e.encodeMapPreamble(len(v))
 	e.e.encodeMapPreamble(len(v))
 	for k2, v2 := range v {
 	for k2, v2 := range v {
-		e.e.encodeInt(int64(k2))
+		e.e.encodeUint(uint64(k2))
 		e.encode(v2)
 		e.encode(v2)
 	}
 	}
 }
 }

+ 78 - 36
codec/helper.go

@@ -36,15 +36,14 @@ const (
 
 
 	// For some common container types, we can short-circuit an elaborate
 	// For some common container types, we can short-circuit an elaborate
 	// reflection dance and call encode/decode directly.
 	// reflection dance and call encode/decode directly.
-	// Currently supported for:
-	//    []interface{}
-	//    []int
-	//    []string
-	//
-	//    map[interface{}]interface{}
-	//    map[int]interface{}
-	//    map[string]interface{}
+	// The currently supported types are:
+	//    - slices of strings, or id's (int64,uint64) or interfaces.
+	//    - maps of str->str, str->intf, id(int64,uint64)->intf, intf->intf
 	shortCircuitReflectToFastPath = true
 	shortCircuitReflectToFastPath = true
+
+	// for debugging, set this to false, to catch panic traces.
+	// Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
+	recoverPanicToErr = true
 )
 )
 
 
 type charEncoding uint8
 type charEncoding uint8
@@ -84,37 +83,70 @@ var (
 	cachedTypeInfo      = make(map[uintptr]*typeInfo, 4)
 	cachedTypeInfo      = make(map[uintptr]*typeInfo, 4)
 	cachedTypeInfoMutex sync.RWMutex
 	cachedTypeInfoMutex sync.RWMutex
 
 
-	nilIntfSlice     = []interface{}(nil)
-	intfSliceTyp     = reflect.TypeOf(nilIntfSlice)
-	intfTyp          = intfSliceTyp.Elem()
-	intSliceTyp      = reflect.TypeOf([]int(nil))
-	strSliceTyp      = reflect.TypeOf([]string(nil))
-	byteSliceTyp     = reflect.TypeOf([]byte(nil))
-	mapStringIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
-	mapIntfIntfTyp   = reflect.TypeOf(map[interface{}]interface{}(nil))
+	intfSliceTyp = reflect.TypeOf([]interface{}(nil))
+	intfTyp      = intfSliceTyp.Elem()
+
+	strSliceTyp     = reflect.TypeOf([]string(nil))
+	boolSliceTyp    = reflect.TypeOf([]bool(nil))
+	uintSliceTyp    = reflect.TypeOf([]uint(nil))
+	uint8SliceTyp   = reflect.TypeOf([]uint8(nil))
+	uint16SliceTyp  = reflect.TypeOf([]uint16(nil))
+	uint32SliceTyp  = reflect.TypeOf([]uint32(nil))
+	uint64SliceTyp  = reflect.TypeOf([]uint64(nil))
+	intSliceTyp     = reflect.TypeOf([]int(nil))
+	int8SliceTyp    = reflect.TypeOf([]int8(nil))
+	int16SliceTyp   = reflect.TypeOf([]int16(nil))
+	int32SliceTyp   = reflect.TypeOf([]int32(nil))
+	int64SliceTyp   = reflect.TypeOf([]int64(nil))
+	float32SliceTyp = reflect.TypeOf([]float32(nil))
+	float64SliceTyp = reflect.TypeOf([]float64(nil))
+
+	mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
+	mapStrIntfTyp  = reflect.TypeOf(map[string]interface{}(nil))
+	mapStrStrTyp   = reflect.TypeOf(map[string]string(nil))
+
 	mapIntIntfTyp    = reflect.TypeOf(map[int]interface{}(nil))
 	mapIntIntfTyp    = reflect.TypeOf(map[int]interface{}(nil))
+	mapInt64IntfTyp  = reflect.TypeOf(map[int64]interface{}(nil))
+	mapUintIntfTyp   = reflect.TypeOf(map[uint]interface{}(nil))
+	mapUint64IntfTyp = reflect.TypeOf(map[uint64]interface{}(nil))
 
 
-	stringTyp     = reflect.TypeOf("")
-	timeTyp       = reflect.TypeOf(time.Time{})
-	int64SliceTyp = reflect.TypeOf([]int64(nil))
-	rawExtTyp     = reflect.TypeOf(RawExt{})
+	stringTyp = reflect.TypeOf("")
+	timeTyp   = reflect.TypeOf(time.Time{})
+	rawExtTyp = reflect.TypeOf(RawExt{})
 
 
 	mapBySliceTyp        = reflect.TypeOf((*MapBySlice)(nil)).Elem()
 	mapBySliceTyp        = reflect.TypeOf((*MapBySlice)(nil)).Elem()
 	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
 	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
 	binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(nil)).Elem()
 	binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(nil)).Elem()
 
 
-	intfTypId      = reflect.ValueOf(intfTyp).Pointer()
-	timeTypId      = reflect.ValueOf(timeTyp).Pointer()
+	rawExtTypId = reflect.ValueOf(rawExtTyp).Pointer()
+	intfTypId   = reflect.ValueOf(intfTyp).Pointer()
+	timeTypId   = reflect.ValueOf(timeTyp).Pointer()
+
 	intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer()
 	intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer()
-	intSliceTypId  = reflect.ValueOf(intSliceTyp).Pointer()
 	strSliceTypId  = reflect.ValueOf(strSliceTyp).Pointer()
 	strSliceTypId  = reflect.ValueOf(strSliceTyp).Pointer()
-	byteSliceTypId = reflect.ValueOf(byteSliceTyp).Pointer()
-	rawExtTypId    = reflect.ValueOf(rawExtTyp).Pointer()
 
 
-	mapStringIntfTypId = reflect.ValueOf(mapStringIntfTyp).Pointer()
+	boolSliceTypId    = reflect.ValueOf(boolSliceTyp).Pointer()
+	uintSliceTypId    = reflect.ValueOf(uintSliceTyp).Pointer()
+	uint8SliceTypId   = reflect.ValueOf(uint8SliceTyp).Pointer()
+	uint16SliceTypId  = reflect.ValueOf(uint16SliceTyp).Pointer()
+	uint32SliceTypId  = reflect.ValueOf(uint32SliceTyp).Pointer()
+	uint64SliceTypId  = reflect.ValueOf(uint64SliceTyp).Pointer()
+	intSliceTypId     = reflect.ValueOf(intSliceTyp).Pointer()
+	int8SliceTypId    = reflect.ValueOf(int8SliceTyp).Pointer()
+	int16SliceTypId   = reflect.ValueOf(int16SliceTyp).Pointer()
+	int32SliceTypId   = reflect.ValueOf(int32SliceTyp).Pointer()
+	int64SliceTypId   = reflect.ValueOf(int64SliceTyp).Pointer()
+	float32SliceTypId = reflect.ValueOf(float32SliceTyp).Pointer()
+	float64SliceTypId = reflect.ValueOf(float64SliceTyp).Pointer()
+
+	mapStrStrTypId     = reflect.ValueOf(mapStrStrTyp).Pointer()
 	mapIntfIntfTypId   = reflect.ValueOf(mapIntfIntfTyp).Pointer()
 	mapIntfIntfTypId   = reflect.ValueOf(mapIntfIntfTyp).Pointer()
+	mapStrIntfTypId    = reflect.ValueOf(mapStrIntfTyp).Pointer()
 	mapIntIntfTypId    = reflect.ValueOf(mapIntIntfTyp).Pointer()
 	mapIntIntfTypId    = reflect.ValueOf(mapIntIntfTyp).Pointer()
-
+	mapInt64IntfTypId  = reflect.ValueOf(mapInt64IntfTyp).Pointer()
+	mapUintIntfTypId   = reflect.ValueOf(mapUintIntfTyp).Pointer()
+	mapUint64IntfTypId = reflect.ValueOf(mapUint64IntfTyp).Pointer()
+	// Id = reflect.ValueOf().Pointer()
 	// mapBySliceTypId  = reflect.ValueOf(mapBySliceTyp).Pointer()
 	// mapBySliceTypId  = reflect.ValueOf(mapBySliceTyp).Pointer()
 
 
 	binaryMarshalerTypId   = reflect.ValueOf(binaryMarshalerTyp).Pointer()
 	binaryMarshalerTypId   = reflect.ValueOf(binaryMarshalerTyp).Pointer()
@@ -456,6 +488,10 @@ func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
 func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
 	sfi *[]*structFieldInfo, siInfo *structFieldInfo,
 	sfi *[]*structFieldInfo, siInfo *structFieldInfo,
 ) {
 ) {
+	// for rt.Kind() == reflect.Ptr {
+	// 	// indexstack = append(indexstack, 0)
+	// 	rt = rt.Elem()
+	// }
 	for j := 0; j < rt.NumField(); j++ {
 	for j := 0; j < rt.NumField(); j++ {
 		f := rt.Field(j)
 		f := rt.Field(j)
 		stag := f.Tag.Get(structTagName)
 		stag := f.Tag.Get(structTagName)
@@ -465,11 +501,15 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
 		if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
 		if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
 			continue
 			continue
 		}
 		}
-		if f.Anonymous {
-			//if anonymous, inline it if there is no struct tag, else treat as regular field
-			if stag == "" {
-				indexstack2 := append(append([]int(nil), indexstack...), j)
-				rgetTypeInfo(f.Type, indexstack2, fnameToHastag, sfi, siInfo)
+		// if anonymous and there is no struct tag and its a struct (or pointer to struct), inline it.
+		if f.Anonymous && stag == "" {
+			ft := f.Type
+			for ft.Kind() == reflect.Ptr {
+				ft = ft.Elem()
+			}
+			if ft.Kind() == reflect.Struct {
+				indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
+				rgetTypeInfo(ft, indexstack2, fnameToHastag, sfi, siInfo)
 				continue
 				continue
 			}
 			}
 		}
 		}
@@ -485,7 +525,7 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
 			si.i = int16(j)
 			si.i = int16(j)
 		} else {
 		} else {
 			si.i = -1
 			si.i = -1
-			si.is = append(append([]int(nil), indexstack...), j)
+			si.is = append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
 		}
 		}
 
 
 		if siInfo != nil {
 		if siInfo != nil {
@@ -499,9 +539,11 @@ func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bo
 }
 }
 
 
 func panicToErr(err *error) {
 func panicToErr(err *error) {
-	if x := recover(); x != nil {
-		//debug.PrintStack()
-		panicValToErr(x, err)
+	if recoverPanicToErr {
+		if x := recover(); x != nil {
+			//debug.PrintStack()
+			panicValToErr(x, err)
+		}
 	}
 	}
 }
 }