Browse Source

Updated README to refer to binc/msgpack, gofmt'ed sources, and updated to v0.3.0 of binc spec
with support for compact time representation.

Ugorji Nwoke 12 years ago
parent
commit
9966a02b69
14 changed files with 851 additions and 855 deletions
  1. 1 1
      README.md
  2. 24 24
      codec/0doc.go
  3. 24 25
      codec/bench_test.go
  4. 137 150
      codec/binc.go
  5. 156 158
      codec/codecs_test.go
  6. 84 157
      codec/decode.go
  7. 78 133
      codec/encode.go
  8. 3 3
      codec/ext_dep_test.go
  9. 57 54
      codec/helper.go
  10. 26 3
      codec/helper_internal.go
  11. 115 121
      codec/msgpack.go
  12. 15 16
      codec/rpc.go
  13. 122 0
      codec/time.go
  14. 9 10
      codec/z_helper_test.go

+ 1 - 1
README.md

@@ -4,7 +4,7 @@ Collection of Open-Source Go libraries and tools.
 
 ## Codec
 
-[Codec](https://github.com/ugorji/go/tree/master/codec#readme) is a High Performance and Feature-Rich Idiomatic encode/decode and rpc library.
+[Codec](https://github.com/ugorji/go/tree/master/codec#readme) is a High Performance and Feature-Rich Idiomatic encode/decode and rpc library for [msgpack](http://msgpack.org) and [Binc](https://github.com/ugorji/binc).
 
 Online documentation is at [http://godoc.org/github.com/ugorji/go/codec].
 

+ 24 - 24
codec/0doc.go

@@ -19,41 +19,41 @@ the standard library (ie json, xml, gob, etc).
 Rich Feature Set includes:
 
   - Simple but extremely powerful and feature-rich API
-  - Very High Performance.   
+  - Very High Performance.
     Our extensive benchmarks show us outperforming Gob, Json and Bson by 2-4X.
     This was achieved by taking extreme care on:
       - managing allocation
-      - stack frame size (important due to Go's use of split stacks), 
+      - stack frame size (important due to Go's use of split stacks),
       - reflection use
       - recursion implications
       - zero-copy mode (encoding/decoding to byte slice without using temp buffers)
-  - Correct.  
-    Care was taken to precisely handle corner cases like: 
+  - Correct.
+    Care was taken to precisely handle corner cases like:
       overflows, nil maps and slices, nil value in stream, etc.
-  - Efficient zero-copying into temporary byte buffers  
+  - Efficient zero-copying into temporary byte buffers
     when encoding into or decoding from a byte slice.
   - Standard field renaming via tags
-  - Encoding from any value  
+  - Encoding from any value
     (struct, slice, map, primitives, pointers, interface{}, etc)
-  - Decoding into pointer to any non-nil typed value  
+  - Decoding into pointer to any non-nil typed value
     (struct, slice, map, int, float32, bool, string, reflect.Value, etc)
   - Supports extension functions to handle the encode/decode of custom types
-  - Schema-less decoding  
-    (decode into a pointer to a nil interface{} as opposed to a typed non-nil value).  
-    Includes Options to configure what specific map or slice type to use 
+  - Schema-less decoding
+    (decode into a pointer to a nil interface{} as opposed to a typed non-nil value).
+    Includes Options to configure what specific map or slice type to use
     when decoding an encoded list or map into a nil interface{}
   - Provides a RPC Server and Client Codec for net/rpc communication protocol.
   - Msgpack Specific:
       - Provides extension functions to handle spec-defined extensions (binary, timestamp)
-      - Options to resolve ambiguities in handling raw bytes (as string or []byte)  
+      - Options to resolve ambiguities in handling raw bytes (as string or []byte)
         during schema-less decoding (decoding into a nil interface{})
-      - RPC Server/Client Codec for msgpack-rpc protocol defined at: 
+      - RPC Server/Client Codec for msgpack-rpc protocol defined at:
         http://wiki.msgpack.org/display/MSGPACK/RPC+specification
 
 Extension Support
 
 Users can register a function to handle the encoding or decoding of
-their custom types. 
+their custom types.
 
 There are no restrictions on what the custom type can be. Extensions can
 be any type: pointers, structs, custom types off arrays/slices, strings,
@@ -84,7 +84,7 @@ Typical usage model:
       sliceByteTyp = reflect.TypeOf([]byte(nil))
       timeTyp = reflect.TypeOf(time.Time{})
     )
-    
+
     // create and configure Handle
     var (
       bh codec.BincHandle
@@ -92,7 +92,7 @@ Typical usage model:
     )
 
     mh.MapType = mapStrIntfTyp
-    
+
     // configure extensions for msgpack, to enable Binary and Time support for tags 0 and 1
     mh.AddExt(sliceByteTyp, 0, mh.BinaryEncodeExt, mh.BinaryDecodeExt)
     mh.AddExt(timeTyp, 1, mh.TimeEncodeExt, mh.TimeDecodeExt)
@@ -104,15 +104,15 @@ Typical usage model:
       b []byte
       h = &bh // or mh to use msgpack
     )
-    
+
     dec = codec.NewDecoder(r, h)
     dec = codec.NewDecoderBytes(b, h)
-    err = dec.Decode(&v) 
-    
+    err = dec.Decode(&v)
+
     enc = codec.NewEncoder(w, h)
     enc = codec.NewEncoderBytes(&b, h)
     err = enc.Encode(v)
-    
+
     //RPC Server
     go func() {
         for {
@@ -122,10 +122,10 @@ Typical usage model:
             rpc.ServeCodec(rpcCodec)
         }
     }()
-    
+
     //RPC Communication (client side)
-    conn, err = net.Dial("tcp", "localhost:5555")  
-    rpcCodec := rpcH.ClientCodec(conn, h)  
+    conn, err = net.Dial("tcp", "localhost:5555")
+    rpcCodec := rpcH.ClientCodec(conn, h)
     client := rpc.NewClientWithCodec(rpcCodec)
 
 Representative Benchmark Results
@@ -133,7 +133,7 @@ Representative Benchmark Results
 A sample run of benchmark using "go test -bi -bench=.":
 
     ..............................................
-    Benchmark: 
+    Benchmark:
     	Struct recursive Depth:             1
     	ApproxDeepSize Of benchmark Struct: 4786
     Benchmark One-Pass Run:
@@ -158,7 +158,7 @@ A sample run of benchmark using "go test -bi -bench=.":
     Benchmark__VMsgpack_Encode	   20000	     81752 ns/op
     Benchmark__VMsgpack_Decode	   10000	    160050 ns/op
 
-To run full benchmark suite (including against vmsgpack and bson), 
+To run full benchmark suite (including against vmsgpack and bson),
 see notes in ext_dep_test.go
 
 */

+ 24 - 25
codec/bench_test.go

@@ -4,41 +4,41 @@
 package codec
 
 import (
-	"encoding/json"
-	"encoding/gob"
-	"testing"
 	"bytes"
-	"reflect"
-	"time"
-	"runtime"
+	"encoding/gob"
+	"encoding/json"
 	"flag"
 	"fmt"
+	"reflect"
+	"runtime"
+	"testing"
+	"time"
 )
 
 // Sample way to run:
 // go test -bi -bv -bd=1 -benchmem -bench Msgpack__Encode
 
 var (
-	_ = fmt.Printf
+	_       = fmt.Printf
 	benchTs *TestStruc
 
 	approxSize int
 
-	benchDoInitBench bool
-	benchVerify bool
+	benchDoInitBench     bool
+	benchVerify          bool
 	benchUnscientificRes bool = false
 	//depth of 0 maps to ~400bytes json-encoded string, 1 maps to ~1400 bytes, etc
 	//For depth>1, we likely trigger stack growth for encoders, making benchmarking unreliable.
-	benchDepth int
+	benchDepth     int
 	benchInitDebug bool
-	benchInitChan = make(chan bool, 1)
-	benchCheckers []benchChecker
+	benchInitChan  = make(chan bool, 1)
+	benchCheckers  []benchChecker
 )
 
 type benchEncFn func(*TestStruc) ([]byte, error)
 type benchDecFn func([]byte, *TestStruc) error
 type benchChecker struct {
-	name string
+	name     string
 	encodefn benchEncFn
 	decodefn benchDecFn
 }
@@ -58,7 +58,7 @@ func init() {
 		bytesLen = approxSize
 	}
 
-	benchCheckers = append(benchCheckers, 
+	benchCheckers = append(benchCheckers,
 		benchChecker{"msgpack", fnMsgpackEncodeFn, fnMsgpackDecodeFn},
 		benchChecker{"binc", fnBincEncodeFn, fnBincDecodeFn},
 		benchChecker{"gob", fnGobEncodeFn, fnGobDecodeFn},
@@ -66,7 +66,7 @@ func init() {
 	)
 	if benchDoInitBench {
 		go func() {
-			<- benchInitChan
+			<-benchInitChan
 			runBenchInit()
 		}()
 	}
@@ -75,12 +75,12 @@ func init() {
 func runBenchInit() {
 	logT(nil, "..............................................")
 	logT(nil, "BENCHMARK INIT: %v", time.Now())
-	logT(nil, "To run full benchmark comparing encodings (MsgPack, Binc, JSON, GOB, etc), " + 
+	logT(nil, "To run full benchmark comparing encodings (MsgPack, Binc, JSON, GOB, etc), "+
 		"use: \"go test -bench=.\"")
 	logT(nil, "Benchmark: ")
 	logT(nil, "\tStruct recursive Depth:             %d", benchDepth)
 	if approxSize > 0 {
-		logT(nil, "\tApproxDeepSize Of benchmark Struct: %d", approxSize)
+		logT(nil, "\tApproxDeepSize Of benchmark Struct: %d bytes", approxSize)
 	}
 	if benchUnscientificRes {
 		logT(nil, "Benchmark One-Pass Run (with Unscientific Encode/Decode times): ")
@@ -102,12 +102,12 @@ func doBenchCheck(name string, encfn benchEncFn, decfn benchDecFn) {
 	buf, err := encfn(benchTs)
 	if err != nil {
 		logT(nil, "\t%10s: **** Error encoding benchTs: %v", name, err)
-	} 
+	}
 	encDur := time.Now().Sub(tnow)
 	encLen := len(buf)
 	runtime.GC()
 	if !benchUnscientificRes {
-		logT(nil, "\t%10s: len: %v\n", name, encLen)
+		logT(nil, "\t%10s: len: %d bytes\n", name, encLen)
 		return
 	}
 	tnow = time.Now()
@@ -115,7 +115,7 @@ func doBenchCheck(name string, encfn benchEncFn, decfn benchDecFn) {
 		logT(nil, "\t%10s: **** Error decoding into new TestStruc: %v", name, err)
 	}
 	decDur := time.Now().Sub(tnow)
-	logT(nil, "\t%10s: len: %v, encode: %v, decode: %v\n", name, encLen, encDur, decDur)
+	logT(nil, "\t%10s: len: %d bytes, encode: %v, decode: %v\n", name, encLen, encDur, decDur)
 }
 
 func fnBenchmarkEncode(b *testing.B, encName string, encfn benchEncFn) {
@@ -139,7 +139,7 @@ func fnBenchmarkDecode(b *testing.B, encName string, encfn benchEncFn, decfn ben
 	runtime.GC()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		ts := new(TestStruc)		
+		ts := new(TestStruc)
 		if err = decfn(buf, ts); err != nil {
 			logT(b, "Error decoding into new TestStruc: %s: %v", encName, err)
 			b.FailNow()
@@ -172,17 +172,17 @@ func verifyCheckAndGet(b *testing.B, ts0 *TestStruc) (ts1m *TestStruc, ts1s *Tes
 	// if len(ts1m.Ms) <= 2 {
 	// 	logT(b, "Error: ts1m.Ms len should be > 2. Got: %v", len(ts1m.Ms))
 	// 	b.FailNow()
-	// } 
+	// }
 	if len(ts0.Its) == 0 {
 		logT(b, "Error: ts0.Islice len should be > 0. Got: %v", len(ts0.Its))
 		b.FailNow()
 	}
 	ts1m = ts0.Mtsptr["0"]
 	ts1s = ts0.Its[0]
-	if (ts1m == nil || ts1s == nil) {
+	if ts1m == nil || ts1s == nil {
 		logT(b, "Error: At benchDepth 1, No *TestStruc found")
 		b.FailNow()
-	}		
+	}
 	return
 }
 
@@ -260,4 +260,3 @@ func Benchmark__Json_____Encode(b *testing.B) {
 func Benchmark__Json_____Decode(b *testing.B) {
 	fnBenchmarkDecode(b, "json", fnJsonEncodeFn, fnJsonDecodeFn)
 }
-

+ 137 - 150
codec/binc.go

@@ -6,8 +6,8 @@ package codec
 import (
 	"math"
 	"reflect"
-	"time"
 	"sync/atomic"
+	"time"
 	//"fmt"
 )
 
@@ -21,7 +21,7 @@ import (
 //    big integers are unsupported.
 //  - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types).
 //    extended precision and decimal IEEE 754 floats are unsupported.
-//  - Only UTF-8 strings supported. 
+//  - Only UTF-8 strings supported.
 //    Unicode_Other Binc types (UTF16, UTF32) are currently unsupported.
 //Note that these EXCEPTIONS are temporary and full support is possible and may happen soon.
 type BincHandle struct {
@@ -35,20 +35,20 @@ const (
 	bincVdUint
 	bincVdInt
 	bincVdFloat
-	
+
 	bincVdString
 	bincVdByteArray
 	bincVdArray
 	bincVdMap
-	
+
 	bincVdTimestamp
 	bincVdSmallInt
 	bincVdUnicodeOther
 	bincVdSymbol
-	
+
 	bincVdDecimal
-	_ // open slot
-	_ // open slot
+	_               // open slot
+	_               // open slot
 	bincVdCustomExt = 0x0f
 )
 
@@ -61,7 +61,7 @@ const (
 	bincSpNegInf
 	bincSpZeroFloat
 	bincSpZero
-    bincSpNegOne
+	bincSpNegOne
 )
 
 const (
@@ -73,179 +73,170 @@ const (
 	// others not currently supported
 )
 
-type bincEncoder struct { 
+type bincEncDriver struct {
 	w encWriter
 	m map[string]uint16 // symbols
-	s uint32 // symbols sequencer
+	s uint32            // symbols sequencer
 	b [8]byte
 }
 
-type bincDecoder struct {
-	r decReader
+type bincDecDriver struct {
+	r      decReader
 	bdRead bool
-	bd byte 
-	vd byte
-	vs byte 
-	b [8]byte
-	m map[uint16]string // symbols (TODO: maybe use uint32 as key, as map optimizes for it)
+	bd     byte
+	vd     byte
+	vs     byte
+	b      [8]byte
+	m      map[uint16]string // symbols (TODO: maybe use uint32 as key, as map optimizes for it)
 }
 
-func (_ *BincHandle) newEncoder(w encWriter) encoder {
-	return &bincEncoder{w: w}
+func (_ *BincHandle) newEncDriver(w encWriter) encDriver {
+	return &bincEncDriver{w: w}
 }
 
-func (_ *BincHandle) newDecoder(r decReader) decoder {
-	return &bincDecoder{r: r}
+func (_ *BincHandle) newDecDriver(r decReader) decDriver {
+	return &bincDecDriver{r: r}
 }
 
 func (_ *BincHandle) writeExt() bool {
 	return true
 }
 
-func (e *bincEncoder) encodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
+func (e *bincEncDriver) encodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
 	switch rt {
 	case timeTyp:
 		bs := encodeTime(rv.Interface().(time.Time))
-		e.w.writen1(bincVdTimestamp << 4 | uint8(len(bs)))
+		e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
 		e.w.writeb(bs)
 		return true
 	}
 	return false
 }
 
-func (e *bincEncoder) encodeNil() { 
-	e.w.writen1(bincVdSpecial << 4 | bincSpNil)
+func (e *bincEncDriver) encodeNil() {
+	e.w.writen1(bincVdSpecial<<4 | bincSpNil)
 }
 
-func (e *bincEncoder) encodeBool(b bool) { 
+func (e *bincEncDriver) encodeBool(b bool) {
 	if b {
-		e.w.writen1(bincVdSpecial << 4 | bincSpTrue)
+		e.w.writen1(bincVdSpecial<<4 | bincSpTrue)
 	} else {
-		e.w.writen1(bincVdSpecial << 4 | bincSpFalse)
-	}		
+		e.w.writen1(bincVdSpecial<<4 | bincSpFalse)
+	}
 }
 
-func (e *bincEncoder) encodeFloat32(f float32) { 
+func (e *bincEncDriver) encodeFloat32(f float32) {
 	if f == 0 {
-		e.w.writen1(bincVdSpecial << 4 | bincSpZeroFloat)
+		e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat)
 		return
 	}
-	e.w.writen1(bincVdFloat << 4 | bincFlBin32)
+	e.w.writen1(bincVdFloat<<4 | bincFlBin32)
 	e.w.writeUint32(math.Float32bits(f))
 }
 
-func (e *bincEncoder) encodeFloat64(f float64) { 
+func (e *bincEncDriver) encodeFloat64(f float64) {
 	//if true { e.w.writen1(bincVdFloat << 4 | bincFlBin64); e.w.writeUint64(math.Float64bits(f)); return; }
 	if f == 0 {
-		e.w.writen1(bincVdSpecial << 4 | bincSpZeroFloat)
+		e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat)
 		return
 	}
 	bigen.PutUint64(e.b[:], math.Float64bits(f))
 	var i int = 7
-	for ; i >= 0 && (e.b[i] == 0); i-- { }
+	for ; i >= 0 && (e.b[i] == 0); i-- {
+	}
 	i++
 	if i > 6 { // 7 or 8 ie < 2 trailing zeros
-		e.w.writen1(bincVdFloat << 4 | bincFlBin64)
+		e.w.writen1(bincVdFloat<<4 | bincFlBin64)
 		e.w.writeb(e.b[:])
 	} else {
-		e.w.writen1(bincVdFloat << 4 | 0x8 | bincFlBin64)
+		e.w.writen1(bincVdFloat<<4 | 0x8 | bincFlBin64)
 		e.w.writen1(byte(i))
 		e.w.writeb(e.b[:i])
 	}
 }
 
-func (e *bincEncoder) encInteger4(bd byte, trim byte, v uint32) {
+func (e *bincEncDriver) encInteger4(bd byte, v uint32) {
 	const lim int = 4
-	bigen.PutUint32(e.b[:lim], v)
-	var i int 
-	for ; i < (lim-1) && (e.b[i] == trim); i++ { }
-	e.w.writen1(bd | byte(lim-i-1))
+	eb := e.b[:lim]
+	bigen.PutUint32(eb, v)
+	i := pruneSignExt(eb)
+	e.w.writen1(bd | byte(lim-1-i))
 	e.w.writeb(e.b[i:lim])
 }
 
-func (e *bincEncoder) encInteger8(bd byte, trim byte, v uint64) {
+func (e *bincEncDriver) encInteger8(bd byte, v uint64) {
 	const lim int = 8
-	bigen.PutUint64(e.b[:lim], v)
-	var i int 
-	for ; i < (lim-1) && (e.b[i] == trim); i++ { }
-	e.w.writen1(bd | byte(lim-i-1))
+	eb := e.b[:lim]
+	bigen.PutUint64(eb, v)
+	i := pruneSignExt(eb)
+	e.w.writen1(bd | byte(lim-1-i))
 	e.w.writeb(e.b[i:lim])
-	// e.w.writen1(bincVdInt << 4 | 0x03)
-	// e.w.writeUint64(uint64(v))
 }
 
-func (e *bincEncoder) encodeInt(v int64) { 
+func (e *bincEncDriver) encodeInt(v int64) {
 	const bd byte = bincVdInt << 4
 	switch {
 	case v == 0:
-		e.w.writen1(bincVdSpecial << 4 | bincSpZero)
+		e.w.writen1(bincVdSpecial<<4 | bincSpZero)
 	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))
+		e.w.writen1(bincVdSmallInt<<4 | byte(v-1))
 	case v >= math.MinInt8 && v <= math.MaxInt8:
-		e.w.writen2(bd | 0x0, byte(v))
+		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:
-		if v < 0 {
-			e.encInteger4(bd, 0xff, uint32(v))
-		} else {
-			e.encInteger4(bd, 0, uint32(v))
-		} 	
+		e.encInteger4(bd, uint32(v))
 	default:
-		if v < 0 {
-			e.encInteger8(bd, 0xff, uint64(v))
-		} else {
-			e.encInteger8(bd, 0, uint64(v))
-		}
+		e.encInteger8(bd, uint64(v))
 	}
 }
 
-func (e *bincEncoder) encodeUint(v uint64) { 
+func (e *bincEncDriver) encodeUint(v uint64) {
 	const bd byte = bincVdUint << 4
 	switch {
 	case v <= math.MaxUint8:
-		e.w.writen2(bd | 0x0, byte(v))
+		e.w.writen2(bd|0x0, byte(v))
 	case v <= math.MaxUint16:
 		e.w.writen1(bd | 0x01)
 		e.w.writeUint16(uint16(v))
 	case v <= math.MaxUint32:
-		e.encInteger4(bd, 0, uint32(v))
+		e.encInteger4(bd, uint32(v))
 	default:
-		e.encInteger8(bd, 0, v)
+		e.encInteger8(bd, v)
 	}
 }
 
-func (e *bincEncoder) encodeExtPreamble(xtag byte, length int)  {
-	e.encLen(bincVdCustomExt << 4, uint64(length))
+func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) {
+	e.encLen(bincVdCustomExt<<4, uint64(length))
 	e.w.writen1(xtag)
 }
 
-func (e *bincEncoder) encodeArrayPreamble(length int) {
-	e.encLen(bincVdArray << 4, uint64(length))
+func (e *bincEncDriver) encodeArrayPreamble(length int) {
+	e.encLen(bincVdArray<<4, uint64(length))
 }
 
-func (e *bincEncoder) encodeMapPreamble(length int) { 
-	e.encLen(bincVdMap << 4, uint64(length))
+func (e *bincEncDriver) encodeMapPreamble(length int) {
+	e.encLen(bincVdMap<<4, uint64(length))
 }
 
-func (e *bincEncoder) encodeString(c charEncoding, v string) { 
+func (e *bincEncDriver) encodeString(c charEncoding, v string) {
 	l := uint64(len(v))
 	e.encBytesLen(c, l)
 	if l > 0 {
 		e.w.writestr(v)
-	}	
+	}
 }
 
-func (e *bincEncoder) encodeSymbol(v string) { 
+func (e *bincEncDriver) encodeSymbol(v string) {
 	//if true { e.encodeString(c_UTF8, v); return; }
-	
+
 	//symbols only offer benefit when string length > 1.
-	//This is because strings with length 1 take only 2 bytes to store 
+	//This is because strings with length 1 take only 2 bytes to store
 	//(bd with embedded length, and single byte for string val).
-	
+
 	l := len(v)
 	switch l {
 	case 0:
@@ -262,9 +253,9 @@ func (e *bincEncoder) encodeSymbol(v string) {
 	ui, ok := e.m[v]
 	if ok {
 		if ui <= math.MaxUint8 {
-			e.w.writen2(bincVdSymbol << 4, byte(ui))
+			e.w.writen2(bincVdSymbol<<4, byte(ui))
 		} else {
-			e.w.writen1(bincVdSymbol << 4 | 0x8)
+			e.w.writen1(bincVdSymbol<<4 | 0x8)
 			e.w.writeUint16(ui)
 		}
 	} else {
@@ -282,9 +273,9 @@ func (e *bincEncoder) encodeSymbol(v string) {
 			lenprec = 3
 		}
 		if ui <= math.MaxUint8 {
-			e.w.writen2(bincVdSymbol << 4 | 0x0 | 0x4 | lenprec, byte(ui))
+			e.w.writen2(bincVdSymbol<<4|0x0|0x4|lenprec, byte(ui))
 		} else {
-			e.w.writen1(bincVdSymbol << 4 | 0x8 | 0x4 | lenprec)
+			e.w.writen1(bincVdSymbol<<4 | 0x8 | 0x4 | lenprec)
 			e.w.writeUint16(ui)
 		}
 		switch lenprec {
@@ -298,35 +289,35 @@ func (e *bincEncoder) encodeSymbol(v string) {
 			e.w.writeUint64(uint64(l))
 		}
 		e.w.writestr(v)
-	}	
+	}
 }
 
-func (e *bincEncoder) encodeStringBytes(c charEncoding, v []byte) { 
+func (e *bincEncDriver) encodeStringBytes(c charEncoding, v []byte) {
 	l := uint64(len(v))
 	e.encBytesLen(c, l)
 	if l > 0 {
 		e.w.writeb(v)
-	}	
+	}
 }
 
-func (e *bincEncoder) encBytesLen(c charEncoding, length uint64) {
+func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) {
 	//TODO: support bincUnicodeOther (for now, just use string or bytearray)
 	if c == c_RAW {
-		e.encLen(bincVdByteArray << 4, length)
+		e.encLen(bincVdByteArray<<4, length)
 	} else {
-		e.encLen(bincVdString << 4, length)
+		e.encLen(bincVdString<<4, length)
 	}
 }
 
-func (e *bincEncoder) encLen(bd byte, l uint64) {
+func (e *bincEncDriver) encLen(bd byte, l uint64) {
 	if l < 12 {
-		e.w.writen1(bd | uint8(l + 4))
+		e.w.writen1(bd | uint8(l+4))
 	} else {
 		e.encLenNumber(bd, l)
 	}
 }
-	
-func (e *bincEncoder) encLenNumber(bd byte, v uint64) {
+
+func (e *bincEncDriver) encLenNumber(bd byte, v uint64) {
 	switch {
 	case v <= math.MaxUint8:
 		e.w.writen2(bd, byte(v))
@@ -342,11 +333,9 @@ func (e *bincEncoder) encLenNumber(bd byte, v uint64) {
 	}
 }
 
-
 //------------------------------------
 
-
-func (d *bincDecoder) initReadNext() {
+func (d *bincDecDriver) initReadNext() {
 	if d.bdRead {
 		return
 	}
@@ -356,15 +345,15 @@ func (d *bincDecoder) initReadNext() {
 	d.bdRead = true
 }
 
-func (d *bincDecoder) currentIsNil() bool {
-	if d.bd == bincVdSpecial << 4 | bincSpNil {
+func (d *bincDecDriver) currentIsNil() bool {
+	if d.bd == bincVdSpecial<<4|bincSpNil {
 		d.bdRead = false
 		return true
-	} 
+	}
 	return false
 }
 
-func (d *bincDecoder) decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
+func (d *bincDecDriver) decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
 	switch rt {
 	case timeTyp:
 		if d.vd != bincVdTimestamp {
@@ -381,8 +370,8 @@ func (d *bincDecoder) decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool
 	return false
 }
 
-func (d *bincDecoder) decFloatPre(vs, defaultLen byte) {
-	if vs & 0x8 == 0 {
+func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
+	if vs&0x8 == 0 {
 		d.r.readb(d.b[0:defaultLen])
 	} else {
 		l := d.r.readn1()
@@ -396,9 +385,9 @@ func (d *bincDecoder) decFloatPre(vs, defaultLen byte) {
 	}
 }
 
-func (d *bincDecoder) decFloat() (f float64) {
+func (d *bincDecDriver) decFloat() (f float64) {
 	//if true { f = math.Float64frombits(d.r.readUint64()); break; }
-	switch vs := d.vs; (vs & 0x7) {
+	switch vs := d.vs; vs & 0x7 {
 	case bincFlBin32:
 		d.decFloatPre(vs, 4)
 		f = float64(math.Float32frombits(bigen.Uint32(d.b[0:4])))
@@ -411,7 +400,7 @@ func (d *bincDecoder) decFloat() (f float64) {
 	return
 }
 
-func (d *bincDecoder) decInt() (v int64) {
+func (d *bincDecDriver) decInt() (v int64) {
 	// need to inline the code (interface conversion and type assertion expensive)
 	switch d.vs {
 	case 0:
@@ -421,7 +410,7 @@ func (d *bincDecoder) decInt() (v int64) {
 		v = int64(int16(bigen.Uint16(d.b[6:])))
 	case 2:
 		d.r.readb(d.b[5:])
-		if d.b[5] & 0x80 == 0 {
+		if d.b[5]&0x80 == 0 {
 			d.b[4] = 0
 		} else {
 			d.b[4] = 0xff
@@ -430,11 +419,11 @@ func (d *bincDecoder) decInt() (v int64) {
 	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)
+	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 {
+		if d.b[lim]&0x80 != 0 {
 			fillval = 0xff
 		}
 		for i := 0; i < lim; i++ {
@@ -447,10 +436,10 @@ func (d *bincDecoder) decInt() (v int64) {
 	default:
 		decErr("integers with greater than 64 bits of precision not supported")
 	}
-	return 
+	return
 }
 
-func (d *bincDecoder) decUint() (v uint64) {
+func (d *bincDecDriver) decUint() (v uint64) {
 	// need to inline the code (interface conversion and type assertion expensive)
 	switch d.vs {
 	case 0:
@@ -465,8 +454,8 @@ func (d *bincDecoder) decUint() (v uint64) {
 	case 3:
 		d.r.readb(d.b[4:])
 		v = uint64(bigen.Uint32(d.b[4:]))
-	case 4,5,6:
-		lim := int(7-d.vs)
+	case 4, 5, 6:
+		lim := int(7 - d.vs)
 		d.r.readb(d.b[lim:])
 		for i := 0; i < lim; i++ {
 			d.b[i] = 0
@@ -478,12 +467,12 @@ func (d *bincDecoder) decUint() (v uint64) {
 	default:
 		decErr("unsigned integers with greater than 64 bits of precision not supported")
 	}
-	return 
+	return
 }
 
-func (d *bincDecoder) decIntAny() (i int64) {
+func (d *bincDecDriver) decIntAny() (i int64) {
 	switch d.vd {
-	case bincVdInt: 
+	case bincVdInt:
 		i = d.decInt()
 	case bincVdSmallInt:
 		i = int64(d.vs) + 1
@@ -501,10 +490,10 @@ func (d *bincDecoder) decIntAny() (i int64) {
 	}
 	return
 }
-		
-func (d *bincDecoder) decodeInt(bitsize uint8) (i int64) {
+
+func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) {
 	switch d.vd {
-	case bincVdUint: 
+	case bincVdUint:
 		i = int64(d.decUint())
 	default:
 		i = d.decIntAny()
@@ -519,9 +508,9 @@ func (d *bincDecoder) decodeInt(bitsize uint8) (i int64) {
 	return
 }
 
-func (d *bincDecoder) decodeUint(bitsize uint8) (ui uint64)  {
+func (d *bincDecDriver) decodeUint(bitsize uint8) (ui uint64) {
 	switch d.vd {
-	case bincVdUint: 
+	case bincVdUint:
 		ui = d.decUint()
 	default:
 		if i := d.decIntAny(); i >= 0 {
@@ -529,18 +518,18 @@ func (d *bincDecoder) decodeUint(bitsize uint8) (ui uint64)  {
 		} else {
 			decErr("Assigning negative signed value: %v, to unsigned type", i)
 		}
-	}	
+	}
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	if bitsize > 0 {
 		if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
-			decErr("Overflow uint value: %v", ui) 
+			decErr("Overflow uint value: %v", ui)
 		}
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *bincDecoder) decodeFloat(chkOverflow32 bool) (f float64) {
+func (d *bincDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
 	if d.vd == bincVdSpecial {
 		switch d.vs {
 		case bincSpNan:
@@ -548,20 +537,20 @@ func (d *bincDecoder) decodeFloat(chkOverflow32 bool) (f float64) {
 		case bincSpPosInf:
 			return math.Inf(1)
 		case bincSpZeroFloat:
-			return 
+			return
 		case bincSpNegInf:
 			return math.Inf(-1)
 		}
 	}
 	switch d.vd {
-	case bincVdFloat: 
+	case bincVdFloat:
 		f = d.decFloat()
-	case bincVdUint: 
+	case bincVdUint:
 		f = float64(d.decUint())
 	default:
 		f = float64(d.decIntAny())
 	}
-	
+
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowFloat()
 	if chkOverflow32 {
 		f2 := f
@@ -576,9 +565,8 @@ func (d *bincDecoder) decodeFloat(chkOverflow32 bool) (f float64) {
 	return
 }
 
-
 // bool can be decoded from bool only (single byte).
-func (d *bincDecoder) decodeBool() (b bool)  {
+func (d *bincDecDriver) decodeBool() (b bool) {
 	switch d.bd {
 	case (bincVdSpecial | bincSpFalse):
 		// b = false
@@ -591,7 +579,7 @@ func (d *bincDecoder) decodeBool() (b bool)  {
 	return
 }
 
-func (d *bincDecoder) readMapLen() (length int) {
+func (d *bincDecDriver) readMapLen() (length int) {
 	if d.vd != bincVdMap {
 		decErr("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd)
 	}
@@ -600,7 +588,7 @@ func (d *bincDecoder) readMapLen() (length int) {
 	return
 }
 
-func (d *bincDecoder) readArrayLen() (length int) {
+func (d *bincDecDriver) readArrayLen() (length int) {
 	if d.vd != bincVdArray {
 		decErr("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd)
 	}
@@ -609,28 +597,28 @@ func (d *bincDecoder) readArrayLen() (length int) {
 	return
 }
 
-func (d *bincDecoder) decLen() int {
+func (d *bincDecDriver) decLen() int {
 	if d.vs <= 3 {
 		return int(d.decUint())
-	} 
+	}
 	return int(d.vs - 4)
 }
 
-func (d *bincDecoder) decodeString() (s string) {
+func (d *bincDecDriver) decodeString() (s string) {
 	switch d.vd {
 	case bincVdString, bincVdByteArray:
 		if length := d.decLen(); length > 0 {
 			s = string(d.r.readn(length))
 		}
 	case bincVdSymbol:
-		//from vs: extract numSymbolBytes, containsStringVal, strLenPrecision, 
+		//from vs: extract numSymbolBytes, containsStringVal, strLenPrecision,
 		//extract symbol
 		//if containsStringVal, read it and put in map
 		//else look in map for string value
 		var symbol uint16
 		vs := d.vs
 		//fmt.Printf(">>>> d.vs: 0b%b, & 0x8: %v, & 0x4: %v\n", d.vs, vs & 0x8, vs & 0x4)
-		if vs & 0x8 == 0 {
+		if vs&0x8 == 0 {
 			symbol = uint16(d.r.readn1())
 		} else {
 			symbol = d.r.readUint16()
@@ -639,8 +627,8 @@ func (d *bincDecoder) decodeString() (s string) {
 		if d.m == nil {
 			d.m = make(map[uint16]string, 16)
 		}
-		
-		if vs & 0x4 == 0 {
+
+		if vs&0x4 == 0 {
 			s = d.m[symbol]
 		} else {
 			//println(">>>> will store symbol")
@@ -661,24 +649,24 @@ func (d *bincDecoder) decodeString() (s string) {
 			d.m[symbol] = s
 		}
 	default:
-		decErr("Invalid d.vd for string. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x", 
+		decErr("Invalid d.vd for string. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x",
 			bincVdString, bincVdByteArray, bincVdSymbol, d.vd)
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *bincDecoder) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
-	var clen int 
+func (d *bincDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
+	var clen int
 	switch d.vd {
 	case bincVdString, bincVdByteArray:
 		clen = d.decLen()
 	default:
-		decErr("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x", 
+		decErr("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x",
 			bincVdString, bincVdByteArray, d.vd)
 	}
 	if clen > 0 {
-		// if no contents in stream, don't update the passed byteslice	
+		// if no contents in stream, don't update the passed byteslice
 		if len(bs) != clen {
 			if len(bs) > clen {
 				bs = bs[:clen]
@@ -694,7 +682,7 @@ func (d *bincDecoder) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
 	return
 }
 
-func (d *bincDecoder) decodeExt(tag byte) (xbs []byte) {
+func (d *bincDecDriver) decodeExt(tag byte) (xbs []byte) {
 	switch d.vd {
 	case bincVdCustomExt:
 		l := d.decLen()
@@ -708,10 +696,10 @@ func (d *bincDecoder) decodeExt(tag byte) (xbs []byte) {
 		decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd)
 	}
 	d.bdRead = false
-	return	
+	return
 }
 
-func (d *bincDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decodeNakedContext) {
+func (d *bincDecDriver) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decodeNakedContext) {
 	d.initReadNext()
 	var v interface{}
 
@@ -776,7 +764,7 @@ func (d *bincDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decode
 		}
 		if fnerr := bfn(rv, d.r.readn(l)); fnerr != nil {
 			panic(fnerr)
-		} 
+		}
 	case bincVdArray:
 		ctx = dncContainer
 		opts := h.(*BincHandle)
@@ -805,4 +793,3 @@ func (d *bincDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decode
 	}
 	return
 }
-

+ 156 - 158
codec/codecs_test.go

@@ -11,7 +11,7 @@ package codec
 // First test internally encodes and decodes things and verifies that
 // the artifact was as expected.
 // Second test will use python msgpack to create a bunch of golden files,
-// read those files, and compare them to what it should be. It then 
+// read those files, and compare them to what it should be. It then
 // writes those files back out and compares the byte streams.
 //
 // Taken together, the tests are pretty extensive.
@@ -21,24 +21,25 @@ package codec
 //   for positive numbers.
 
 import (
-	"reflect"
-	"testing"
-	"net/rpc"
 	"bytes"
-	"time"
+	"encoding/gob"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"math"
+	"net"
+	"net/rpc"
 	"os"
 	"os/exec"
-	"io/ioutil"
 	"path/filepath"
+	"reflect"
 	"strconv"
-	"net"
-	"fmt"
-	"flag"
-	"math"
-	"encoding/gob"
+	"testing"
+	"time"
 )
 
-type testVerifyArg int 
+type testVerifyArg int
+
 const (
 	testVerifyMapTypeSame testVerifyArg = iota
 	testVerifyMapTypeStrIntf
@@ -46,22 +47,22 @@ const (
 )
 
 var (
-	testInitDebug bool
+	testInitDebug   bool
 	testUseIoEncDec bool
-	_ = fmt.Printf
-	skipVerifyVal interface{} = &(struct{}{})
-	timeLoc = time.FixedZone("UTC-08:00", -8*60*60) //time.UTC
-	timeToCompare = time.Date(2012, 2, 2, 2, 2, 2, 2000, timeLoc) //time.Time{} 
+	_                           = fmt.Printf
+	skipVerifyVal   interface{} = &(struct{}{})
+	timeLoc                     = time.FixedZone("UTC-08:00", -8*60*60)         //time.UTC
+	timeToCompare               = time.Date(2012, 2, 2, 2, 2, 2, 2000, timeLoc) //time.Time{}
 	//"2012-02-02T02:02:02.000002000Z" //1328148122000002
-	timeToCompareAs interface{} = timeToCompare.UnixNano() 
-	table []interface{}               // main items we encode
-	tableVerify []interface{}         // we verify encoded things against this after decode
-	tableTestNilVerify []interface{}  // for nil interface, use this to verify (rules are different)
-	tablePythonVerify []interface{}   // for verifying for python, since Python sometimes
-                                      // will encode a float32 as float64, or large int as uint
-	testRpcInt = new(TestRpcInt)
+	timeToCompareAs    interface{}   = timeToCompare.UnixNano()
+	table              []interface{} // main items we encode
+	tableVerify        []interface{} // we verify encoded things against this after decode
+	tableTestNilVerify []interface{} // for nil interface, use this to verify (rules are different)
+	tablePythonVerify  []interface{} // for verifying for python, since Python sometimes
+	// will encode a float32 as float64, or large int as uint
+	testRpcInt   = new(TestRpcInt)
 	testMsgpackH = &MsgpackHandle{}
-	testBincH = &BincHandle{}
+	testBincH    = &BincHandle{}
 )
 
 func init() {
@@ -74,54 +75,54 @@ func init() {
 		ts0 := newTestStruc(2, false)
 		fmt.Printf("====> depth: %v, ts: %#v\n", 2, ts0)
 	}
-	
+
 	testMsgpackH.AddExt(byteSliceTyp, 0, testMsgpackH.BinaryEncodeExt, testMsgpackH.BinaryDecodeExt)
 	testMsgpackH.AddExt(timeTyp, 1, testMsgpackH.TimeEncodeExt, testMsgpackH.TimeDecodeExt)
 }
 
 type AnonInTestStruc struct {
-	AS string
-	AI64 int64
-	AI16 int16
-	AUi64 uint64
-	ASslice []string
+	AS        string
+	AI64      int64
+	AI16      int16
+	AUi64     uint64
+	ASslice   []string
 	AI64slice []int64
 }
 
 type TestStruc struct {
-	S string
-	I64 int64
-	I16 int16
+	S    string
+	I64  int64
+	I16  int16
 	Ui64 uint64
-	Ui8 uint8
-	B bool
-	By byte
-	
-	Sslice []string
-	I64slice []int64
-	I16slice []int16
+	Ui8  uint8
+	B    bool
+	By   byte
+
+	Sslice    []string
+	I64slice  []int64
+	I16slice  []int16
 	Ui64slice []uint64
-	Ui8slice []uint8
-	Bslice []bool
-	Byslice []byte
-	
-	Islice []interface{}
+	Ui8slice  []uint8
+	Bslice    []bool
+	Byslice   []byte
+
+	Islice    []interface{}
 	Iptrslice []*int64
-	
+
 	AnonInTestStruc
-	
+
 	//M map[interface{}]interface{}  `json:"-",bson:"-"`
-	Ms map[string]interface{}
+	Ms    map[string]interface{}
 	Msi64 map[string]int64
-	
-	Nintf interface{}    //don't set this, so we can test for nil
-	T time.Time          
-	Nmap map[string]bool //don't set this, so we can test for nil
-	Nslice []byte        //don't set this, so we can test for nil
-	Nint64 *int64        //don't set this, so we can test for nil
-	Mtsptr map[string]*TestStruc
-	Mts map[string]TestStruc
-	Its []*TestStruc
+
+	Nintf      interface{} //don't set this, so we can test for nil
+	T          time.Time
+	Nmap       map[string]bool //don't set this, so we can test for nil
+	Nslice     []byte          //don't set this, so we can test for nil
+	Nint64     *int64          //don't set this, so we can test for nil
+	Mtsptr     map[string]*TestStruc
+	Mts        map[string]TestStruc
+	Its        []*TestStruc
 	Nteststruc *TestStruc
 }
 
@@ -129,9 +130,9 @@ type TestRpcInt struct {
 	i int
 }
 
-func (r *TestRpcInt) Update(n int, res *int) error { r.i = n; *res = r.i; return nil }
+func (r *TestRpcInt) Update(n int, res *int) error      { r.i = n; *res = r.i; return nil }
 func (r *TestRpcInt) Square(ignore int, res *int) error { *res = r.i * r.i; return nil }
-func (r *TestRpcInt) Mult(n int, res *int) error { *res = r.i * n; return nil }
+func (r *TestRpcInt) Mult(n int, res *int) error        { *res = r.i * n; return nil }
 
 func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 	switch iv := v.(type) {
@@ -161,13 +162,13 @@ func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 			m2[j] = testVerifyVal(vj, arg)
 		}
 		v2 = m2
-	case map[string]bool: 
+	case map[string]bool:
 		switch arg {
 		case testVerifyMapTypeSame:
 			m2 := make(map[string]bool)
 			for kj, kv := range iv {
 				m2[kj] = kv
-			}			
+			}
 			v2 = m2
 		case testVerifyMapTypeStrIntf:
 			m2 := make(map[string]interface{})
@@ -182,7 +183,7 @@ func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 			}
 			v2 = m2
 		}
-	case map[string]interface{}: 
+	case map[string]interface{}:
 		switch arg {
 		case testVerifyMapTypeSame:
 			m2 := make(map[string]interface{})
@@ -203,7 +204,7 @@ func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 			}
 			v2 = m2
 		}
-	case map[interface{}]interface{}: 
+	case map[interface{}]interface{}:
 		m2 := make(map[interface{}]interface{})
 		for kj, kv := range iv {
 			m2[testVerifyVal(kj, arg)] = testVerifyVal(kv, arg)
@@ -216,7 +217,7 @@ func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
 }
 
 func init() {
-	primitives := []interface{} {
+	primitives := []interface{}{
 		int8(-8),
 		int16(-1616),
 		int32(-32323232),
@@ -240,12 +241,12 @@ func init() {
 	}
 	mapsAndStrucs := []interface{}{
 		map[string]bool{
-			"true":true,
-			"false":false,
+			"true":  true,
+			"false": false,
 		},
 		map[string]interface{}{
-			"true": "True",
-			"false": false,
+			"true":         "True",
+			"false":        false,
 			"uint16(1616)": uint16(1616),
 		},
 		//add a complex combo map in here. (map has list which has map)
@@ -256,25 +257,25 @@ func init() {
 				int32(32323232),
 				true,
 				float32(-3232.0),
-				map[string]interface{} {
-					"TRUE":true,
-					"FALSE":false,
+				map[string]interface{}{
+					"TRUE":  true,
+					"FALSE": false,
 				},
 				[]interface{}{true, false},
 			},
-			"int32": int32(32323232),
-			"bool": true,
-			"LONG STRING": "123456789012345678901234567890123456789012345678901234567890",
+			"int32":        int32(32323232),
+			"bool":         true,
+			"LONG STRING":  "123456789012345678901234567890123456789012345678901234567890",
 			"SHORT STRING": "1234567890",
 		},
 		map[interface{}]interface{}{
-			true: "true",
+			true:     "true",
 			uint8(8): false,
-			"false": uint8(0),
+			"false":  uint8(0),
 		},
 		newTestStruc(0, false),
 	}
-	
+
 	table = []interface{}{}
 	table = append(table, primitives...)    //0-19 are primitives
 	table = append(table, primitives)       //20 is a list of primitives
@@ -283,14 +284,14 @@ func init() {
 	tableVerify = make([]interface{}, len(table))
 	tableTestNilVerify = make([]interface{}, len(table))
 	tablePythonVerify = make([]interface{}, len(table))
-	
+
 	lp := len(primitives)
 	av := tableVerify
 	for i, v := range table {
 		if i == lp+3 {
 			av[i] = skipVerifyVal
 			continue
-		} 
+		}
 		switch v.(type) {
 		case []interface{}:
 			av[i] = testVerifyVal(v, testVerifyMapTypeSame)
@@ -300,21 +301,21 @@ func init() {
 			av[i] = testVerifyVal(v, testVerifyMapTypeSame)
 		default:
 			av[i] = v
-		}				
+		}
 	}
 
 	av = tableTestNilVerify
 	for i, v := range table {
-		if i > lp+3 { 
+		if i > lp+3 {
 			av[i] = skipVerifyVal
 			continue
 		}
 		av[i] = testVerifyVal(v, testVerifyMapTypeStrIntf)
 	}
-	
+
 	av = tablePythonVerify
 	for i, v := range table {
-		if i > lp+3 { 
+		if i > lp+3 {
 			av[i] = skipVerifyVal
 			continue
 		}
@@ -332,7 +333,7 @@ func init() {
 			av[i] = m3
 		case 23:
 			m2 := make(map[string]interface{})
-			for k2, v2 := range av[i].(map[string]interface{}) { 
+			for k2, v2 := range av[i].(map[string]interface{}) {
 				m2[k2] = v2
 			}
 			m2["int32"] = uint64(32323232)
@@ -341,7 +342,7 @@ func init() {
 			av[i] = m2
 		}
 	}
-	
+
 	tablePythonVerify = tablePythonVerify[:24]
 }
 
@@ -365,28 +366,28 @@ func testMarshal(v interface{}, h Handle) (bs []byte, err error) {
 
 func newTestStruc(depth int, bench bool) (ts *TestStruc) {
 	var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464
-	
-	ts = &TestStruc {
-		S: "some string",
-		I64: math.MaxInt64 * 2 / 3, // 64,
-		I16: 16,
+
+	ts = &TestStruc{
+		S:    "some string",
+		I64:  math.MaxInt64 * 2 / 3, // 64,
+		I16:  16,
 		Ui64: uint64(int64(math.MaxInt64 * 2 / 3)), // 64, //don't use MaxUint64, as bson can't write it
-		Ui8: 160,
-		B: true,
-		By: 5,
-		
-		Sslice: []string{"one", "two", "three"},
-		I64slice: []int64{1, 2, 3},
-		I16slice: []int16{4, 5, 6},
+		Ui8:  160,
+		B:    true,
+		By:   5,
+
+		Sslice:    []string{"one", "two", "three"},
+		I64slice:  []int64{1, 2, 3},
+		I16slice:  []int16{4, 5, 6},
 		Ui64slice: []uint64{7, 8, 9},
-		Ui8slice: []uint8{10, 11, 12},
-		Bslice: []bool{true, false, true, false},
-		Byslice: []byte{13, 14, 15},
-		
+		Ui8slice:  []uint8{10, 11, 12},
+		Bslice:    []bool{true, false, true, false},
+		Byslice:   []byte{13, 14, 15},
+
 		Islice: []interface{}{"true", true, "no", false, uint64(88), float64(0.4)},
-		
+
 		Ms: map[string]interface{}{
-			"true": "true",
+			"true":     "true",
 			"int64(9)": false,
 		},
 		Msi64: map[string]int64{
@@ -395,11 +396,11 @@ func newTestStruc(depth int, bench bool) (ts *TestStruc) {
 		},
 		T: timeToCompare,
 		AnonInTestStruc: AnonInTestStruc{
-			AS: "A-String",
-			AI64: 64,
-			AI16: 16,
-			AUi64: 64,
-			ASslice: []string{"Aone", "Atwo", "Athree"},
+			AS:        "A-String",
+			AI64:      64,
+			AI16:      16,
+			AUi64:     64,
+			ASslice:   []string{"Aone", "Atwo", "Athree"},
 			AI64slice: []int64{1, 2, 3},
 		},
 	}
@@ -430,7 +431,7 @@ func newTestStruc(depth int, bench bool) (ts *TestStruc) {
 }
 
 // doTestCodecTableOne allows us test for different variations based on arguments passed.
-func doTestCodecTableOne(t *testing.T, testNil bool, h Handle, 
+func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 	vs []interface{}, vsVerify []interface{}) {
 	//if testNil, then just test for when a pointer to a nil interface{} is passed. It should work.
 	//Current setup allows us test (at least manually) the nil interface or typed interface.
@@ -445,9 +446,9 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 			continue
 		}
 		logT(t, "         Encoded bytes: len: %v, %v\n", len(b0), b0)
-		
+
 		var v1 interface{}
-		
+
 		if testNil {
 			err = testUnmarshal(&v1, b0, h)
 		} else {
@@ -459,7 +460,7 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 				// v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface()
 			}
 		}
-		
+
 		logT(t, "         v1 returned: %T, %#v", v1, v1)
 		// if v1 != nil {
 		//	logT(t, "         v1 returned: %T, %#v", v1, v1)
@@ -472,32 +473,31 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 			continue
 		}
 		v0check := vsVerify[i]
-		if v0check == skipVerifyVal { 
+		if v0check == skipVerifyVal {
 			logT(t, "        Nil Check skipped: Decoded: %T, %#v\n", v1, v1)
-			continue 
+			continue
 		}
-		
-		if err = deepEqual(v0check, v1); err == nil { 
+
+		if err = deepEqual(v0check, v1); err == nil {
 			logT(t, "++++++++ Before and After marshal matched\n")
 		} else {
-			logT(t, "-------- Before and After marshal do not match: Error: %v" + 
+			logT(t, "-------- Before and After marshal do not match: Error: %v"+
 				" ====> AGAINST: (%T) %#v, DECODED: (%T) %#v\n", err, v0check, v0check, v1, v1)
 			failT(t)
 		}
 	}
 }
 
-
 func testCodecTableOne(t *testing.T, h Handle) {
 	// func TestMsgpackAllExperimental(t *testing.T) {
-	// dopts := testDecOpts(nil, nil, false, true, true), 
+	// dopts := testDecOpts(nil, nil, false, true, true),
 	var oldWriteExt bool
 	switch v := h.(type) {
 	case *MsgpackHandle:
 		oldWriteExt = v.WriteExt
 		v.WriteExt = true
 	}
-	doTestCodecTableOne(t, false, h, table, tableVerify) 
+	doTestCodecTableOne(t, false, h, table, tableVerify)
 	//if true { panic("") }
 	switch v := h.(type) {
 	case *MsgpackHandle:
@@ -505,8 +505,8 @@ func testCodecTableOne(t *testing.T, h Handle) {
 	}
 	// func TestMsgpackAll(t *testing.T) {
 
-	doTestCodecTableOne(t, false, h, table[:20], tableVerify[:20]) 
-	doTestCodecTableOne(t, false, h, table[21:], tableVerify[21:]) 
+	doTestCodecTableOne(t, false, h, table[:20], tableVerify[:20])
+	doTestCodecTableOne(t, false, h, table[21:], tableVerify[21:])
 
 	// func TestMsgpackNilStringMap(t *testing.T) {
 	var oldMapType reflect.Type
@@ -519,10 +519,10 @@ func testCodecTableOne(t *testing.T, h Handle) {
 		v.MapType = mapStringIntfTyp
 	}
 	//skip #16 (time.Time), and #20 ([]interface{} containing time.Time)
-	doTestCodecTableOne(t, true, h, table[:16], tableTestNilVerify[:16]) 
+	doTestCodecTableOne(t, true, h, table[:16], tableTestNilVerify[:16])
 	doTestCodecTableOne(t, true, h, table[17:20], tableTestNilVerify[17:20])
-	doTestCodecTableOne(t, true, h, table[21:24], tableTestNilVerify[21:24]) 
-	
+	doTestCodecTableOne(t, true, h, table[21:24], tableTestNilVerify[21:24])
+
 	switch v := h.(type) {
 	case *MsgpackHandle:
 		v.MapType = oldMapType
@@ -530,13 +530,12 @@ func testCodecTableOne(t *testing.T, h Handle) {
 		v.MapType = oldMapType
 	}
 
-	// func TestMsgpackNilIntf(t *testing.T) {	
-	doTestCodecTableOne(t, true, h, table[24:], tableTestNilVerify[24:]) 
+	// func TestMsgpackNilIntf(t *testing.T) {
+	doTestCodecTableOne(t, true, h, table[24:], tableTestNilVerify[24:])
 
-	doTestCodecTableOne(t, true, h, table[17:18], tableTestNilVerify[17:18]) 
+	doTestCodecTableOne(t, true, h, table[17:18], tableTestNilVerify[17:18])
 }
 
-
 func testCodecMiscOne(t *testing.T, h Handle) {
 	b, err := testMarshal(32, h)
 	// Cannot do this nil one, because faster type assertion decoding will panic
@@ -571,13 +570,13 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	if err != nil {
 		logT(t, "------- Cannot Unmarshal pointer to struct. Error: %v", err)
 		t.FailNow()
-	} else if ts2.I64 != math.MaxInt64 * 2 / 3 {
+	} else if ts2.I64 != math.MaxInt64*2/3 {
 		logT(t, "------- Unmarshal wrong. Expect I64 = 64. Got: %v", ts2.I64)
 		t.FailNow()
 	}
 
 	// func TestMsgpackIntfDecode(t *testing.T) {
-	m := map[string]int{"A":2, "B":3, }
+	m := map[string]int{"A": 2, "B": 3}
 	p := []interface{}{m}
 	bs, err := testMarshal(p, h)
 	if err != nil {
@@ -586,12 +585,12 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 	}
 	m2 := map[string]int{}
 	p2 := []interface{}{m2}
-    err = testUnmarshal(&p2, bs, h)
+	err = testUnmarshal(&p2, bs, h)
 	if err != nil {
 		logT(t, "Error unmarshalling into &p2: %v, Err: %v", p2, err)
 		t.FailNow()
 	}
-	
+
 	if m2["A"] != 2 || m2["B"] != 3 {
 		logT(t, "m2 not as expected: expecting: %v, got: %v", m, m2)
 		t.FailNow()
@@ -612,7 +611,7 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 
 	// func TestMsgpackDecodeStructSubset(t *testing.T) {
 	// 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)
@@ -642,14 +641,14 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 	// log("listener: %v", ln.Addr())
 	checkErrT(t, err)
 	defer ln.Close()
-	
+
 	// var opts *DecoderOptions
 	// opts := testDecOpts
 	// opts.MapType = mapStringIntfTyp
 	// opts.RawToString = false
 	serverExitChan := make(chan bool, 1)
 	serverFn := func() {
-		for { 
+		for {
 			conn1, err1 := ln.Accept()
 			if err1 != nil {
 				continue
@@ -666,7 +665,7 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 				sc = rr.ServerCodec(conn1, h)
 			case 'X':
 				serverExitChan <- true
-				// <- serverExitChan				
+				// <- serverExitChan
 				conn1.Close()
 				return // exit serverFn goroutine
 			}
@@ -681,16 +680,16 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 			// 	}
 			// }
 			// if callClose {
-			// 	sc.Close() 
+			// 	sc.Close()
 			// }
 		}
 	}
-	
+
 	clientFn := func(cc rpc.ClientCodec) {
 		cl := rpc.NewClientWithCodec(cc)
 		if callClose {
-			defer cl.Close() 
-		} 
+			defer cl.Close()
+		}
 		var up, sq, mult int
 		// log("Calling client")
 		checkErrT(t, cl.Call("TestRpcInt.Update", 5, &up))
@@ -700,9 +699,9 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 		checkErrT(t, cl.Call("TestRpcInt.Square", 1, &sq))
 		checkEqualT(t, sq, 25)
 		checkErrT(t, cl.Call("TestRpcInt.Mult", 20, &mult))
-		checkEqualT(t, mult, 100)		
+		checkEqualT(t, mult, 100)
 	}
-	
+
 	connFn := func(req byte) (bs net.Conn) {
 		// log("calling f1")
 		bs, err2 := net.Dial(ln.Addr().Network(), ln.Addr().String())
@@ -713,7 +712,7 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 		checkEqualT(t, n1, 1)
 		return
 	}
-	
+
 	go serverFn()
 	if doRequest {
 		bs := connFn('R')
@@ -722,19 +721,19 @@ func doTestRpcOne(t *testing.T, rr Rpc, h Handle, callClose, doRequest, doExit b
 	}
 	if doExit {
 		bs := connFn('X')
-		<- serverExitChan
+		<-serverExitChan
 		bs.Close()
 		// serverExitChan <- true
 	}
 }
 
-// Comprehensive testing that generates data encoded from python msgpack, 
+// Comprehensive testing that generates data encoded from python msgpack,
 // and validates that our code can read and write it out accordingly.
 // We keep this unexported here, and put actual test in ext_dep_test.go.
 // This way, it can be excluded by excluding file completely.
 func doTestMsgpackPythonGenStreams(t *testing.T) {
 	logT(t, "TestPythonGenStreams")
-	tmpdir, err := ioutil.TempDir("", "golang-msgpack-test") 
+	tmpdir, err := ioutil.TempDir("", "golang-msgpack-test")
 	if err != nil {
 		logT(t, "-------- Unable to create temp directory\n")
 		t.FailNow()
@@ -750,7 +749,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 		logT(t, "         %v", string(cmdout))
 		t.FailNow()
 	}
-	
+
 	oldMapType := testMsgpackH.MapType
 	for i, v := range tablePythonVerify {
 		testMsgpackH.MapType = oldMapType
@@ -760,16 +759,16 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 		//encode it again
 		//compare to output stream
 		logT(t, "..............................................")
-		logT(t, "         Testing: #%d: %T, %#v\n", i, v, v) 
+		logT(t, "         Testing: #%d: %T, %#v\n", i, v, v)
 		var bss []byte
-		bss, err = ioutil.ReadFile(filepath.Join(tmpdir, strconv.Itoa(i) + ".golden"))
+		bss, err = ioutil.ReadFile(filepath.Join(tmpdir, strconv.Itoa(i)+".golden"))
 		if err != nil {
 			logT(t, "-------- Error reading golden file: %d. Err: %v", i, err)
 			failT(t)
 			continue
 		}
 		testMsgpackH.MapType = mapStringIntfTyp
-		
+
 		var v1 interface{}
 		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {
 			logT(t, "-------- Error decoding stream: %d: Err: %v", i, err)
@@ -779,9 +778,9 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 		if v == skipVerifyVal {
 			continue
 		}
-		//no need to indirect, because we pass a nil ptr, so we already have the value 
+		//no need to indirect, because we pass a nil ptr, so we already have the value
 		//if v1 != nil { v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface() }
-		if err = deepEqual(v, v1); err == nil { 
+		if err = deepEqual(v, v1); err == nil {
 			logT(t, "++++++++ Objects match")
 		} else {
 			logT(t, "-------- Objects do not match: %v. Source: %T. Decoded: %T", err, v, v1)
@@ -795,7 +794,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 			failT(t)
 			continue
 		}
-		if err = deepEqual(bsb, bss); err == nil { 
+		if err = deepEqual(bsb, bss); err == nil {
 			logT(t, "++++++++ Bytes match")
 		} else {
 			logT(t, "???????? Bytes do not match. %v.", err)
@@ -812,7 +811,7 @@ func doTestMsgpackPythonGenStreams(t *testing.T) {
 		}
 	}
 	testMsgpackH.MapType = oldMapType
-	
+
 }
 
 func TestMsgpackCodecsTable(t *testing.T) {
@@ -828,7 +827,7 @@ func TestBincCodecsTable(t *testing.T) {
 }
 
 func TestBincCodecsMisc(t *testing.T) {
-	testCodecMiscOne(t, testBincH)	
+	testCodecMiscOne(t, testBincH)
 }
 
 func TestMsgpackRpcGo(t *testing.T) {
@@ -841,4 +840,3 @@ func TestMsgpackRpcSpec(t *testing.T) {
 func TestBincRpcGo(t *testing.T) {
 	doTestRpcOne(t, GoRpc, testBincH, true, true, true)
 }
-

+ 84 - 157
codec/decode.go

@@ -7,18 +7,18 @@ import (
 	"io"
 	"reflect"
 	//"math"
-	"fmt"
-	"time"
+	//"fmt"
 )
 
 // Some tagging information for error messages.
 var (
-	msgTagDec = "codec.decoder"
+	msgTagDec  = "codec.decoder"
 	msgBadDesc = "Unrecognized descriptor byte"
-	digits = [...]byte {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
+	digits     = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
 )
 
-type decodeNakedContext uint8 
+type decodeNakedContext uint8
+
 const (
 	dncHandled decodeNakedContext = iota
 	dncNil
@@ -26,7 +26,7 @@ const (
 	dncContainer
 )
 
-// decReader abstracts the reading source, allowing implementations that can 
+// decReader abstracts the reading source, allowing implementations that can
 // read from an io.Reader or directly off a byte slice with zero-copying.
 type decReader interface {
 	readn(n int) []byte
@@ -37,50 +37,47 @@ type decReader interface {
 	readUint64() uint64
 }
 
-type decoder interface {
-	initReadNext() 
+type decDriver interface {
+	initReadNext()
 	currentIsNil() bool
 	decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool
 	//decodeNaked should completely handle extensions, builtins, primitives, etc.
 	//Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
 	decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decodeNakedContext)
 	decodeInt(bitsize uint8) (i int64)
-	decodeUint(bitsize uint8) (ui uint64) 
+	decodeUint(bitsize uint8) (ui uint64)
 	decodeFloat(chkOverflow32 bool) (f float64)
-	decodeBool() (b bool) 
+	decodeBool() (b bool)
 	// decodeString can also decode symbols
-	decodeString() (s string) 
+	decodeString() (s string)
 	decodeBytes(bs []byte) (bsOut []byte, changed bool)
 	decodeExt(tag byte) []byte
 	readMapLen() int
-	readArrayLen() int 
+	readArrayLen() int
 }
 
-type newDecoderFunc func(r decReader) decoder 
-
 // A Decoder reads and decodes an object from an input stream in the codec format.
 type Decoder struct {
 	r decReader
-	d decoder 
+	d decDriver
 	h decodeHandleI
 }
 
 // ioDecReader is a decReader that reads off an io.Reader
 type ioDecReader struct {
 	r io.Reader
-	x [8]byte        //temp byte array re-used internally for efficiency
+	x [8]byte //temp byte array re-used internally for efficiency
 }
 
-
 // bytesDecReader is a decReader that reads off a byte slice with zero copying
 type bytesDecReader struct {
 	b []byte // data
 	c int    // cursor
-	a int // available
+	a int    // available
 }
 
 type decExtTagFn struct {
-	fn func(reflect.Value, []byte)(error)
+	fn  func(reflect.Value, []byte) error
 	tag byte
 }
 
@@ -91,14 +88,13 @@ type decExtTypeTagFn struct {
 
 type decodeHandleI interface {
 	getDecodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value, []byte) error)
-	newDecoder(r decReader) decoder
 	errorIfNoField() bool
 }
 
 type decHandle struct {
 	// put word-aligned fields first (before bools, etc)
-	exts []decExtTypeTagFn
-	extFuncs map[reflect.Type] decExtTagFn
+	exts     []decExtTypeTagFn
+	extFuncs map[reflect.Type]decExtTagFn
 	// if an extension for byte slice is defined, then always decode Raw as strings
 	rawToStringOverride bool
 }
@@ -110,7 +106,7 @@ type DecodeOptions struct {
 	// An instance of SliceType is used during schema-less decoding of an array in the stream.
 	// If nil, we use []interface{}
 	SliceType reflect.Type
-	// ErrorIfNoField controls whether an error is returned when decoding a map 
+	// ErrorIfNoField controls whether an error is returned when decoding a map
 	// from a codec stream into a struct, and no matching struct field is found.
 	ErrorIfNoField bool
 }
@@ -119,10 +115,10 @@ func (o *DecodeOptions) errorIfNoField() bool {
 	return o.ErrorIfNoField
 }
 
-// addDecodeExt registers a function to handle decoding into a given type when an 
-// extension type and specific tag byte is detected in the codec stream. 
+// addDecodeExt registers a function to handle decoding into a given type when an
+// extension type and specific tag byte is detected in the codec stream.
 // To remove an extension, pass fn=nil.
-func (o *decHandle) addDecodeExt(rt reflect.Type, tag byte, fn func(reflect.Value, []byte) (error)) {
+func (o *decHandle) addDecodeExt(rt reflect.Type, tag byte, fn func(reflect.Value, []byte) error) {
 	if o.exts == nil {
 		o.exts = make([]decExtTypeTagFn, 0, 2)
 		o.extFuncs = make(map[reflect.Type]decExtTagFn, 2)
@@ -139,7 +135,7 @@ func (o *decHandle) addDecodeExt(rt reflect.Type, tag byte, fn func(reflect.Valu
 			o.rawToStringOverride = true
 		}
 	}
-	
+
 	if leno := len(o.extFuncs); leno > cap(o.exts) {
 		o.exts = make([]decExtTypeTagFn, leno, (leno * 3 / 2))
 	} else {
@@ -147,7 +143,7 @@ func (o *decHandle) addDecodeExt(rt reflect.Type, tag byte, fn func(reflect.Valu
 	}
 	var i int
 	for k, v := range o.extFuncs {
-		o.exts[i] = decExtTypeTagFn {k, v}
+		o.exts[i] = decExtTypeTagFn{k, v}
 		i++
 	}
 }
@@ -158,7 +154,7 @@ func (o *decHandle) getDecodeExtForTag(tag byte) (rt reflect.Type, fn func(refle
 			return o.exts[i].rt, o.exts[i].fn
 		}
 	}
-	return 
+	return
 }
 
 func (o *decHandle) getDecodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value, []byte) error) {
@@ -179,31 +175,31 @@ func (o *decHandle) getDecodeExt(rt reflect.Type) (tag byte, fn func(reflect.Val
 }
 
 // NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
-func NewDecoder(r io.Reader, h Handle) (*Decoder) {
-	z := ioDecReader {
+func NewDecoder(r io.Reader, h Handle) *Decoder {
+	z := ioDecReader{
 		r: r,
 	}
-	return &Decoder{ r: &z, d: h.newDecoder(&z), h: h }
+	return &Decoder{r: &z, d: h.newDecDriver(&z), h: h}
 }
 
-// NewDecoderBytes returns a Decoder which efficiently decodes directly 
+// NewDecoderBytes returns a Decoder which efficiently decodes directly
 // from a byte slice with zero copying.
-func NewDecoderBytes(in []byte, h Handle) (*Decoder) {
-	z := bytesDecReader {
+func NewDecoderBytes(in []byte, h Handle) *Decoder {
+	z := bytesDecReader{
 		b: in,
 		a: len(in),
 	}
-	return &Decoder{ r: &z, d: h.newDecoder(&z), h: h }
+	return &Decoder{r: &z, d: h.newDecDriver(&z), h: h}
 }
 
-// Decode decodes the stream from reader and stores the result in the 
-// value pointed to by v. v cannot be a nil pointer. v can also be 
+// Decode decodes the stream from reader and stores the result in the
+// value pointed to by v. v cannot be a nil pointer. v can also be
 // a reflect.Value of a pointer.
-// 
+//
 // Note that a pointer to a nil interface is not a nil pointer.
 // If you do not know what type of stream it is, pass in a pointer to a nil interface.
-// We will decode and store a value in that nil interface. 
-// 
+// We will decode and store a value in that nil interface.
+//
 // Sample usages:
 //   // Decoding into a non-nil typed value
 //   var f float32
@@ -213,7 +209,7 @@ func NewDecoderBytes(in []byte, h Handle) (*Decoder) {
 //   var v interface{}
 //   dec := codec.NewDecoder(r, handle)
 //   err = dec.Decode(&v)
-//   
+//
 func (d *Decoder) Decode(v interface{}) (err error) {
 	defer panicToErr(&err)
 	d.decode(v)
@@ -222,7 +218,7 @@ func (d *Decoder) Decode(v interface{}) (err error) {
 
 func (d *Decoder) decode(iv interface{}) {
 	d.d.initReadNext()
-	
+
 	// Fast path included for various pointer types which cannot be registered as extensions
 	switch v := iv.(type) {
 	case nil:
@@ -257,20 +253,19 @@ func (d *Decoder) decode(iv interface{}) {
 	case *float32:
 		*v = float32(d.d.decodeFloat(true))
 	case *float64:
-		*v = d.d.decodeFloat(false) 
+		*v = d.d.decodeFloat(false)
 	case *interface{}:
-	 	d.decodeValue(reflect.ValueOf(iv).Elem())
+		d.decodeValue(reflect.ValueOf(iv).Elem())
 	default:
 		rv := reflect.ValueOf(iv)
 		d.chkPtrValue(rv)
 		d.decodeValue(rv)
-	}	
+	}
 }
 
-
 func (d *Decoder) decodeValue(rv reflect.Value) {
 	// Note: if stream is set to nil, we set the corresponding value to its "zero" value
-	
+
 	// var ctr int (define this above the  function if trying to do this run)
 	// ctr++
 	// log(".. [%v] enter decode: rv: %v <==> %T <==> %v", ctr, rv, rv.Interface(), rv.Interface())
@@ -279,13 +274,13 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 	// }(ctr)
 	dd := d.d //so we don't dereference constantly
 	dd.initReadNext()
-	
+
 	rvOrig := rv
 	wasNilIntf := rv.Kind() == reflect.Interface && rv.IsNil()
 	rt := rv.Type()
-	
+
 	var ndesc decodeNakedContext
-	//if nil interface, use some hieristics to set the nil interface to an 
+	//if nil interface, use some hieristics to set the nil interface to an
 	//appropriate value based on the first byte read (byte descriptor bd)
 	if wasNilIntf {
 		if dd.currentIsNil() {
@@ -313,15 +308,15 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		}
 		return
 	}
-	
-	// An extension can be registered for any type, regardless of the Kind 
+
+	// An extension can be registered for any type, regardless of the Kind
 	// (e.g. type BitSet int64, type MyStruct { / * unexported fields * / }, type X []int, etc.
-	// 
-	// We can't check if it's an extension byte here first, because the user may have 
-	// registered a pointer or non-pointer type, meaning we may have to recurse first 
+	//
+	// We can't check if it's an extension byte here first, because the user may have
+	// registered a pointer or non-pointer type, meaning we may have to recurse first
 	// before matching a mapped type, even though the extension byte is already detected.
-	// 
-	// If we are checking for builtin or ext type here, it means we didn't go through decodeNaked, 
+	//
+	// If we are checking for builtin or ext type here, it means we didn't go through decodeNaked,
 	// Because decodeNaked would have handled it. It also means wasNilIntf = false.
 	if dd.decodeBuiltinType(rt, rv) {
 		return
@@ -333,22 +328,22 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		}
 		return
 	}
-	
+
 	// Note: In decoding into containers, we just use the stream to UPDATE the container.
 	// This means that for a struct or map, we just update matching fields or keys.
-	// For a slice/array, we just update the first n elements, where n is the length of the 
+	// For a slice/array, we just update the first n elements, where n is the length of the
 	// stream.
-	// However, if the encoded value is Nil in the stream, then we try to set 
+	// However, if the encoded value is Nil in the stream, then we try to set
 	// to nil, or a "zero" value.
 	//
 	// Also, we must ensure that, if decoding into a nil interface{}, we return a non-nil
 	// value except even if the container registers a length of 0.
-	// 
-	// NOTE: Do not make blocks for struct, slice, map, etc individual methods. 
+	//
+	// NOTE: Do not make blocks for struct, slice, map, etc individual methods.
 	// It ends up being more expensive, because they recursively calls decodeValue
-	// 
+	//
 	// (Mar 7, 2013. DON'T REARRANGE ... code clarity)
-	// tried arranging in sequence of most probable ones. 
+	// tried arranging in sequence of most probable ones.
 	// string, bool, integer, float, struct, ptr, slice, array, map, interface, uint.
 	switch rk := rv.Kind(); rk {
 	case reflect.String:
@@ -371,7 +366,7 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		rv.SetFloat(dd.decodeFloat(false))
 	case reflect.Uint8:
 		rv.SetUint(dd.decodeUint(8))
-	case reflect.Uint64: 
+	case reflect.Uint64:
 		rv.SetUint(dd.decodeUint(64))
 	case reflect.Uint:
 		rv.SetUint(dd.decodeUint(uintBitsize))
@@ -392,11 +387,11 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		d.decodeValue(rv.Elem())
 	case reflect.Struct:
 		containerLen := dd.readMapLen()
-		
+
 		if containerLen == 0 {
 			break
 		}
-		
+
 		sfi := getStructFieldInfos(rt)
 		for j := 0; j < containerLen; j++ {
 			// var rvkencname string
@@ -412,7 +407,7 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 					d.decodeValue(rv.FieldByIndex(sfik.is))
 				}
 				// d.decodeValue(sfi.field(k, rv))
-			} else { 
+			} else {
 				if d.h.errorIfNoField() {
 					decErr("No matching struct field found when decoding stream map with key: %v", rvkencname)
 				} else {
@@ -423,10 +418,10 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		}
 	case reflect.Slice:
 		// Be more careful calling Set() here, because a reflect.Value from an array
-		// may have come in here (which may not be settable). 
+		// 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.
-		
-		if rt == byteSliceTyp { // rawbytes 
+
+		if rt == byteSliceTyp { // rawbytes
 			if bs2, changed2 := dd.decodeBytes(rv.Bytes()); changed2 {
 				rv.SetBytes(bs2)
 			}
@@ -435,16 +430,16 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 			}
 			break
 		}
-		
+
 		containerLen := dd.readArrayLen()
 
 		if wasNilIntf {
 			rv = reflect.MakeSlice(rt, containerLen, containerLen)
-		} 
+		}
 		if containerLen == 0 {
 			break
 		}
-		
+
 		if rv.IsNil() {
 			// wasNilIntf only applies if rv is nil (since that's what we did earlier)
 			if containerLen > 0 {
@@ -474,7 +469,7 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		d.decodeValue(rv.Slice(0, rv.Len()))
 	case reflect.Map:
 		containerLen := dd.readMapLen()
-		
+
 		if containerLen == 0 {
 			break
 		}
@@ -482,11 +477,11 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 		if rv.IsNil() {
 			rv.Set(reflect.MakeMap(rt))
 		}
-		ktype, vtype := rt.Key(), rt.Elem()			
+		ktype, vtype := rt.Key(), rt.Elem()
 		for j := 0; j < containerLen; j++ {
 			rvk := reflect.New(ktype).Elem()
 			d.decodeValue(rvk)
-			
+
 			if ktype == intfTyp {
 				rvk = rvk.Elem()
 				if rvk.Type() == byteSliceTyp {
@@ -497,29 +492,29 @@ func (d *Decoder) decodeValue(rv reflect.Value) {
 			if !rvv.IsValid() {
 				rvv = reflect.New(vtype).Elem()
 			}
-			
+
 			d.decodeValue(rvv)
 			rv.SetMapIndex(rvk, rvv)
 		}
 	default:
 		decErr("Unhandled value for kind: %v: %s", rk, msgBadDesc)
 	}
-	
+
 	if wasNilIntf {
 		rvOrig.Set(rv)
-	} 
+	}
 	return
 }
 
 func (d *Decoder) chkPtrValue(rv reflect.Value) {
-	// We cannot marshal into a non-pointer or a nil pointer 
+	// 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", 
+		decErr("Decode: Expecting valid pointer to decode into. Got: %v, %T, %v",
 			rv.Kind(), rvi, rvi)
 	}
 }
@@ -573,12 +568,12 @@ func (z *bytesDecReader) consume(n int) (oldcursor int) {
 	oldcursor = z.c
 	z.c = oldcursor + n
 	z.a = z.a - n
-	return 
+	return
 }
 
 func (z *bytesDecReader) readn(n int) (bs []byte) {
 	c0 := z.consume(n)
-	bs = z.b[c0 : z.c]
+	bs = z.b[c0:z.c]
 	return
 }
 
@@ -593,21 +588,21 @@ func (z *bytesDecReader) readn1() uint8 {
 
 // Use binaryEncoding helper for 4 and 8 bits, but inline it for 2 bits
 // creating temp slice variable and copying it to helper function is expensive
-// for just 2 bits. 
+// for just 2 bits.
 
 func (z *bytesDecReader) readUint16() uint16 {
 	c0 := z.consume(2)
-	return uint16(z.b[c0+1]) | uint16(z.b[c0])<<8 
+	return uint16(z.b[c0+1]) | uint16(z.b[c0])<<8
 }
 
 func (z *bytesDecReader) readUint32() uint32 {
 	c0 := z.consume(4)
-	return bigen.Uint32(z.b[c0 : z.c])
+	return bigen.Uint32(z.b[c0:z.c])
 }
 
 func (z *bytesDecReader) readUint64() uint64 {
 	c0 := z.consume(8)
-	return bigen.Uint64(z.b[c0 : z.c])
+	return bigen.Uint64(z.b[c0:z.c])
 }
 
 // ----------------------------------------
@@ -615,71 +610,3 @@ func (z *bytesDecReader) readUint64() uint64 {
 func decErr(format string, params ...interface{}) {
 	doPanic(msgTagDec, format, params...)
 }
-
-// DecodeTimeExt decodes a []byte into a time.Time, 
-// and sets into passed reflectValue.
-func decodeTime(bs []byte) (tt time.Time, err error) {
-	var (
-		tsec int64
-		tnsec int32
-		tz uint16
-	)
-	switch len(bs) {
-	case 4:		
-		tsec = int64(int32(bigen.Uint32(bs)))
-	case 6:
-		tsec = int64(int32(bigen.Uint32(bs)))
-		tz = (bigen.Uint16(bs[4:]))
-	case 8:
-		tsec = int64(int32(bigen.Uint32(bs)))
-		tnsec = int32(bigen.Uint32(bs[4:]))
-	case 10:
-		tsec = int64(int32(bigen.Uint32(bs)))
-		tnsec = int32(bigen.Uint32(bs[4:]))
-		tz = (bigen.Uint16(bs[8:]))
-
-	case 9:
-		tsec = int64(bigen.Uint64(bs))
-	case 11:
-		tsec = int64(bigen.Uint64(bs))
-		tz = (bigen.Uint16(bs[8:]))
-	case 12:
-		tsec = int64(bigen.Uint64(bs))
-		tnsec = int32(bigen.Uint32(bs[8:]))
-	case 14:
-		tsec = int64(bigen.Uint64(bs))
-		tnsec = int32(bigen.Uint32(bs[8:]))
-		tz = (bigen.Uint16(bs[12:]))
-	default:
-		err = fmt.Errorf("Error decoding bytes: %v as time.Time. Invalid length: %v", bs, len(bs))
-		return 
-	}
-	if tz == 0 {
-		tt = time.Unix(tsec, int64(tnsec)).UTC()
-	} else {
-		// In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name.
-		// However, we need name here, so it can be shown when time is printed.
-		// Zone name is in form: UTC-08:00.
-		// Note that Go Libs do not give access to dst flag, so we only check for sign bit
-		tzneg := tz & (1 << 15) != 0 //check if negative sign
-		tz = tz & 0x1fff             //clear 3 MSBs: sign and dst bits 
-		tzoff := int(tz) * 60
-		var tzname = []byte("UTC+00:00")
-		if tzneg {
-			tzoff = -tzoff
-			tzname[3] = '-'
-		}
-		//tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
-		//tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
-		tzhr, tzmin := int(tz/60), int(tz%60)
-		tzname[4] = digits[tzhr/10]
-		tzname[5] = digits[tzhr%10]
-		tzname[7] = digits[tzmin/10]
-		tzname[8] = digits[tzmin%10]
-			
-		//fmt.Printf(">>>>> DEC: tzname: %s, tzoff: %v\n", tzname, tzoff)
-		tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone(string(tzname), tzoff))
-	}
-	return 
-}
-

+ 78 - 133
codec/encode.go

@@ -4,23 +4,21 @@
 package codec
 
 import (
-	"io"
 	"bufio"
+	"io"
 	"reflect"
-	"math"
-	"time"
 	//"fmt"
 )
 
 //var _ = fmt.Printf
 const (
 	// Some tagging information for error messages.
-	msgTagEnc = "codec.encoder"
+	msgTagEnc         = "codec.encoder"
 	defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
 	// maxTimeSecs32 = math.MaxInt32 / 60 / 24 / 366
 )
 
-// encWriter abstracting writing to a byte array or to an io.Writer. 
+// encWriter abstracting writing to a byte array or to an io.Writer.
 type encWriter interface {
 	writeUint16(uint16)
 	writeUint32(uint32)
@@ -34,37 +32,34 @@ type encWriter interface {
 	flush()
 }
 
-type encoder interface {
+type encDriver interface {
 	encodeBuiltinType(rt reflect.Type, rv reflect.Value) bool
 	encodeNil()
 	encodeInt(i int64)
 	encodeUint(i uint64)
-	encodeBool(b bool) 
+	encodeBool(b bool)
 	encodeFloat32(f float32)
 	encodeFloat64(f float64)
-	encodeExtPreamble(xtag byte, length int) 
+	encodeExtPreamble(xtag byte, length int)
 	encodeArrayPreamble(length int)
 	encodeMapPreamble(length int)
 	encodeString(c charEncoding, v string)
 	encodeSymbol(v string)
 	encodeStringBytes(c charEncoding, v []byte)
 	//TODO
-	//encBignum(f *big.Int) 
+	//encBignum(f *big.Int)
 	//encStringRunes(c charEncoding, v []rune)
 }
 
-type newEncoderFunc func(w encWriter) encoder
-
 type encodeHandleI interface {
-	getEncodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value) ([]byte, error)) 
-	newEncoder(w encWriter) encoder
+	getEncodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value) ([]byte, error))
 	writeExt() bool
 }
 
 // An Encoder writes an object to an output stream in the codec format.
 type Encoder struct {
 	w encWriter
-	e encoder
+	e encDriver
 	h encodeHandleI
 }
 
@@ -75,9 +70,9 @@ type ioEncWriterWriter interface {
 }
 
 type ioEncWriterFlusher interface {
-	 Flush() error
+	Flush() error
 }
-	
+
 // ioEncWriter implements encWriter and can write to an io.Writer implementation
 type ioEncWriter struct {
 	w ioEncWriterWriter
@@ -87,16 +82,16 @@ type ioEncWriter struct {
 // bytesEncWriter implements encWriter and can write to an byte slice.
 // It is used by Marshal function.
 type bytesEncWriter struct {
-	b []byte
-	c int // cursor
+	b   []byte
+	c   int     // cursor
 	out *[]byte // write out on flush
 }
-	
+
 type encExtTagFn struct {
-	fn func(reflect.Value) ([]byte, error)
+	fn  func(reflect.Value) ([]byte, error)
 	tag byte
 }
- 
+
 type encExtTypeTagFn struct {
 	rt reflect.Type
 	encExtTagFn
@@ -104,20 +99,20 @@ type encExtTypeTagFn struct {
 
 // EncoderOptions contain options for the encoder, e.g. registered extension functions.
 type encHandle struct {
-	extFuncs map[reflect.Type] encExtTagFn
-	exts []encExtTypeTagFn
+	extFuncs map[reflect.Type]encExtTagFn
+	exts     []encExtTypeTagFn
 }
 
-// addEncodeExt registers a function to handle encoding a given type as an extension  
-// with a specific specific tag byte. 
+// addEncodeExt registers a function to handle encoding a given type as an extension
+// with a specific specific tag byte.
 // To remove an extension, pass fn=nil.
 func (o *encHandle) addEncodeExt(rt reflect.Type, tag byte, fn func(reflect.Value) ([]byte, error)) {
 	if o.exts == nil {
 		o.exts = make([]encExtTypeTagFn, 0, 8)
-		o.extFuncs = make(map[reflect.Type] encExtTagFn, 8)
+		o.extFuncs = make(map[reflect.Type]encExtTagFn, 8)
 	}
 	delete(o.extFuncs, rt)
-	
+
 	if fn != nil {
 		o.extFuncs[rt] = encExtTagFn{fn, tag}
 	}
@@ -128,12 +123,12 @@ func (o *encHandle) addEncodeExt(rt reflect.Type, tag byte, fn func(reflect.Valu
 	}
 	var i int
 	for k, v := range o.extFuncs {
-		o.exts[i] = encExtTypeTagFn {k, v}
+		o.exts[i] = encExtTypeTagFn{k, v}
 		i++
 	}
 }
 
-func (o *encHandle) getEncodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value) ([]byte, error)) {	
+func (o *encHandle) getEncodeExt(rt reflect.Type) (tag byte, fn func(reflect.Value) ([]byte, error)) {
 	// For >= 5 elements, map constant cost less than iteration cost.
 	// This is because reflect.Type equality cost is pretty high
 	if l := len(o.exts); l == 0 {
@@ -155,56 +150,56 @@ func (o *encHandle) getEncodeExt(rt reflect.Type) (tag byte, fn func(reflect.Val
 // NewEncoder returns an Encoder for encoding into an io.Writer.
 // For efficiency, Users are encouraged to pass in a memory buffered writer
 // (eg bufio.Writer, bytes.Buffer). This implementation *may* use one internally.
-func NewEncoder(w io.Writer, h Handle) (*Encoder) {
+func NewEncoder(w io.Writer, h Handle) *Encoder {
 	ww, ok := w.(ioEncWriterWriter)
 	if !ok {
 		ww = bufio.NewWriterSize(w, defEncByteBufSize)
 	}
-	z := ioEncWriter {
+	z := ioEncWriter{
 		w: ww,
 	}
-	return &Encoder { w: &z, h: h, e: h.newEncoder(&z) }
+	return &Encoder{w: &z, h: h, e: h.newEncDriver(&z)}
 }
 
-// NewEncoderBytes returns an encoder for encoding directly and efficiently 
+// NewEncoderBytes returns an encoder for encoding directly and efficiently
 // into a byte slice, using zero-copying to temporary slices.
-// 
+//
 // It will potentially replace the output byte slice pointed to.
 // After encoding, the out parameter contains the encoded contents.
-func NewEncoderBytes(out *[]byte, h Handle) (*Encoder) {
+func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
 	in := *out
 	if in == nil {
 		in = make([]byte, defEncByteBufSize)
 	}
-	z := bytesEncWriter {
-		b: in,
+	z := bytesEncWriter{
+		b:   in,
 		out: out,
 	}
-	return &Encoder { w: &z, h: h, e: h.newEncoder(&z) }
+	return &Encoder{w: &z, h: h, e: h.newEncDriver(&z)}
 }
 
 // Encode writes an object into a stream in the codec format.
-// 
+//
 // Struct values encode as maps. Each exported struct field is encoded unless:
 //    - the field's tag is "-", or
 //    - the field is empty and its tag specifies the "omitempty" option.
 //
-// The empty values are false, 0, any nil pointer or interface value, 
-// and any array, slice, map, or string of length zero. 
-// 
+// The empty values are false, 0, any nil pointer or interface value,
+// and any array, slice, map, or string of length zero.
+//
 // Anonymous fields are encoded inline if no struct tag is present.
 // Else they are encoded as regular fields.
-// 
-// The object's default key string is the struct field name but can be 
-// specified in the struct field's tag value. 
-// The "codec" key in struct field's tag value is the key name, 
-// followed by an optional comma and options. 
-// 
-// To set an option on all fields (e.g. omitempty on all fields), you 
+//
+// The object's default key string is the struct field name but can be
+// specified in the struct field's tag value.
+// The "codec" key in struct field's tag value is the key name,
+// followed by an optional comma and options.
+//
+// To set an option on all fields (e.g. omitempty on all fields), you
 // can create a field called _struct, and set flags on it.
-// 
+//
 // Examples:
-//    
+//
 //      type MyStruct struct {
 //          _struct bool    `codec:",omitempty"`   //set omitempty for every field
 //          Field1 string   `codec:"-"`            //skip this field
@@ -213,23 +208,23 @@ func NewEncoderBytes(out *[]byte, h Handle) (*Encoder) {
 //          Field4 bool     `codec:"f4,omitempty"` //use key "f4". Omit if empty.
 //          ...
 //      }
-// 
-// Note: 
+//
+// Note:
 //   - Encode will treat struct field names and keys in map[string]XXX as symbols.
 //     Some formats support symbols (e.g. binc) and will properly encode the string
 //     only once in the stream, and use a tag to refer to it thereafter.
 func (e *Encoder) Encode(v interface{}) (err error) {
-	defer panicToErr(&err) 
+	defer panicToErr(&err)
 	e.encode(v)
 	e.w.flush()
-	return 
+	return
 }
 
 func (e *Encoder) encode(iv interface{}) {
 	switch v := iv.(type) {
 	case nil:
 		e.e.encodeNil()
-		
+
 	case reflect.Value:
 		e.encodeValue(v)
 
@@ -294,7 +289,7 @@ func (e *Encoder) encode(iv interface{}) {
 	default:
 		e.encodeValue(reflect.ValueOf(iv))
 	}
-	
+
 }
 
 func (e *Encoder) encodeValue(rv reflect.Value) {
@@ -304,7 +299,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 	if ee.encodeBuiltinType(rt, rv) {
 		return
 	}
-	
+
 	//Note: tagFn must handle returning nil if value should be encoded as a nil.
 	if xfTag, xfFn := e.h.getEncodeExt(rt); xfFn != nil {
 		bs, fnerr := xfFn(rv)
@@ -323,7 +318,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		}
 		return
 	}
-	
+
 	// ensure more common cases appear early in switch.
 	rk := rv.Kind()
 	switch rk {
@@ -339,7 +334,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		if rv.IsNil() {
 			ee.encodeNil()
 			break
-		} 
+		}
 		if rt == byteSliceTyp {
 			ee.encodeStringBytes(c_RAW, rv.Bytes())
 			break
@@ -364,7 +359,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 		if l == 0 {
 			break
 		}
-		keyTypeIsString := rt.Key().Kind() == reflect.String 
+		keyTypeIsString := rt.Key().Kind() == reflect.String
 		mks := rv.MapKeys()
 		// for j, lmks := 0, len(mks); j < lmks; j++ {
 		for j := range mks {
@@ -373,7 +368,7 @@ func (e *Encoder) encodeValue(rv reflect.Value) {
 			} else {
 				e.encodeValue(mks[j])
 			}
-		 	e.encodeValue(rv.MapIndex(mks[j]))
+			e.encodeValue(rv.MapIndex(mks[j]))
 		}
 	case reflect.Struct:
 		e.encStruct(rt, rv)
@@ -456,7 +451,7 @@ func (z *ioEncWriter) writeb(bs []byte) {
 	}
 	if n != len(bs) {
 		doPanic(msgTagEnc, "write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n)
-	}	
+	}
 }
 
 func (z *ioEncWriter) writestr(s string) {
@@ -466,7 +461,7 @@ func (z *ioEncWriter) writestr(s string) {
 	}
 	if n != len(s) {
 		doPanic(msgTagEnc, "write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n)
-	}	
+	}
 }
 
 func (z *ioEncWriter) writen1(b byte) {
@@ -506,27 +501,27 @@ func (z *ioEncWriter) flush() {
 func (z *bytesEncWriter) writeUint16(v uint16) {
 	c := z.grow(2)
 	z.b[c] = byte(v >> 8)
-	z.b[c + 1] = byte(v)
+	z.b[c+1] = byte(v)
 }
 
 func (z *bytesEncWriter) writeUint32(v uint32) {
 	c := z.grow(4)
 	z.b[c] = byte(v >> 24)
-	z.b[c + 1] = byte(v >> 16)
-	z.b[c + 2] = byte(v >> 8)
-	z.b[c + 3] = byte(v)
+	z.b[c+1] = byte(v >> 16)
+	z.b[c+2] = byte(v >> 8)
+	z.b[c+3] = byte(v)
 }
 
 func (z *bytesEncWriter) writeUint64(v uint64) {
 	c := z.grow(8)
 	z.b[c] = byte(v >> 56)
-	z.b[c + 1] = byte(v >> 48)
-	z.b[c + 2] = byte(v >> 40)
-	z.b[c + 3] = byte(v >> 32)
-	z.b[c + 4] = byte(v >> 24)
-	z.b[c + 5] = byte(v >> 16)
-	z.b[c + 6] = byte(v >> 8)
-	z.b[c + 7] = byte(v)
+	z.b[c+1] = byte(v >> 48)
+	z.b[c+2] = byte(v >> 40)
+	z.b[c+3] = byte(v >> 32)
+	z.b[c+4] = byte(v >> 24)
+	z.b[c+5] = byte(v >> 16)
+	z.b[c+6] = byte(v >> 8)
+	z.b[c+7] = byte(v)
 }
 
 func (z *bytesEncWriter) writeb(s []byte) {
@@ -547,25 +542,25 @@ func (z *bytesEncWriter) writen1(b1 byte) {
 func (z *bytesEncWriter) writen2(b1 byte, b2 byte) {
 	c := z.grow(2)
 	z.b[c] = b1
-	z.b[c + 1] = b2
+	z.b[c+1] = b2
 }
 
 func (z *bytesEncWriter) writen3(b1 byte, b2 byte, b3 byte) {
 	c := z.grow(3)
 	z.b[c] = b1
-	z.b[c + 1] = b2
-	z.b[c + 2] = b3
+	z.b[c+1] = b2
+	z.b[c+2] = b3
 }
 
 func (z *bytesEncWriter) writen4(b1 byte, b2 byte, b3 byte, b4 byte) {
 	c := z.grow(4)
 	z.b[c] = b1
-	z.b[c + 1] = b2
-	z.b[c + 2] = b3
-	z.b[c + 3] = b4
+	z.b[c+1] = b2
+	z.b[c+2] = b3
+	z.b[c+3] = b4
 }
 
-func (z *bytesEncWriter) flush() { 
+func (z *bytesEncWriter) flush() {
 	*(z.out) = z.b[:z.c]
 }
 
@@ -574,7 +569,7 @@ func (z *bytesEncWriter) grow(n int) (oldcursor int) {
 	z.c = oldcursor + n
 	if z.c > cap(z.b) {
 		// It tried using appendslice logic: (if cap < 1024, *2, else *1.25).
-		// However, it was too expensive, causing too many iterations of copy. 
+		// However, it was too expensive, causing too many iterations of copy.
 		// Using bytes.Buffer model was much better (2*cap + n)
 		bs := make([]byte, 2*cap(z.b)+n)
 		copy(bs, z.b[:oldcursor])
@@ -590,53 +585,3 @@ func (z *bytesEncWriter) grow(n int) (oldcursor int) {
 func encErr(format string, params ...interface{}) {
 	doPanic(msgTagEnc, format, params...)
 }
-
-// EncodeTimeExt encodes a time.Time as a []byte, including 
-// information on the instant in time and UTC offset.
-func encodeTime(t time.Time) ([]byte) {
-	//t := rv.Interface().(time.Time)
-	tsecs, tnsecs := t.Unix(), t.Nanosecond()
-	var padzero bool
-	var bs [14]byte
-	var i int
-	l := t.Location()
-	if l == time.UTC {
-		l = nil
-	}
-	if tsecs > math.MinInt32 && tsecs < math.MaxInt32 {
-		bigen.PutUint32(bs[i:], uint32(int32(tsecs)))
-		i = i + 4
-	} else {
-		bigen.PutUint64(bs[i:], uint64(tsecs))
-		i = i + 8
-		padzero = (tnsecs == 0)
-	}
-	if tnsecs != 0 {
-		bigen.PutUint32(bs[i:], uint32(tnsecs))
-		i = i + 4
-	}
-	if l != nil {
-		// Note that Go Libs do not give access to dst flag.
-		_, zoneOffset := t.Zone()
-		//zoneName, zoneOffset := t.Zone()
-		//fmt.Printf(">>>>>> ENC: zone: %s, %v\n", zoneName, zoneOffset)
-		zoneOffset /= 60
-		isNeg := zoneOffset < 0
-		if isNeg {
-			zoneOffset = -zoneOffset
-		}
-		var z uint16 = uint16(zoneOffset)
-		if isNeg {
-			z |= 1 << 15 //set sign bit
-		}
-		//fmt.Printf(">>>>>> ENC: z: %b\n", z)
-		bigen.PutUint16(bs[i:], z)
-		i = i + 2
-	}
-	if padzero {
-		i = i + 1
-	}
-	//fmt.Printf(">>>> EncodeTimeExt: t: %v, len: %v, v: %v\n", t, i, bs[0:i])
-	return bs[0:i]
-}
-

+ 3 - 3
codec/ext_dep_test.go

@@ -5,9 +5,9 @@
 
 package codec
 
-// This file includes benchmarks which have dependencies on 3rdparty  
+// This file includes benchmarks which have dependencies on 3rdparty
 // packages (bson and vmihailenco/msgpack) which must be installed locally.
-// 
+//
 // To run the benchmarks including these 3rdparty packages, first
 //   - Uncomment first line in this file (put // // in front of it)
 //   - Get those packages:
@@ -23,7 +23,7 @@ import (
 )
 
 func init() {
-	benchCheckers = append(benchCheckers, 
+	benchCheckers = append(benchCheckers,
 		benchChecker{"v-msgpack", fnVMsgpackEncodeFn, fnVMsgpackDecodeFn},
 		benchChecker{"bson", fnBsonEncodeFn, fnBsonDecodeFn},
 	)

+ 57 - 54
codec/helper.go

@@ -6,22 +6,22 @@ package codec
 // Contains code shared by both encode and decode.
 
 import (
-	"unicode"
-	"unicode/utf8"
-	"reflect"
-	"sync"
-	"strings"
+	"encoding/binary"
 	"fmt"
+	"reflect"
 	"sort"
+	"strings"
+	"sync"
 	"time"
-	"encoding/binary"
+	"unicode"
+	"unicode/utf8"
 )
 
 const (
 	// For >= 4 elements, map outways cost of linear search (especially for reflect.Type)
-	mapAccessThreshold = 4 
-	binarySearchThreshold = 16 
-	structTagName = "codec"
+	mapAccessThreshold    = 4
+	binarySearchThreshold = 16
+	structTagName         = "codec"
 )
 
 type charEncoding uint8
@@ -36,24 +36,24 @@ const (
 )
 
 var (
-	bigen = binary.BigEndian
+	bigen               = binary.BigEndian
 	structInfoFieldName = "_struct"
-	
-	cachedStructFieldInfos = make(map[reflect.Type]structFieldInfos, 4)
+
+	cachedStructFieldInfos      = make(map[reflect.Type]structFieldInfos, 4)
 	cachedStructFieldInfosMutex sync.RWMutex
 
-	nilIntfSlice = []interface{}(nil)
-	intfSliceTyp = reflect.TypeOf(nilIntfSlice)
-	intfTyp = intfSliceTyp.Elem()
-	byteSliceTyp = reflect.TypeOf([]byte(nil))
-	ptrByteSliceTyp = reflect.TypeOf((*[]byte)(nil))
+	nilIntfSlice     = []interface{}(nil)
+	intfSliceTyp     = reflect.TypeOf(nilIntfSlice)
+	intfTyp          = intfSliceTyp.Elem()
+	byteSliceTyp     = reflect.TypeOf([]byte(nil))
+	ptrByteSliceTyp  = reflect.TypeOf((*[]byte)(nil))
 	mapStringIntfTyp = reflect.TypeOf(map[string]interface{}(nil))
-	mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
-	timeTyp = reflect.TypeOf(time.Time{})
-	ptrTimeTyp = reflect.TypeOf((*time.Time)(nil))
-	int64SliceTyp = reflect.TypeOf([]int64(nil))
-	
-	intBitsize uint8 = uint8(reflect.TypeOf(int(0)).Bits())
+	mapIntfIntfTyp   = reflect.TypeOf(map[interface{}]interface{}(nil))
+	timeTyp          = reflect.TypeOf(time.Time{})
+	ptrTimeTyp       = reflect.TypeOf((*time.Time)(nil))
+	int64SliceTyp    = reflect.TypeOf([]int64(nil))
+
+	intBitsize  uint8 = uint8(reflect.TypeOf(int(0)).Bits())
 	uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits())
 )
 
@@ -63,24 +63,31 @@ type encdecHandle struct {
 }
 
 func (o *encdecHandle) AddExt(
-	rt reflect.Type, 
-	tag byte, 
+	rt reflect.Type,
+	tag byte,
 	encfn func(reflect.Value) ([]byte, error),
-	decfn func(reflect.Value, []byte) (error),
+	decfn func(reflect.Value, []byte) error,
 ) {
 	o.addEncodeExt(rt, tag, encfn)
 	o.addDecodeExt(rt, tag, decfn)
 }
 
+// Handle is the interface for a specific encoding format.
+//
+// Typically, a Handle is pre-configured before first time use,
+// and not modified while in use. Such a pre-configured Handle
+// is safe for concurrent access.
 type Handle interface {
 	encodeHandleI
 	decodeHandleI
+	newEncDriver(w encWriter) encDriver
+	newDecDriver(r decReader) decDriver
 }
-	
+
 type structFieldInfo struct {
-	encName   string      // encode name
+	encName   string // encode name
 	is        []int
-	i         int16       // field index in struct
+	i         int16 // field index in struct
 	omitEmpty bool
 	// tag       string   // tag
 	// name      string   // field name
@@ -92,16 +99,16 @@ type structFieldInfos []structFieldInfo
 
 type sfiSortedByEncName []*structFieldInfo
 
-func (p sfiSortedByEncName) Len() int { 
-	return len(p) 
+func (p sfiSortedByEncName) Len() int {
+	return len(p)
 }
 
-func (p sfiSortedByEncName) Less(i, j int) bool { 
-	return p[i].encName < p[j].encName 
+func (p sfiSortedByEncName) Less(i, j int) bool {
+	return p[i].encName < p[j].encName
 }
 
-func (p sfiSortedByEncName) Swap(i, j int) { 
-	p[i], p[j] = p[j], p[i] 
+func (p sfiSortedByEncName) Swap(i, j int) {
+	p[i], p[j] = p[j], p[i]
 }
 
 func (sis structFieldInfos) indexForEncName(name string) int {
@@ -117,7 +124,7 @@ func (sis structFieldInfos) indexForEncName(name string) int {
 		// binary search. adapted from sort/search.go.
 		h, i, j := 0, 0, sislen
 		for i < j {
-			h = i + (j-i)/2 
+			h = i + (j-i)/2
 			// i ≤ h < j
 			if sis[h].encName < name {
 				i = h + 1 // preserves f(i-1) == false
@@ -137,12 +144,12 @@ func getStructFieldInfos(rt reflect.Type) (sis structFieldInfos) {
 	sis, ok := cachedStructFieldInfos[rt]
 	cachedStructFieldInfosMutex.RUnlock()
 	if ok {
-		return 
+		return
 	}
-	
+
 	cachedStructFieldInfosMutex.Lock()
 	defer cachedStructFieldInfosMutex.Unlock()
-	
+
 	var siInfo *structFieldInfo
 	if f, ok := rt.FieldByName(structInfoFieldName); ok {
 		siInfo = parseStructFieldInfo(structInfoFieldName, f.Tag.Get(structTagName))
@@ -161,7 +168,7 @@ func getStructFieldInfos(rt reflect.Type) (sis structFieldInfos) {
 	return
 }
 
-func rgetStructFieldInfos(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool, 
+func rgetStructFieldInfos(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
 	sis *[]*structFieldInfo, siInfo *structFieldInfo,
 ) {
 	for j := 0; j < rt.NumField(); j++ {
@@ -172,7 +179,7 @@ func rgetStructFieldInfos(rt reflect.Type, indexstack []int, fnameToHastag map[s
 		}
 		if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
 			continue
-		} 
+		}
 		if f.Anonymous {
 			//if anonymous, inline it if there is no struct tag, else treat as regular field
 			if stag == "" {
@@ -180,7 +187,7 @@ func rgetStructFieldInfos(rt reflect.Type, indexstack []int, fnameToHastag map[s
 				rgetStructFieldInfos(f.Type, indexstack2, fnameToHastag, sis, siInfo)
 				continue
 			}
-		} 
+		}
 		//do not let fields with same name in embedded structs override field at higher level.
 		//this must be done after anonymous check, to allow anonymous field still include their child fields
 		if _, ok := fnameToHastag[f.Name]; ok {
@@ -205,16 +212,16 @@ func rgetStructFieldInfos(rt reflect.Type, indexstack []int, fnameToHastag map[s
 	}
 }
 
-func parseStructFieldInfo(fname string, stag string) (*structFieldInfo) {
+func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
 	if fname == "" {
 		panic("parseStructFieldInfo: No Field Name")
 	}
-	si := structFieldInfo {
+	si := structFieldInfo{
 		// name: fname,
 		encName: fname,
 		// tag: stag,
-	}	
-	
+	}
+
 	if stag != "" {
 		for i, s := range strings.Split(stag, ",") {
 			if i == 0 {
@@ -233,22 +240,19 @@ func parseStructFieldInfo(fname string, stag string) (*structFieldInfo) {
 }
 
 func panicToErr(err *error) {
-	if x := recover(); x != nil { 
-		//debug.PrintStack() 
+	if x := recover(); x != nil {
+		//debug.PrintStack()
 		panicValToErr(x, err)
 	}
 }
 
 func doPanic(tag string, format string, params ...interface{}) {
-	params2 := make([]interface{}, len(params) + 1)
+	params2 := make([]interface{}, len(params)+1)
 	params2[0] = tag
 	copy(params2[1:], params)
-	panic(fmt.Errorf("%s: " + format, params2...))
+	panic(fmt.Errorf("%s: "+format, params2...))
 }
 
-
-
-
 //--------------------------------------------------
 
 // // This implements the util.Codec interface
@@ -271,4 +275,3 @@ func doPanic(tag string, format string, params ...interface{}) {
 // func (x Codec) DecodeBytes(in []byte, v interface{}) error {
 // 	return NewDecoderBytes(in, x.H).Decode(v)
 // }
-

+ 26 - 3
codec/helper_internal.go

@@ -7,14 +7,14 @@ package codec
 // so porting to different environment is easy (just update functions).
 
 import (
-	"reflect"
-	"fmt"
 	"errors"
+	"fmt"
+	"reflect"
 )
 
 var (
 	raisePanicAfterRecover = false
-	debugging = true
+	debugging              = true
 )
 
 func panicValToErr(panicVal interface{}, err *error) {
@@ -59,3 +59,26 @@ func debugf(format string, args ...interface{}) {
 	}
 }
 
+func pruneSignExt(v []byte) (n int) {
+	l := len(v)
+	if l < 2 {
+		return
+	}
+	if v[0] == 0 {
+		n2 := n + 1
+		for v[n] == 0 && n2 < l && (v[n2]&(1<<7) == 0) {
+			n++
+			n2++
+		}
+		return
+	}
+	if v[0] == 0xff {
+		n2 := n + 1
+		for v[n] == 0xff && n2 < l && (v[n2]&(1<<7) != 0) {
+			n++
+			n2++
+		}
+		return
+	}
+	return
+}

+ 115 - 121
codec/msgpack.go

@@ -4,44 +4,44 @@
 package codec
 
 import (
-	"reflect"
-	"math"
-	"time"
 	"fmt"
-	"net/rpc"
 	"io"
+	"math"
+	"net/rpc"
+	"reflect"
+	"time"
 )
 
 const (
 	mpPosFixNumMin byte = 0x00
-	mpPosFixNumMax = 0x7f
-	mpFixMapMin = 0x80
-	mpFixMapMax = 0x8f
-	mpFixArrayMin =  0x90
-	mpFixArrayMax =  0x9f
-	mpFixRawMin  = 0xa0
-	mpFixRawMax  = 0xbf
-	mpNil = 0xc0
-	mpFalse = 0xc2
-	mpTrue = 0xc3
-	mpFloat = 0xca
-	mpDouble = 0xcb
-	mpUint8 = 0xcc
-	mpUint16 = 0xcd
-	mpUint32 = 0xce
-	mpUint64 = 0xcf
-	mpInt8 = 0xd0
-	mpInt16 = 0xd1
-	mpInt32 = 0xd2
-	mpInt64 = 0xd3
-	mpRaw16 = 0xda
-	mpRaw32 = 0xdb
-	mpArray16 = 0xdc
-	mpArray32 = 0xdd
-	mpMap16 = 0xde
-	mpMap32 = 0xdf
-	mpNegFixNumMin = 0xe0
-	mpNegFixNumMax = 0xff
+	mpPosFixNumMax      = 0x7f
+	mpFixMapMin         = 0x80
+	mpFixMapMax         = 0x8f
+	mpFixArrayMin       = 0x90
+	mpFixArrayMax       = 0x9f
+	mpFixRawMin         = 0xa0
+	mpFixRawMax         = 0xbf
+	mpNil               = 0xc0
+	mpFalse             = 0xc2
+	mpTrue              = 0xc3
+	mpFloat             = 0xca
+	mpDouble            = 0xcb
+	mpUint8             = 0xcc
+	mpUint16            = 0xcd
+	mpUint32            = 0xce
+	mpUint64            = 0xcf
+	mpInt8              = 0xd0
+	mpInt16             = 0xd1
+	mpInt32             = 0xd2
+	mpInt64             = 0xd3
+	mpRaw16             = 0xda
+	mpRaw32             = 0xdb
+	mpArray16           = 0xdc
+	mpArray32           = 0xdd
+	mpMap16             = 0xde
+	mpMap32             = 0xdf
+	mpNegFixNumMin      = 0xe0
+	mpNegFixNumMax      = 0xff
 
 	// extensions below
 	// mpBin8 = 0xc4
@@ -64,31 +64,31 @@ const (
 	mpXv4Fixext4 = 0xc8
 	mpXv4Fixext5 = 0xc9
 
-	mpXv4Ext8m = 0xd4
+	mpXv4Ext8m  = 0xd4
 	mpXv4Ext16m = 0xd5
 	mpXv4Ext32m = 0xd6
-	mpXv4Ext8 = 0xd7
-	mpXv4Ext16 = 0xd8
-	mpXv4Ext32 = 0xd9
-)	
+	mpXv4Ext8   = 0xd7
+	mpXv4Ext16  = 0xd8
+	mpXv4Ext32  = 0xd9
+)
 
-// MsgpackSpecRpc implements Rpc using the communication protocol defined in 
+// MsgpackSpecRpc implements Rpc using the communication protocol defined in
 // the msgpack spec at http://wiki.msgpack.org/display/MSGPACK/RPC+specification
 var MsgpackSpecRpc msgpackSpecRpc
 
 // A MsgpackContainer type specifies the different types of msgpackContainers.
 type msgpackContainerType struct {
-	cutoff int8
+	cutoff     int8
 	b0, b1, b2 byte
 }
 
 var (
 	msgpackContainerRawBytes = msgpackContainerType{32, mpFixRawMin, mpRaw16, mpRaw32}
-	msgpackContainerList = msgpackContainerType{16, mpFixArrayMin, mpArray16, mpArray32}
-	msgpackContainerMap = msgpackContainerType{16, mpFixMapMin, mpMap16, mpMap32}
+	msgpackContainerList     = msgpackContainerType{16, mpFixArrayMin, mpArray16, mpArray32}
+	msgpackContainerMap      = msgpackContainerType{16, mpFixMapMin, mpMap16, mpMap32}
 )
 
-// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol 
+// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol
 // as defined in the msgpack spec at http://wiki.msgpack.org/display/MSGPACK/RPC+specification
 type msgpackSpecRpc struct{}
 
@@ -99,44 +99,44 @@ type msgpackSpecRpcCodec struct {
 //MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format.
 type MsgpackHandle struct {
 	// RawToString controls how raw bytes are decoded into a nil interface{}.
-	// Note that setting an extension func for []byte ensures that raw bytes 
-	// are decoded as strings, regardless of this setting. 
+	// Note that setting an extension func for []byte ensures that raw bytes
+	// are decoded as strings, regardless of this setting.
 	// This setting is used only if an extension func isn't defined for []byte.
 	RawToString bool
 	// WriteExt flag supports encoding configured extensions with extension tags.
-	// 
+	//
 	// With WriteExt=false, configured extensions are serialized as raw bytes.
-	// 
-	// They can still be decoded into a typed object, provided an appropriate one is 
+	//
+	// They can still be decoded into a typed object, provided an appropriate one is
 	// provided, but the type cannot be inferred from the stream. If no appropriate
 	// type is provided (e.g. decoding into a nil interface{}), you get back
 	// a []byte or string based on the setting of RawToString.
-	WriteExt bool	
+	WriteExt bool
 
 	encdecHandle
 	DecodeOptions
 }
 
-type msgpackEncoder struct { 
+type msgpackEncDriver struct {
 	w encWriter
 }
 
-type msgpackDecoder struct {
-	r decReader
-	bd byte
+type msgpackDecDriver struct {
+	r      decReader
+	bd     byte
 	bdRead bool
 }
 
-func (e *msgpackEncoder) encodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
+func (e *msgpackEncDriver) encodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
 	//no builtin types. All encodings are based on kinds. Types supported as extensions.
 	return false
 }
 
-func (e *msgpackEncoder) encodeNil() {
+func (e *msgpackEncDriver) encodeNil() {
 	e.w.writen1(mpNil)
 }
 
-func (e *msgpackEncoder) encodeInt(i int64) {
+func (e *msgpackEncDriver) encodeInt(i int64) {
 	switch {
 	case i >= -32 && i <= math.MaxInt8:
 		e.w.writen1(byte(i))
@@ -156,7 +156,7 @@ func (e *msgpackEncoder) encodeInt(i int64) {
 	}
 }
 
-func (e *msgpackEncoder) encodeUint(i uint64) {
+func (e *msgpackEncDriver) encodeUint(i uint64) {
 	// uints are not fixnums. fixnums are always signed.
 	// case i <= math.MaxInt8:
 	// 	e.w.writen1(byte(i))
@@ -175,7 +175,7 @@ func (e *msgpackEncoder) encodeUint(i uint64) {
 	}
 }
 
-func (e *msgpackEncoder) encodeBool(b bool) {
+func (e *msgpackEncDriver) encodeBool(b bool) {
 	if b {
 		e.w.writen1(mpTrue)
 	} else {
@@ -183,22 +183,22 @@ func (e *msgpackEncoder) encodeBool(b bool) {
 	}
 }
 
-func (e *msgpackEncoder) encodeFloat32(f float32) {
+func (e *msgpackEncDriver) encodeFloat32(f float32) {
 	e.w.writen1(mpFloat)
 	e.w.writeUint32(math.Float32bits(f))
 }
 
-func (e *msgpackEncoder) encodeFloat64(f float64) {
+func (e *msgpackEncDriver) encodeFloat64(f float64) {
 	e.w.writen1(mpDouble)
 	e.w.writeUint64(math.Float64bits(f))
 }
 
-func (e *msgpackEncoder) encodeExtPreamble(xtag byte, l int) {
+func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) {
 	switch {
 	case l <= 4:
-		e.w.writen2(0xd4 | byte(l), xtag)
+		e.w.writen2(0xd4|byte(l), xtag)
 	case l <= 8:
-		e.w.writen2(0xc0 | byte(l), xtag)
+		e.w.writen2(0xc0|byte(l), xtag)
 	case l < 256:
 		e.w.writen3(mpXv4Fixext5, xtag, byte(l))
 	case l < 65536:
@@ -210,36 +210,35 @@ func (e *msgpackEncoder) encodeExtPreamble(xtag byte, l int) {
 	}
 }
 
-func (e *msgpackEncoder) encodeArrayPreamble(length int) {
+func (e *msgpackEncDriver) encodeArrayPreamble(length int) {
 	e.writeContainerLen(msgpackContainerList, length)
 }
 
-
-func (e *msgpackEncoder) encodeMapPreamble(length int) {
-	e.writeContainerLen(msgpackContainerMap, length)	
+func (e *msgpackEncDriver) encodeMapPreamble(length int) {
+	e.writeContainerLen(msgpackContainerMap, length)
 }
 
-func (e *msgpackEncoder) encodeString(c charEncoding, s string) {
-	//ignore charEncoding. 
+func (e *msgpackEncDriver) encodeString(c charEncoding, s string) {
+	//ignore charEncoding.
 	e.writeContainerLen(msgpackContainerRawBytes, len(s))
 	if len(s) > 0 {
 		e.w.writestr(s)
 	}
 }
 
-func (e *msgpackEncoder) encodeSymbol(v string) { 
+func (e *msgpackEncDriver) encodeSymbol(v string) {
 	e.encodeString(c_UTF8, v)
 }
 
-func (e *msgpackEncoder) encodeStringBytes(c charEncoding, bs []byte) {
-	//ignore charEncoding. 
+func (e *msgpackEncDriver) encodeStringBytes(c charEncoding, bs []byte) {
+	//ignore charEncoding.
 	e.writeContainerLen(msgpackContainerRawBytes, len(bs))
 	if len(bs) > 0 {
 		e.w.writeb(bs)
 	}
 }
 
-func (e *msgpackEncoder) writeContainerLen(ct msgpackContainerType, l int) {
+func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
 	switch {
 	case l < int(ct.cutoff):
 		e.w.writen1(ct.b0 | byte(l))
@@ -254,19 +253,19 @@ func (e *msgpackEncoder) writeContainerLen(ct msgpackContainerType, l int) {
 
 //---------------------------------------------
 
-func (d *msgpackDecoder) decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool { 
+func (d *msgpackDecDriver) decodeBuiltinType(rt reflect.Type, rv reflect.Value) bool {
 	return false
 }
 
 // Note: This returns either a primitive (int, bool, etc) for non-containers,
-// or a containerType, or a specific type denoting nil or extension. 
-// It is called when a nil interface{} is passed, leaving it up to the Decoder
+// or a containerType, or a specific type denoting nil or extension.
+// It is called when a nil interface{} is passed, leaving it up to the DecDriver
 // to introspect the stream and decide how best to decode.
 // It deciphers the value by looking at the stream first.
-func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decodeNakedContext) {
+func (d *msgpackDecDriver) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx decodeNakedContext) {
 	d.initReadNext()
 	bd := d.bd
-	
+
 	var v interface{}
 
 	switch bd {
@@ -282,7 +281,7 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 		v = float64(math.Float32frombits(d.r.readUint32()))
 	case mpDouble:
 		v = math.Float64frombits(d.r.readUint64())
-		
+
 	case mpUint8:
 		v = uint64(d.r.readn1())
 	case mpUint16:
@@ -291,7 +290,7 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 		v = uint64(d.r.readUint32())
 	case mpUint64:
 		v = uint64(d.r.readUint64())
-		
+
 	case mpInt8:
 		v = int64(int8(d.r.readn1()))
 	case mpInt16:
@@ -300,7 +299,7 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 		v = int64(int32(d.r.readUint32()))
 	case mpInt64:
 		v = int64(int64(d.r.readUint64()))
-		
+
 	default:
 		switch {
 		case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
@@ -308,7 +307,7 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 			v = int64(int8(bd))
 		case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
 			// negative fixnum
-			v = int64(int8(bd))		
+			v = int64(int8(bd))
 		case bd == mpRaw16, bd == mpRaw32, bd >= mpFixRawMin && bd <= mpFixRawMax:
 			ctx = dncContainer
 			// v = containerRawBytes
@@ -352,7 +351,7 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 			}
 			if fnerr := bfn(rv, d.r.readn(d.readExtLen())); fnerr != nil {
 				panic(fnerr)
-			} 
+			}
 		default:
 			decErr("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
 		}
@@ -366,8 +365,8 @@ func (d *msgpackDecoder) decodeNaked(h decodeHandleI) (rv reflect.Value, ctx dec
 	return
 }
 
-// int can be decoded from msgpack type: intXXX or uintXXX 
-func (d *msgpackDecoder) decodeInt(bitsize uint8) (i int64) {
+// int can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) decodeInt(bitsize uint8) (i int64) {
 	switch d.bd {
 	case mpUint8:
 		i = int64(uint64(d.r.readn1()))
@@ -405,9 +404,8 @@ func (d *msgpackDecoder) decodeInt(bitsize uint8) (i int64) {
 	return
 }
 
-
-// uint can be decoded from msgpack type: intXXX or uintXXX 
-func (d *msgpackDecoder) decodeUint(bitsize uint8) (ui uint64) {
+// uint can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) decodeUint(bitsize uint8) (ui uint64) {
 	switch d.bd {
 	case mpUint8:
 		ui = uint64(d.r.readn1())
@@ -454,7 +452,7 @@ func (d *msgpackDecoder) decodeUint(bitsize uint8) (ui uint64) {
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	if bitsize > 0 {
 		if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
-			decErr("Overflow uint value: %v", ui) 
+			decErr("Overflow uint value: %v", ui)
 		}
 	}
 	d.bdRead = false
@@ -462,7 +460,7 @@ func (d *msgpackDecoder) decodeUint(bitsize uint8) (ui uint64) {
 }
 
 // float can either be decoded from msgpack type: float, double or intX
-func (d *msgpackDecoder) decodeFloat(chkOverflow32 bool) (f float64) {
+func (d *msgpackDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
 	switch d.bd {
 	case mpFloat:
 		f = float64(math.Float32frombits(d.r.readUint32()))
@@ -486,7 +484,7 @@ func (d *msgpackDecoder) decodeFloat(chkOverflow32 bool) (f float64) {
 }
 
 // bool can be decoded from bool, fixnum 0 or 1.
-func (d *msgpackDecoder) decodeBool() (b bool) {
+func (d *msgpackDecDriver) decodeBool() (b bool) {
 	switch d.bd {
 	case mpFalse, 0:
 		// b = false
@@ -498,8 +496,8 @@ func (d *msgpackDecoder) decodeBool() (b bool) {
 	d.bdRead = false
 	return
 }
-	
-func (d *msgpackDecoder) decodeString() (s string) {
+
+func (d *msgpackDecDriver) decodeString() (s string) {
 	clen := d.readContainerLen(msgpackContainerRawBytes)
 	if clen > 0 {
 		s = string(d.r.readn(clen))
@@ -509,14 +507,14 @@ func (d *msgpackDecoder) decodeString() (s string) {
 }
 
 // Callers must check if changed=true (to decide whether to replace the one they have)
-func (d *msgpackDecoder) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
+func (d *msgpackDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
 	clen := d.readContainerLen(msgpackContainerRawBytes)
 	// if clen < 0 {
 	// 	changed = true
 	// 	panic("length cannot be zero. this cannot be nil.")
-	// } 
+	// }
 	if clen > 0 {
-		// if no contents in stream, don't update the passed byteslice	
+		// if no contents in stream, don't update the passed byteslice
 		if len(bs) != clen {
 			// Return changed=true if length of passed slice is different from length of bytes in the stream.
 			if len(bs) > clen {
@@ -534,7 +532,7 @@ func (d *msgpackDecoder) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
 }
 
 // Every top-level decode funcs (i.e. decodeValue, decode) must call this first.
-func (d *msgpackDecoder) initReadNext() {
+func (d *msgpackDecDriver) initReadNext() {
 	if d.bdRead {
 		return
 	}
@@ -542,15 +540,15 @@ func (d *msgpackDecoder) initReadNext() {
 	d.bdRead = true
 }
 
-func (d *msgpackDecoder) currentIsNil() bool {
+func (d *msgpackDecDriver) currentIsNil() bool {
 	if d.bd == mpNil {
 		d.bdRead = false
 		return true
-	} 
+	}
 	return false
 }
 
-func (d *msgpackDecoder) readContainerLen(ct msgpackContainerType) (clen int) {
+func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) {
 	switch {
 	case d.bd == mpNil:
 		clen = -1 // to represent nil
@@ -564,19 +562,18 @@ func (d *msgpackDecoder) readContainerLen(ct msgpackContainerType) (clen int) {
 		decErr("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, d.bd, d.bd)
 	}
 	d.bdRead = false
-	return	
+	return
 }
 
-func (d *msgpackDecoder) readMapLen() int {
+func (d *msgpackDecDriver) readMapLen() int {
 	return d.readContainerLen(msgpackContainerMap)
 }
 
-func (d *msgpackDecoder) readArrayLen() int {
+func (d *msgpackDecDriver) readArrayLen() int {
 	return d.readContainerLen(msgpackContainerList)
 }
 
-
-func (d *msgpackDecoder) readExtLen() (clen int) {
+func (d *msgpackDecDriver) readExtLen() (clen int) {
 	switch d.bd {
 	case mpNil:
 		clen = -1 // to represent nil
@@ -586,7 +583,7 @@ func (d *msgpackDecoder) readExtLen() (clen int) {
 		clen = int(d.r.readUint16())
 	case mpXv4Ext32:
 		clen = int(d.r.readUint32())
-	default: 
+	default:
 		switch {
 		case d.bd >= mpXv4Fixext0 && d.bd <= mpXv4Fixext4:
 			clen = int(d.bd & 0x0f)
@@ -599,7 +596,7 @@ func (d *msgpackDecoder) readExtLen() (clen int) {
 	return
 }
 
-func (d *msgpackDecoder) decodeExt(tag byte) (xbs []byte) {
+func (d *msgpackDecDriver) decodeExt(tag byte) (xbs []byte) {
 	// if (d.bd >= mpXv4Fixext0 && d.bd <= mpXv4Fixext5) || (d.bd >= mpXv4Ext8m && d.bd <= mpXv4Ext32) {
 	xbd := d.bd
 	switch {
@@ -612,19 +609,19 @@ func (d *msgpackDecoder) decodeExt(tag byte) (xbs []byte) {
 		xbs, _ = d.decodeBytes(nil)
 	default:
 		decErr("Wrong byte descriptor (Expecting extensions or raw bytes). Got: 0x%x", xbd)
-	}		
+	}
 	d.bdRead = false
 	return
 }
 
 //--------------------------------------------------
 
-func (msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) (rpc.ServerCodec) {
-	return &msgpackSpecRpcCodec{ newRPCCodec(conn, h) }
+func (msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+	return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
 }
 
-func (msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) (rpc.ClientCodec) {
-	return &msgpackSpecRpcCodec{ newRPCCodec(conn, h) }
+func (msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+	return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
 }
 
 // /////////////// Spec RPC Codec ///////////////////
@@ -646,13 +643,13 @@ func (c msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error {
 
 func (c msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
 
-	// We read the response header by hand 
+	// We read the response header by hand
 	// so that the body can be decoded on its own from the stream at a later time.
 
 	bs := make([]byte, 1)
 	n, err := c.rwc.Read(bs)
 	if err != nil {
-		return 
+		return
 	}
 	if n != 1 {
 		err = fmt.Errorf("Couldn't read array descriptor: No bytes read")
@@ -685,12 +682,10 @@ func (c msgpackSpecRpcCodec) writeCustomBody(typeByte byte, msgid uint64, method
 			body = nil
 		}
 	}
-	r2 := []interface{}{ typeByte, uint32(msgid), moe, body }
+	r2 := []interface{}{typeByte, uint32(msgid), moe, body}
 	return c.enc.Encode(r2)
 }
 
-
-
 //--------------------------------------------------
 
 // EncodeBinaryExt returns the underlying bytes of this value AS-IS.
@@ -724,15 +719,14 @@ func (_ *MsgpackHandle) TimeDecodeExt(rv reflect.Value, bs []byte) (err error) {
 	return
 }
 
-func (_ *MsgpackHandle) newEncoder(w encWriter) encoder {
-	return &msgpackEncoder{w: w}
+func (_ *MsgpackHandle) newEncDriver(w encWriter) encDriver {
+	return &msgpackEncDriver{w: w}
 }
 
-func (_ *MsgpackHandle) newDecoder(r decReader) decoder {
-	return &msgpackDecoder{r: r}
+func (_ *MsgpackHandle) newDecDriver(r decReader) decDriver {
+	return &msgpackDecDriver{r: r}
 }
 
 func (o *MsgpackHandle) writeExt() bool {
 	return o.WriteExt
 }
-

+ 15 - 16
codec/rpc.go

@@ -5,13 +5,13 @@
 RPC
 
 RPC Client and Server Codecs are implemented, so the codecs can be used
-with the standard net/rpc package. 
+with the standard net/rpc package.
 */
 package codec
 
 import (
-	"net/rpc"
 	"io"
+	"net/rpc"
 )
 
 // GoRpc implements Rpc using the communication protocol defined in net/rpc package.
@@ -19,33 +19,33 @@ var GoRpc goRpc
 
 // Rpc interface provides a rpc Server or Client Codec for rpc communication.
 type Rpc interface {
-	ServerCodec(conn io.ReadWriteCloser, h Handle) (rpc.ServerCodec) 
-	ClientCodec(conn io.ReadWriteCloser, h Handle) (rpc.ClientCodec)
+	ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec
+	ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec
 }
 
 type rpcCodec struct {
-	rwc       io.ReadWriteCloser
-	dec       *Decoder
-	enc       *Encoder
+	rwc io.ReadWriteCloser
+	dec *Decoder
+	enc *Encoder
 }
 
 type goRpcCodec struct {
 	rpcCodec
 }
 
-// goRpc is the implementation of Rpc that uses the communication protocol 
+// goRpc is the implementation of Rpc that uses the communication protocol
 // as defined in net/rpc package.
-type goRpc struct {}
+type goRpc struct{}
 
-func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) (rpc.ServerCodec) {
-	return goRpcCodec { newRPCCodec(conn, h) }
+func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+	return goRpcCodec{newRPCCodec(conn, h)}
 }
 
-func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) (rpc.ClientCodec) {
-	return goRpcCodec { newRPCCodec(conn, h) }
+func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+	return goRpcCodec{newRPCCodec(conn, h)}
 }
 
-func newRPCCodec(conn io.ReadWriteCloser, h Handle) (rpcCodec) {
+func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
 	return rpcCodec{
 		rwc: conn,
 		dec: NewDecoder(conn, h),
@@ -79,7 +79,7 @@ func (c rpcCodec) read(objs ...interface{}) (err error) {
 }
 
 func (c rpcCodec) Close() error {
-	return c.rwc.Close()	
+	return c.rwc.Close()
 }
 
 func (c rpcCodec) ReadResponseBody(body interface{}) (err error) {
@@ -108,4 +108,3 @@ func (c goRpcCodec) ReadResponseHeader(r *rpc.Response) (err error) {
 func (c goRpcCodec) ReadRequestHeader(r *rpc.Request) error {
 	return c.read(r)
 }
-

+ 122 - 0
codec/time.go

@@ -0,0 +1,122 @@
+// 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.
+
+package codec
+
+import (
+	"time"
+)
+
+// encodeTime encodes a time.Time as a []byte, including
+// information on the instant in time and UTC offset.
+func encodeTime(t time.Time) []byte {
+	//t := rv.Interface().(time.Time)
+	tsecs, tnsecs := t.Unix(), t.Nanosecond()
+	var (
+		bd   byte
+		btmp [8]byte
+		bs   [16]byte
+		i    int = 1
+	)
+	l := t.Location()
+	if l == time.UTC {
+		l = nil
+	}
+	if tsecs != 0 {
+		bd = bd | 0x80
+		bigen.PutUint64(btmp[:], uint64(tsecs))
+		f := pruneSignExt(btmp[:])
+		bd = bd | (byte(7-f) << 2)
+		copy(bs[i:], btmp[f:])
+		i = i + (8 - f)
+	}
+	if tnsecs != 0 {
+		bd = bd | 0x40
+		bigen.PutUint32(btmp[:4], uint32(tnsecs))
+		f := pruneSignExt(btmp[:4])
+		bd = bd | byte(3-f)
+		copy(bs[i:], btmp[f:4])
+		i = i + (4 - f)
+	}
+	if l != nil {
+		bd = bd | 0x20
+		// Note that Go Libs do not give access to dst flag.
+		_, zoneOffset := t.Zone()
+		//zoneName, zoneOffset := t.Zone()
+		zoneOffset /= 60
+		z := uint16(zoneOffset)
+		bigen.PutUint16(btmp[:2], z)
+		// clear dst flags
+		bs[i] = btmp[0] & 0x3f
+		bs[i+1] = btmp[1]
+		i = i + 2
+	}
+	bs[0] = bd
+	return bs[0:i]
+}
+
+// decodeTime decodes a []byte into a time.Time,
+// and sets into passed reflectValue.
+func decodeTime(bs []byte) (tt time.Time, err error) {
+	bd := bs[0]
+	var (
+		tsec  int64
+		tnsec uint32
+		tz    uint16
+		i     byte = 1
+		i2    byte
+		n     byte
+	)
+	if bd&(1<<7) != 0 {
+		var btmp [8]byte
+		n = ((bd >> 2) & 0x7) + 1
+		i2 = i + n
+		copy(btmp[8-n:], bs[i:i2])
+		i = i2
+		tsec = int64(bigen.Uint64(btmp[:]))
+	}
+	if bd&(1<<6) != 0 {
+		var btmp [4]byte
+		n = (bd & 0x3) + 1
+		i2 = i + n
+		copy(btmp[4-n:], bs[i:i2])
+		i = i2
+		tnsec = bigen.Uint32(btmp[:])
+	}
+	if bd&(1<<5) == 0 {
+		tt = time.Unix(tsec, int64(tnsec)).UTC()
+		return
+	}
+	// In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name.
+	// However, we need name here, so it can be shown when time is printed.
+	// Zone name is in form: UTC-08:00.
+	// Note that Go Libs do not give access to dst flag, so we ignore dst bits
+
+	i2 = i + 2
+	tz = bigen.Uint16(bs[i:i2])
+	i = i2
+	var tzname = []byte("UTC+00:00")
+	// sign extend sign bit into top 2 MSB (which were dst bits):
+	if tz&(1<<13) == 0 { // positive
+		tz = tz & 0x3fff //clear 2 MSBs: dst bits
+	} else { // negative
+		tz = tz | 0xc000 //set 2 MSBs: dst bits
+		tzname[3] = '-'
+	}
+	tzint := (int16(tz))
+	//tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
+	//tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
+	var tzhr, tzmin int16
+	if tzint < 0 {
+		tzhr, tzmin = -tzint/60, (-tzint)%60
+	} else {
+		tzhr, tzmin = tzint/60, tzint%60
+	}
+	tzname[4] = digits[tzhr/10]
+	tzname[5] = digits[tzhr%10]
+	tzname[7] = digits[tzmin/10]
+	tzname[8] = digits[tzmin%10]
+
+	tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone(string(tzname), int(tzint)*60))
+	return
+}

+ 9 - 10
codec/z_helper_test.go

@@ -5,18 +5,18 @@ package codec
 
 // All non-std package dependencies related to testing live in this file,
 // so porting to different environment is easy (just update functions).
-// 
+//
 // Also, this file is called z_helper_test, to give a "hint" to compiler
 // that its init() function should be called last. (not guaranteed by spec)
 
 import (
-	"testing"
-	"reflect"
 	"errors"
+	"reflect"
+	"testing"
 )
 
 var (
-	testLogToT = true
+	testLogToT    = true
 	failNowOnFail = true
 )
 
@@ -33,7 +33,7 @@ func checkErrT(t *testing.T, err error) {
 }
 
 func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}) {
-	if err := deepEqual(v1, v2); err != nil { 
+	if err := deepEqual(v1, v2); err != nil {
 		logT(t, "Do not match: %v. v1: %v, v2: %v", err, v1, v2)
 		failT(t)
 	}
@@ -41,7 +41,7 @@ func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}) {
 
 func logT(x interface{}, format string, args ...interface{}) {
 	if t, ok := x.(*testing.T); ok && t != nil && testLogToT {
-		t.Logf(format, args...)	
+		t.Logf(format, args...)
 	} else if b, ok := x.(*testing.B); ok && b != nil && testLogToT {
 		b.Logf(format, args...)
 	} else {
@@ -76,10 +76,10 @@ func approxDataSize(rv reflect.Value) (sum int) {
 			sum += approxDataSize(rv.Index(j))
 		}
 	case reflect.String:
-		sum += int(rv.Type().Size()) 
+		sum += int(rv.Type().Size())
 		sum += rv.Len()
 	case reflect.Map:
-		sum += int(rv.Type().Size()) 
+		sum += int(rv.Type().Size())
 		for _, mk := range rv.MapKeys() {
 			sum += approxDataSize(mk)
 			sum += approxDataSize(rv.MapIndex(mk))
@@ -89,11 +89,10 @@ func approxDataSize(rv reflect.Value) (sum int) {
 		//sum += int(rv.Type().Size())
 		for j := 0; j < rv.NumField(); j++ {
 			sum += approxDataSize(rv.Field(j))
-		}	
+		}
 	default:
 		//pure value types
 		sum += int(rv.Type().Size())
 	}
 	return
 }
-