Browse Source

codec: negative vs positive values.

In line with msgpack C implementation, treat signed as synonymous to negative
and unsigned as synonymous to positive integers.

Consequently, encode all negative integers (go intX < 0) as msgpack negative fixnum or signed,
and all positive integers (go intX >= 0, or uintX) as msgpack positive fixnum or unsigned.

Also, get binc implementation up to spec, with distinction between negative and positive integers
(not between signed and unsigned integers). Also, fix binc implementation so that negative integers
are encoded just like positive integers, but with a different vd.

Fixes #24 .
Ugorji Nwoke 12 years ago
parent
commit
f8f25d7bb7
4 changed files with 161 additions and 195 deletions
  1. 80 84
      codec/binc.go
  2. 52 95
      codec/codecs_test.go
  3. 25 13
      codec/msgpack.go
  4. 4 3
      codec/z_helper_test.go

+ 80 - 84
codec/binc.go

@@ -16,8 +16,8 @@ import (
 // vd as low 4 bits (there are 16 slots)
 // vd as low 4 bits (there are 16 slots)
 const (
 const (
 	bincVdSpecial byte = iota
 	bincVdSpecial byte = iota
-	bincVdUint
-	bincVdInt
+	bincVdPosInt
+	bincVdNegInt
 	bincVdFloat
 	bincVdFloat
 
 
 	bincVdString
 	bincVdString
@@ -137,29 +137,27 @@ func (e *bincEncDriver) encInteger8(bd byte, v uint64) {
 }
 }
 
 
 func (e *bincEncDriver) encodeInt(v int64) {
 func (e *bincEncDriver) encodeInt(v int64) {
-	const bd byte = bincVdInt << 4
+	const nbd byte = bincVdNegInt << 4
 	switch {
 	switch {
-	case v == 0:
-		e.w.writen1(bincVdSpecial<<4 | bincSpZero)
+	case v >= 0:
+		e.encUint(bincVdPosInt << 4, true, uint64(v))
 	case v == -1:
 	case v == -1:
 		e.w.writen1(bincVdSpecial<<4 | bincSpNegOne)
 		e.w.writen1(bincVdSpecial<<4 | bincSpNegOne)
-	case v >= 1 && v <= 16:
-		e.w.writen1(bincVdSmallInt<<4 | byte(v-1))
-	case v >= math.MinInt8 && v <= math.MaxInt8:
-		e.w.writen2(bd|0x0, byte(v))
-	case v >= math.MinInt16 && v <= math.MaxInt16:
-		e.w.writen1(bd | 0x1)
-		e.w.writeUint16(uint16(v))
-	case v >= math.MinInt32 && v <= math.MaxInt32:
-		e.encInteger4(bd, uint32(v))
 	default:
 	default:
-		e.encInteger8(bd, uint64(v))
+		e.encUint(bincVdNegInt << 4, false, uint64(-v))
 	}
 	}
 }
 }
 
 
 func (e *bincEncDriver) encodeUint(v uint64) {
 func (e *bincEncDriver) encodeUint(v uint64) {
-	const bd byte = bincVdUint << 4
+	e.encUint(bincVdPosInt << 4, true, v)
+}
+
+func (e *bincEncDriver) encUint(bd byte, pos bool, v uint64) {
 	switch {
 	switch {
+	case v == 0:
+		e.w.writen1(bincVdSpecial<<4 | bincSpZero)
+	case pos && v >= 1 && v <= 16:
+		e.w.writen1(bincVdSmallInt<<4 | byte(v-1))
 	case v <= math.MaxUint8:
 	case v <= math.MaxUint8:
 		e.w.writen2(bd|0x0, byte(v))
 		e.w.writen2(bd|0x0, byte(v))
 	case v <= math.MaxUint16:
 	case v <= math.MaxUint16:
@@ -336,16 +334,18 @@ func (d *bincDecDriver) currentEncodedType() valueType {
 				d.bdType = valueTypeBool
 				d.bdType = valueTypeBool
 			case bincSpNan, bincSpNegInf, bincSpPosInf, bincSpZeroFloat:
 			case bincSpNan, bincSpNegInf, bincSpPosInf, bincSpZeroFloat:
 				d.bdType = valueTypeFloat
 				d.bdType = valueTypeFloat
-			case bincSpZero, bincSpNegOne:
+			case bincSpZero:
+				d.bdType = valueTypeUint
+			case bincSpNegOne:
 				d.bdType = valueTypeInt
 				d.bdType = valueTypeInt
 			default:
 			default:
 				decErr("currentEncodedType: Unrecognized special value 0x%x", d.vs)
 				decErr("currentEncodedType: Unrecognized special value 0x%x", d.vs)
 			}
 			}
 		case bincVdSmallInt:
 		case bincVdSmallInt:
-			d.bdType = valueTypeInt
-		case bincVdUint:
 			d.bdType = valueTypeUint
 			d.bdType = valueTypeUint
-		case bincVdInt:
+		case bincVdPosInt:
+			d.bdType = valueTypeUint
+		case bincVdNegInt:
 			d.bdType = valueTypeInt
 			d.bdType = valueTypeInt
 		case bincVdFloat:
 		case bincVdFloat:
 			d.bdType = valueTypeFloat
 			d.bdType = valueTypeFloat
@@ -428,44 +428,44 @@ func (d *bincDecDriver) decFloat() (f float64) {
 	return
 	return
 }
 }
 
 
-func (d *bincDecDriver) decInt() (v int64) {
-	// need to inline the code (interface conversion and type assertion expensive)
-	switch d.vs {
-	case 0:
-		v = int64(int8(d.r.readn1()))
-	case 1:
-		d.r.readb(d.b[6:])
-		v = int64(int16(bigen.Uint16(d.b[6:])))
-	case 2:
-		d.r.readb(d.b[5:])
-		if d.b[5]&0x80 == 0 {
-			d.b[4] = 0
-		} else {
-			d.b[4] = 0xff
-		}
-		v = int64(int32(bigen.Uint32(d.b[4:])))
-	case 3:
-		d.r.readb(d.b[4:])
-		v = int64(int32(bigen.Uint32(d.b[4:])))
-	case 4, 5, 6:
-		lim := int(7 - d.vs)
-		d.r.readb(d.b[lim:])
-		var fillval byte = 0
-		if d.b[lim]&0x80 != 0 {
-			fillval = 0xff
-		}
-		for i := 0; i < lim; i++ {
-			d.b[i] = fillval
-		}
-		v = int64(bigen.Uint64(d.b[:]))
-	case 7:
-		d.r.readb(d.b[:])
-		v = int64(bigen.Uint64(d.b[:]))
-	default:
-		decErr("integers with greater than 64 bits of precision not supported")
-	}
-	return
-}
+// func (d *bincDecDriver) decInt() (v int64) {
+// 	// need to inline the code (interface conversion and type assertion expensive)
+// 	switch d.vs {
+// 	case 0:
+// 		v = int64(int8(d.r.readn1()))
+// 	case 1:
+// 		d.r.readb(d.b[6:])
+// 		v = int64(int16(bigen.Uint16(d.b[6:])))
+// 	case 2:
+// 		d.r.readb(d.b[5:])
+// 		if d.b[5]&0x80 == 0 {
+// 			d.b[4] = 0
+// 		} else {
+// 			d.b[4] = 0xff
+// 		}
+// 		v = int64(int32(bigen.Uint32(d.b[4:])))
+// 	case 3:
+// 		d.r.readb(d.b[4:])
+// 		v = int64(int32(bigen.Uint32(d.b[4:])))
+// 	case 4, 5, 6:
+// 		lim := int(7 - d.vs)
+// 		d.r.readb(d.b[lim:])
+// 		var fillval byte = 0
+// 		if d.b[lim]&0x80 != 0 {
+// 			fillval = 0xff
+// 		}
+// 		for i := 0; i < lim; i++ {
+// 			d.b[i] = fillval
+// 		}
+// 		v = int64(bigen.Uint64(d.b[:]))
+// 	case 7:
+// 		d.r.readb(d.b[:])
+// 		v = int64(bigen.Uint64(d.b[:]))
+// 	default:
+// 		decErr("integers with greater than 64 bits of precision not supported")
+// 	}
+// 	return
+// }
 
 
 func (d *bincDecDriver) decUint() (v uint64) {
 func (d *bincDecDriver) decUint() (v uint64) {
 	// need to inline the code (interface conversion and type assertion expensive)
 	// need to inline the code (interface conversion and type assertion expensive)
@@ -498,17 +498,25 @@ func (d *bincDecDriver) decUint() (v uint64) {
 	return
 	return
 }
 }
 
 
-func (d *bincDecDriver) decIntAny() (i int64) {
+func (d *bincDecDriver) decIntAny() (ui uint64, i int64, neg bool) {
 	switch d.vd {
 	switch d.vd {
-	case bincVdInt:
-		i = d.decInt()
+	case bincVdPosInt:
+		ui = d.decUint()
+		i = int64(ui)
+	case bincVdNegInt:
+		ui = d.decUint()
+		i = -(int64(ui))
+		neg = true
 	case bincVdSmallInt:
 	case bincVdSmallInt:
 		i = int64(d.vs) + 1
 		i = int64(d.vs) + 1
+		ui = uint64(d.vs) + 1
 	case bincVdSpecial:
 	case bincVdSpecial:
 		switch d.vs {
 		switch d.vs {
 		case bincSpZero:
 		case bincSpZero:
 			//i = 0
 			//i = 0
 		case bincSpNegOne:
 		case bincSpNegOne:
+			neg = true
+			ui = 1
 			i = -1
 			i = -1
 		default:
 		default:
 			decErr("numeric decode fails for special value: d.vs: 0x%x", d.vs)
 			decErr("numeric decode fails for special value: d.vs: 0x%x", d.vs)
@@ -520,12 +528,7 @@ func (d *bincDecDriver) decIntAny() (i int64) {
 }
 }
 
 
 func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) {
 func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) {
-	switch d.vd {
-	case bincVdUint:
-		i = int64(d.decUint())
-	default:
-		i = d.decIntAny()
-	}
+	_, i, _ = d.decIntAny()
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	if bitsize > 0 {
 	if bitsize > 0 {
 		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
 		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
@@ -537,15 +540,9 @@ func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) {
 }
 }
 
 
 func (d *bincDecDriver) decodeUint(bitsize uint8) (ui uint64) {
 func (d *bincDecDriver) decodeUint(bitsize uint8) (ui uint64) {
-	switch d.vd {
-	case bincVdUint:
-		ui = d.decUint()
-	default:
-		if i := d.decIntAny(); i >= 0 {
-			ui = uint64(i)
-		} else {
-			decErr("Assigning negative signed value: %v, to unsigned type", i)
-		}
+	ui, i, neg := d.decIntAny()
+	if neg {
+		decErr("Assigning negative signed value: %v, to unsigned type", i)
 	}
 	}
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	if bitsize > 0 {
 	if bitsize > 0 {
@@ -575,10 +572,9 @@ func (d *bincDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
 		}
 		}
 	case bincVdFloat:
 	case bincVdFloat:
 		f = d.decFloat()
 		f = d.decFloat()
-	case bincVdUint:
-		f = float64(d.decUint())
 	default:
 	default:
-		f = float64(d.decIntAny())
+		_, i, _ := d.decIntAny()
+		f = float64(i)
 	}
 	}
 
 
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowFloat()
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowFloat()
@@ -753,7 +749,7 @@ func (d *bincDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurthe
 			vt = valueTypeFloat
 			vt = valueTypeFloat
 			v = float64(0)
 			v = float64(0)
 		case bincSpZero:
 		case bincSpZero:
-			vt = valueTypeInt
+			vt = valueTypeUint
 			v = int64(0) // int8(0)
 			v = int64(0) // int8(0)
 		case bincSpNegOne:
 		case bincSpNegOne:
 			vt = valueTypeInt
 			vt = valueTypeInt
@@ -762,14 +758,14 @@ func (d *bincDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurthe
 			decErr("decodeNaked: Unrecognized special value 0x%x", d.vs)
 			decErr("decodeNaked: Unrecognized special value 0x%x", d.vs)
 		}
 		}
 	case bincVdSmallInt:
 	case bincVdSmallInt:
-		vt = valueTypeInt
+		vt = valueTypeUint
 		v = int64(int8(d.vs)) + 1 // int8(d.vs) + 1
 		v = int64(int8(d.vs)) + 1 // int8(d.vs) + 1
-	case bincVdUint:
+	case bincVdPosInt:
 		vt = valueTypeUint
 		vt = valueTypeUint
 		v = d.decUint()
 		v = d.decUint()
-	case bincVdInt:
+	case bincVdNegInt:
 		vt = valueTypeInt
 		vt = valueTypeInt
-		v = d.decInt()
+		v = -(int64(d.decUint()))
 	case bincVdFloat:
 	case bincVdFloat:
 		vt = valueTypeFloat
 		vt = valueTypeFloat
 		v = d.decFloat()
 		v = d.decFloat()

+ 52 - 95
codec/codecs_test.go

@@ -16,12 +16,6 @@ package codec
 //
 //
 // Taken together, the tests are pretty extensive.
 // Taken together, the tests are pretty extensive.
 
 
-// Some hints:
-// - python msgpack encodes positive numbers as uints, so use uints below
-//   for positive numbers.
-// - flag mpEncodeUintAsFixnum allows uints be encoded as fixnums.
-//   To accomodate it being true or false, ensure all unsigned values below are > 128.
-
 import (
 import (
 	"bytes"
 	"bytes"
 	"encoding/gob"
 	"encoding/gob"
@@ -160,25 +154,25 @@ func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 	//  - all floats are float64
 	//  - all floats are float64
 	switch iv := v.(type) {
 	switch iv := v.(type) {
 	case int8:
 	case int8:
-		if arg == testVerifyForPython && iv > 0 {
+		if iv > 0 {
 			v2 = uint64(iv)
 			v2 = uint64(iv)
 		} else {
 		} else {
 			v2 = int64(iv)
 			v2 = int64(iv)
 		}
 		}
 	case int16:
 	case int16:
-		if arg == testVerifyForPython && iv > 0 {
+		if iv > 0 {
 			v2 = uint64(iv)
 			v2 = uint64(iv)
 		} else {
 		} else {
 			v2 = int64(iv)
 			v2 = int64(iv)
 		}
 		}
 	case int32:
 	case int32:
-		if arg == testVerifyForPython && iv > 0 {
+		if iv > 0 {
 			v2 = uint64(iv)
 			v2 = uint64(iv)
 		} else {
 		} else {
 			v2 = int64(iv)
 			v2 = int64(iv)
 		}
 		}
 	case int64:
 	case int64:
-		if arg == testVerifyForPython && iv > 0 {
+		if iv > 0 {
 			v2 = uint64(iv)
 			v2 = uint64(iv)
 		} else {
 		} else {
 			v2 = int64(iv)
 			v2 = int64(iv)
@@ -426,6 +420,22 @@ func testMarshal(v interface{}, h Handle) (bs []byte, err error) {
 	return
 	return
 }
 }
 
 
+func testMarshalErr(v interface{}, h Handle, t *testing.T, name string) (bs []byte, err error) {
+	if bs, err = testMarshal(v, h); err != nil {
+		logT(t, "Error encoding %s: %v, Err: %v", name, v, err)
+		t.FailNow()
+	}
+	return
+}
+
+func testUnmarshalErr(v interface{}, data []byte, h Handle, t *testing.T, name string) (err error) {
+	if err = testUnmarshal(v, data, h); err != nil {
+		logT(t, "Error Decoding into %s: %v, Err: %v", name, v, err)
+		t.FailNow()
+	}
+	return   
+}
+
 func newTestStruc(depth int, bench bool) (ts *TestStruc) {
 func newTestStruc(depth int, bench bool) (ts *TestStruc) {
 	var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464
 	var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464
 
 
@@ -501,10 +511,8 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 	for i, v0 := range vs {
 	for i, v0 := range vs {
 		logT(t, "..............................................")
 		logT(t, "..............................................")
 		logT(t, "         Testing: #%d:, %T, %#v\n", i, v0, v0)
 		logT(t, "         Testing: #%d:, %T, %#v\n", i, v0, v0)
-		b0, err := testMarshal(v0, h)
+		b0, err := testMarshalErr(v0, h, t, "v0")
 		if err != nil {
 		if err != nil {
-			logT(t, err.Error())
-			failT(t)
 			continue
 			continue
 		}
 		}
 		logT(t, "         Encoded bytes: len: %v, %v\n", len(b0), b0)
 		logT(t, "         Encoded bytes: len: %v, %v\n", len(b0), b0)
@@ -524,6 +532,7 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 		}
 		}
 
 
 		logT(t, "         v1 returned: %T, %#v", v1, v1)
 		logT(t, "         v1 returned: %T, %#v", v1, v1)
+		// t.FailNow() //todo: ugorji: remove
 		// if v1 != nil {
 		// if v1 != nil {
 		//	logT(t, "         v1 returned: %T, %#v", v1, v1)
 		//	logT(t, "         v1 returned: %T, %#v", v1, v1)
 		//	//we always indirect, because ptr to typed value may be passed (if not testNil)
 		//	//we always indirect, because ptr to typed value may be passed (if not testNil)
@@ -600,7 +609,7 @@ func testCodecTableOne(t *testing.T, h Handle) {
 }
 }
 
 
 func testCodecMiscOne(t *testing.T, h Handle) {
 func testCodecMiscOne(t *testing.T, h Handle) {
-	b, err := testMarshal(32, h)
+	b, err := testMarshalErr(32, h, t, "32")
 	// Cannot do this nil one, because faster type assertion decoding will panic
 	// Cannot do this nil one, because faster type assertion decoding will panic
 	// var i *int32
 	// var i *int32
 	// if err = testUnmarshal(b, i, nil); err == nil {
 	// if err = testUnmarshal(b, i, nil); err == nil {
@@ -608,10 +617,7 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	// 	t.FailNow()
 	// 	t.FailNow()
 	// }
 	// }
 	var i2 int32 = 0
 	var i2 int32 = 0
-	if err = testUnmarshal(&i2, b, h); err != nil {
-		logT(t, "------- Cannot unmarshal to int32 ptr. Error: %v", err)
-		t.FailNow()
-	}
+	err = testUnmarshalErr(&i2, b, h, t, "int32-ptr")
 	if i2 != int32(32) {
 	if i2 != int32(32) {
 		logT(t, "------- didn't unmarshal to 32: Received: %d", i2)
 		logT(t, "------- didn't unmarshal to 32: Received: %d", i2)
 		t.FailNow()
 		t.FailNow()
@@ -619,21 +625,15 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 
 
 	// func TestMsgpackDecodePtr(t *testing.T) {
 	// func TestMsgpackDecodePtr(t *testing.T) {
 	ts := newTestStruc(0, false)
 	ts := newTestStruc(0, false)
-	b, err = testMarshal(ts, h)
-	if err != nil {
-		logT(t, "------- Cannot Marshal pointer to struct. Error: %v", err)
-		t.FailNow()
-	} else if len(b) < 40 {
+	b, err = testMarshalErr(ts, h, t, "pointer-to-struct")
+	if len(b) < 40 {
 		logT(t, "------- Size must be > 40. Size: %d", len(b))
 		logT(t, "------- Size must be > 40. Size: %d", len(b))
 		t.FailNow()
 		t.FailNow()
 	}
 	}
 	logT(t, "------- b: %v", b)
 	logT(t, "------- b: %v", b)
 	ts2 := new(TestStruc)
 	ts2 := new(TestStruc)
-	err = testUnmarshal(ts2, b, h)
-	if err != nil {
-		logT(t, "------- Cannot Unmarshal pointer to struct. Error: %v", err)
-		t.FailNow()
-	} else if ts2.I64 != math.MaxInt64*2/3 {
+	err = testUnmarshalErr(ts2, b, h, t, "pointer-to-struct")
+	if ts2.I64 != math.MaxInt64*2/3 {
 		logT(t, "------- Unmarshal wrong. Expect I64 = 64. Got: %v", ts2.I64)
 		logT(t, "------- Unmarshal wrong. Expect I64 = 64. Got: %v", ts2.I64)
 		t.FailNow()
 		t.FailNow()
 	}
 	}
@@ -641,25 +641,19 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	// func TestMsgpackIntfDecode(t *testing.T) {
 	// func TestMsgpackIntfDecode(t *testing.T) {
 	m := map[string]int{"A": 2, "B": 3}
 	m := map[string]int{"A": 2, "B": 3}
 	p := []interface{}{m}
 	p := []interface{}{m}
-	bs, err := testMarshal(p, h)
-	if err != nil {
-		logT(t, "Error marshalling p: %v, Err: %v", p, err)
-		t.FailNow()
-	}
+	bs, err := testMarshalErr(p, h, t, "p")
 
 
 	m2 := map[string]int{}
 	m2 := map[string]int{}
 	p2 := []interface{}{m2}
 	p2 := []interface{}{m2}
-	err = testUnmarshal(&p2, bs, h)
-	if err != nil {
-		logT(t, "Error unmarshalling into &p2: %v, Err: %v", p2, err)
-		t.FailNow()
-	}
+	err = testUnmarshalErr(&p2, bs, h, t, "&p2")
 
 
 	if m2["A"] != 2 || m2["B"] != 3 {
 	if m2["A"] != 2 || m2["B"] != 3 {
 		logT(t, "m2 not as expected: expecting: %v, got: %v", m, m2)
 		logT(t, "m2 not as expected: expecting: %v, got: %v", m, m2)
 		t.FailNow()
 		t.FailNow()
 	}
 	}
 	// log("m: %v, m2: %v, p: %v, p2: %v", m, m2, p, p2)
 	// log("m: %v, m2: %v, p: %v, p2: %v", m, m2, p, p2)
+	checkEqualT(t, p, p2, "p=p2")
+	checkEqualT(t, m, m2, "m=m2")
 	if err = deepEqual(p, p2); err == nil {
 	if err = deepEqual(p, p2); err == nil {
 		logT(t, "p and p2 match")
 		logT(t, "p and p2 match")
 	} else {
 	} else {
@@ -672,30 +666,19 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 		logT(t, "Not Equal: %v. m: %v, m2: %v", err, m, m2)
 		logT(t, "Not Equal: %v. m: %v, m2: %v", err, m, m2)
 		t.FailNow()
 		t.FailNow()
 	}
 	}
-
+	
 	// func TestMsgpackDecodeStructSubset(t *testing.T) {
 	// func TestMsgpackDecodeStructSubset(t *testing.T) {
 	// test that we can decode a subset of the stream
 	// test that we can decode a subset of the stream
 	mm := map[string]interface{}{"A": 5, "B": 99, "C": 333}
 	mm := map[string]interface{}{"A": 5, "B": 99, "C": 333}
-	bs, err = testMarshal(mm, h)
-	if err != nil {
-		logT(t, "Error marshalling m: %v, Err: %v", mm, err)
-		t.FailNow()
-	}
+	bs, err = testMarshalErr(mm, h, t, "mm")
 	type ttt struct {
 	type ttt struct {
 		A uint8
 		A uint8
 		C int32
 		C int32
 	}
 	}
 	var t2 ttt
 	var t2 ttt
-	err = testUnmarshal(&t2, bs, h)
-	if err != nil {
-		logT(t, "Error unmarshalling into &t2: %v, Err: %v", t2, err)
-		t.FailNow()
-	}
+	testUnmarshalErr(&t2, bs, h, t, "t2")
 	t3 := ttt{5, 333}
 	t3 := ttt{5, 333}
-	if err = deepEqual(t2, t3); err != nil {
-		logT(t, "Not Equal: %v. t2: %v, t3: %v", err, t2, t3)
-		t.FailNow()
-	}
+	checkEqualT(t, t2, t3, "t2=t3")
 
 
 	// println(">>>>>")
 	// println(">>>>>")
 	// test simple arrays, non-addressable arrays, slices
 	// test simple arrays, non-addressable arrays, slices
@@ -708,21 +691,10 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	var tarr0 = tarr{1, [3]int64{2,3,4}, []byte{4,5,6}, [3]byte{7,8,9} }
 	var tarr0 = tarr{1, [3]int64{2,3,4}, []byte{4,5,6}, [3]byte{7,8,9} }
 	// test both pointer and non-pointer (value)
 	// test both pointer and non-pointer (value)
 	for _, tarr1 := range []interface{}{tarr0, &tarr0} {
 	for _, tarr1 := range []interface{}{tarr0, &tarr0} {
-		bs, err = testMarshal(tarr1, h)
-		if err != nil {
-			logT(t, "Error marshalling tarr: %v, Err: %v", tarr1, err)
-			t.FailNow()
-		}
+		bs, err = testMarshalErr(tarr1, h, t, "tarr1")
 		var tarr2 tarr 
 		var tarr2 tarr 
-		err = testUnmarshal(&tarr2, bs, h)
-		if err != nil {
-			logT(t, "Error unmarshalling into &tarr2: %v, Err: %v", tarr2, err)
-			t.FailNow()
-		}
-		if err = deepEqual(tarr0, tarr2); err != nil {
-			logT(t, "Not Equal: %v. tarr1: %v, tarr2: %v", err, tarr0, tarr2)
-			t.FailNow()
-		}
+		testUnmarshalErr(&tarr2, bs, h, t, "tarr2")
+		checkEqualT(t, tarr0, tarr2, "tarr0=tarr2")
 		// fmt.Printf(">>>> err: %v. tarr1: %v, tarr2: %v\n", err, tarr0, tarr2)
 		// fmt.Printf(">>>> err: %v. tarr1: %v, tarr2: %v\n", err, tarr0, tarr2)
 	}
 	}
 
 
@@ -732,11 +704,7 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 			Anarray []byte
 			Anarray []byte
 		}
 		}
 		var ya = ystruct{}
 		var ya = ystruct{}
-		err = testUnmarshal(&ya, []byte{0x91, 0x90}, h)
-		if err != nil {
-			logT(t, "Error unmarshalling into ystruct: %v, Err: %v", ya, err)
-			t.FailNow()
-		}
+		testUnmarshalErr(&ya, []byte{0x91, 0x90}, h, t, "ya")
 	}
 	}
 }
 }
 
 
@@ -752,23 +720,12 @@ func testCodecEmbeddedPointer(t *testing.T, h Handle) {
 	}
 	}
 	var z Z = 4
 	var z Z = 4
 	x1 := &B{&z, &A{5}, 6}
 	x1 := &B{&z, &A{5}, 6}
-	bs, err := testMarshal(x1, h)
-	if err != nil {
-		logT(t, "Error encoding %v, Err: %v", x1, err)
-		t.FailNow()
-	}
+	bs, err := testMarshalErr(x1, h, t, "x1")
 	// fmt.Printf("buf: len(%v): %x\n", buf.Len(), buf.Bytes())
 	// fmt.Printf("buf: len(%v): %x\n", buf.Len(), buf.Bytes())
 	var x2 = new(B)
 	var x2 = new(B)
-	err = testUnmarshal(x2, bs, h)
-	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()
-	}
-
+	err = testUnmarshalErr(x2, bs, h, t, "x2")
+	err = checkEqualT(t, x1, x2, "x1=x2")
+	_ = err
 }
 }
 
 
 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,
@@ -815,16 +772,16 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs ti
 		// log("Calling client")
 		// log("Calling client")
 		checkErrT(t, cl.Call("TestRpcInt.Update", 5, &up))
 		checkErrT(t, cl.Call("TestRpcInt.Update", 5, &up))
 		// log("Called TestRpcInt.Update")
 		// log("Called TestRpcInt.Update")
-		checkEqualT(t, testRpcInt.i, 5)
-		checkEqualT(t, up, 5)
+		checkEqualT(t, testRpcInt.i, 5, "testRpcInt.i=5")
+		checkEqualT(t, up, 5, "up=5")
 		checkErrT(t, cl.Call("TestRpcInt.Square", 1, &sq))
 		checkErrT(t, cl.Call("TestRpcInt.Square", 1, &sq))
-		checkEqualT(t, sq, 25)
+		checkEqualT(t, sq, 25, "sq=25")
 		checkErrT(t, cl.Call("TestRpcInt.Mult", 20, &mult))
 		checkErrT(t, cl.Call("TestRpcInt.Mult", 20, &mult))
-		checkEqualT(t, mult, 100)
+		checkEqualT(t, mult, 100, "mult=100")
 		checkErrT(t, cl.Call("TestRpcInt.EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr))
 		checkErrT(t, cl.Call("TestRpcInt.EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr))
-		checkEqualT(t, rstr, fmt.Sprintf("%#v", TestABC{"Aa", "Bb", "Cc"}))
+		checkEqualT(t, rstr, fmt.Sprintf("%#v", TestABC{"Aa", "Bb", "Cc"}), "rstr=")
 		checkErrT(t, cl.Call("TestRpcInt.Echo123", []string{"A1", "B2", "C3"}, &rstr))
 		checkErrT(t, cl.Call("TestRpcInt.Echo123", []string{"A1", "B2", "C3"}, &rstr))
-		checkEqualT(t, rstr, fmt.Sprintf("%#v", []string{"A1", "B2", "C3"}))
+		checkEqualT(t, rstr, fmt.Sprintf("%#v", []string{"A1", "B2", "C3"}), "rstr=")
 	}
 	}
 
 
 	connFn := func() (bs net.Conn) {
 	connFn := func() (bs net.Conn) {
@@ -975,7 +932,7 @@ func doTestMsgpackRpcSpecGoClientToPythonSvc(t *testing.T) {
 	//checkEqualT(t, rstr, "{'A': 'Aa', 'B': 'Bb', 'C': 'Cc'}")
 	//checkEqualT(t, rstr, "{'A': 'Aa', 'B': 'Bb', 'C': 'Cc'}")
 	var mArgs MsgpackSpecRpcMultiArgs = []interface{}{"A1", "B2", "C3"}
 	var mArgs MsgpackSpecRpcMultiArgs = []interface{}{"A1", "B2", "C3"}
 	checkErrT(t, cl.Call("Echo123", mArgs, &rstr))
 	checkErrT(t, cl.Call("Echo123", mArgs, &rstr))
-	checkEqualT(t, rstr, "1:A1 2:B2 3:C3")
+	checkEqualT(t, rstr, "1:A1 2:B2 3:C3", "rstr=")
 }
 }
 
 
 func doTestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) {
 func doTestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) {
@@ -990,7 +947,7 @@ func doTestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) {
 		t.FailNow()
 		t.FailNow()
 	}
 	}
 	checkEqualT(t, string(cmdout),
 	checkEqualT(t, string(cmdout),
-		fmt.Sprintf("%#v\n%#v\n", []string{"A1", "B2", "C3"}, TestABC{"Aa", "Bb", "Cc"}))
+		fmt.Sprintf("%#v\n%#v\n", []string{"A1", "B2", "C3"}, TestABC{"Aa", "Bb", "Cc"}), "cmdout=")
 }
 }
 
 
 func TestMsgpackCodecsTable(t *testing.T) {
 func TestMsgpackCodecsTable(t *testing.T) {

+ 25 - 13
codec/msgpack.go

@@ -1,6 +1,22 @@
 // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
 // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
 // Use of this source code is governed by a BSD-style license found in the LICENSE file.
 // Use of this source code is governed by a BSD-style license found in the LICENSE file.
 
 
+/*
+MSGPACK
+
+Msgpack-c implementation powers the c, c++, python, ruby, etc libraries.
+We need to maintain compatibility with it and how it encodes integer values
+without caring about the type.
+
+For compatibility with behaviour of msgpack-c reference implementation:
+  - Go intX (>0) and uintX 
+       IS ENCODED AS 
+    msgpack +ve fixnum, unsigned
+  - Go intX (<0)
+       IS ENCODED AS 
+    msgpack -ve fixnum, signed
+
+*/
 package codec
 package codec
 
 
 import (
 import (
@@ -61,11 +77,6 @@ const (
 	mpNegFixNumMax = 0xff
 	mpNegFixNumMax = 0xff
 )
 )
 
 
-// TODO: Should I enable this, which causes small uints be encoded as fixnums?
-// uints are not fixnums. fixnums are always signed.
-// conditionally support them (but keep flag off for compatibility).
-const mpEncodeUintAsFixnum = false 
-
 // MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
 // MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
 // that the backend RPC service takes multiple arguments, which have been arranged
 // that the backend RPC service takes multiple arguments, which have been arranged
 // in sequence in the slice.
 // in sequence in the slice.
@@ -107,28 +118,29 @@ func (e *msgpackEncDriver) encodeNil() {
 }
 }
 
 
 func (e *msgpackEncDriver) encodeInt(i int64) {
 func (e *msgpackEncDriver) encodeInt(i int64) {
+	
 	switch {
 	switch {
-	case i >= -32 && i <= math.MaxInt8:
+	case i >= 0:
+		e.encodeUint(uint64(i))
+	case i >= -32:
 		e.w.writen1(byte(i))
 		e.w.writen1(byte(i))
-	case i < -32 && i >= math.MinInt8:
+	case i >= math.MinInt8:
 		e.w.writen2(mpInt8, byte(i))
 		e.w.writen2(mpInt8, byte(i))
-	case i >= math.MinInt16 && i <= math.MaxInt16:
+	case i >= math.MinInt16:
 		e.w.writen1(mpInt16)
 		e.w.writen1(mpInt16)
 		e.w.writeUint16(uint16(i))
 		e.w.writeUint16(uint16(i))
-	case i >= math.MinInt32 && i <= math.MaxInt32:
+	case i >= math.MinInt32:
 		e.w.writen1(mpInt32)
 		e.w.writen1(mpInt32)
 		e.w.writeUint32(uint32(i))
 		e.w.writeUint32(uint32(i))
-	case i >= math.MinInt64 && i <= math.MaxInt64:
+	default:
 		e.w.writen1(mpInt64)
 		e.w.writen1(mpInt64)
 		e.w.writeUint64(uint64(i))
 		e.w.writeUint64(uint64(i))
-	default:
-		encErr("encInt64: Unreachable block")
 	}
 	}
 }
 }
 
 
 func (e *msgpackEncDriver) encodeUint(i uint64) {
 func (e *msgpackEncDriver) encodeUint(i uint64) {
 	switch {
 	switch {
-	case mpEncodeUintAsFixnum && i <= math.MaxInt8:
+	case i <= math.MaxInt8:
 		e.w.writen1(byte(i))
 		e.w.writen1(byte(i))
 	case i <= math.MaxUint8:
 	case i <= math.MaxUint8:
 		e.w.writen2(mpUint8, byte(i))
 		e.w.writen2(mpUint8, byte(i))

+ 4 - 3
codec/z_helper_test.go

@@ -36,11 +36,12 @@ func checkErrT(t *testing.T, err error) {
 	}
 	}
 }
 }
 
 
-func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}) {
-	if err := deepEqual(v1, v2); err != nil {
-		logT(t, "Do not match: %v. v1: %v, v2: %v", err, v1, v2)
+func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}, desc string) (err error) {
+	if err = deepEqual(v1, v2); err != nil {
+		logT(t, "Not Equal: %s: %v. v1: %v, v2: %v", desc, err, v1, v2)
 		failT(t)
 		failT(t)
 	}
 	}
+	return
 }
 }
 
 
 func logT(x interface{}, format string, args ...interface{}) {
 func logT(x interface{}, format string, args ...interface{}) {