Преглед изворни кода

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 година
родитељ
комит
9966a02b69
14 измењених фајлова са 851 додато и 855 уклоњено
  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
 }
-