Browse Source

codec: error handling cleanup, and unsafe build tag.

This package understands the 'unsafe' tag, to allow using unsafe semantics:

  - When decoding into a struct, you need to read the field name as a string
    so you can find the struct field it is mapped to.
    Using `unsafe` will bypass the allocation and copying overhead of []byte->string conversion.

To install using unsafe, pass the 'unsafe' tag:

    go get -tags=unsafe github.com/ugorji/go/codec

Also, we cleaned up error handling so that an error implementation is always
used, and the error values could be shared if constant (i.e. use a var to keep
single instance instead of creating a new error value each time).

In addition, we now make error a method of Decoder and Encoder, setting the stage
for possibly moving away from panics to manage internal error propagation.
Note: I eventually decided not to do this (see comments in helper.go).
Ugorji Nwoke 11 years ago
parent
commit
b5e234a12e
15 changed files with 503 additions and 257 deletions
  1. 10 0
      codec/0doc.go
  2. 12 0
      codec/README.md
  3. 59 35
      codec/binc.go
  4. 40 26
      codec/cbor.go
  5. 2 2
      codec/codec_test.go
  6. 70 39
      codec/decode.go
  7. 27 17
      codec/encode.go
  8. 36 23
      codec/gen.go
  9. 33 12
      codec/helper.go
  10. 20 0
      codec/helper_not_unsafe.go
  11. 39 0
      codec/helper_unsafe.go
  12. 68 47
      codec/json.go
  13. 42 27
      codec/msgpack.go
  14. 4 4
      codec/noop.go
  15. 41 25
      codec/simple.go

+ 10 - 0
codec/0doc.go

@@ -17,6 +17,16 @@ To install:
 
     go get github.com/ugorji/go/codec
 
+This package understands the 'unsafe' tag, to allow using unsafe semantics:
+
+  - When decoding into a struct, you need to read the field name as a string 
+    so you can find the struct field it is mapped to.
+    Using `unsafe` will bypass the allocation and copying overhead of []byte->string conversion.
+
+To install using unsafe, pass the 'unsafe' tag:
+
+    go get -tags=unsafe github.com/ugorji/go/codec
+
 For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .
 
 The idiomatic Go support is as seen in other encoding packages in

+ 12 - 0
codec/README.md

@@ -15,6 +15,18 @@ To install:
 
     go get github.com/ugorji/go/codec
 
+This package understands the `unsafe` tag, to allow using unsafe semantics:
+
+  - When decoding into a struct, you need to read the field name as a string 
+    so you can find the struct field it is mapped to.
+    Using `unsafe` will bypass the allocation and copying overhead of `[]byte->string` conversion.
+
+To use it, you must pass the `unsafe` tag during install:
+
+```
+go install -tags=unsafe github.com/ugorji/go/codec 
+```
+
 Online documentation: http://godoc.org/github.com/ugorji/go/codec  
 Detailed Usage/How-to Primer: http://ugorji.net/blog/go-codec-primer
 

+ 59 - 35
codec/binc.go

@@ -55,6 +55,7 @@ const (
 )
 
 type bincEncDriver struct {
+	e *Encoder
 	w encWriter
 	m map[string]uint16 // symbols
 	s uint16            // symbols sequencer
@@ -314,6 +315,7 @@ type bincDecSymbol struct {
 }
 
 type bincDecDriver struct {
+	d      *Decoder
 	h      *BincHandle
 	r      decReader
 	br     bool // bytes reader
@@ -352,8 +354,8 @@ func (d *bincDecDriver) IsContainerType(vt valueType) (b bool) {
 	case valueTypeMap:
 		return d.vd == bincVdMap
 	}
-	decErr("isContainerType: unsupported parameter: %v", vt)
-	panic("unreachable")
+	d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+	return // "unreachable"
 }
 
 func (d *bincDecDriver) TryDecodeAsNil() bool {
@@ -377,7 +379,8 @@ func (d *bincDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {
 	}
 	if rt == timeTypId {
 		if d.vd != bincVdTimestamp {
-			decErr("Invalid d.vd. Expecting 0x%x. Received: 0x%x", bincVdTimestamp, d.vd)
+			d.d.errorf("Invalid d.vd. Expecting 0x%x. Received: 0x%x", bincVdTimestamp, d.vd)
+			return
 		}
 		tt, err := decodeTime(d.r.readx(int(d.vs)))
 		if err != nil {
@@ -395,7 +398,8 @@ func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
 	} else {
 		l := d.r.readn1()
 		if l > 8 {
-			decErr("At most 8 bytes used to represent float. Received: %v bytes", l)
+			d.d.errorf("At most 8 bytes used to represent float. Received: %v bytes", l)
+			return
 		}
 		for i := l; i < 8; i++ {
 			d.b[i] = 0
@@ -413,7 +417,8 @@ func (d *bincDecDriver) decFloat() (f float64) {
 		d.decFloatPre(d.vs, 8)
 		f = math.Float64frombits(bigen.Uint64(d.b[0:8]))
 	} else {
-		decErr("only float32 and float64 are supported. d.vd: 0x%x, d.vs: 0x%x", d.vd, d.vs)
+		d.d.errorf("only float32 and float64 are supported. d.vd: 0x%x, d.vs: 0x%x", d.vd, d.vs)
+		return
 	}
 	return
 }
@@ -444,7 +449,8 @@ func (d *bincDecDriver) decUint() (v uint64) {
 		d.r.readb(d.b[:8])
 		v = uint64(bigen.Uint64(d.b[:8]))
 	default:
-		decErr("unsigned integers with greater than 64 bits of precision not supported")
+		d.d.errorf("unsigned integers with greater than 64 bits of precision not supported")
+		return
 	}
 	return
 }
@@ -468,10 +474,12 @@ func (d *bincDecDriver) decCheckInteger() (ui uint64, neg bool) {
 			neg = true
 			ui = 1
 		} else {
-			decErr("numeric decode fails for special value: d.vs: 0x%x", d.vs)
+			d.d.errorf("numeric decode fails for special value: d.vs: 0x%x", d.vs)
+			return
 		}
 	} else {
-		decErr("number can only be decoded from uint or int values. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd)
+		d.d.errorf("number can only be decoded from uint or int values. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd)
+		return
 	}
 	return
 }
@@ -480,13 +488,15 @@ func (d *bincDecDriver) DecodeInt(bitsize uint8) (i int64) {
 	ui, neg := d.decCheckInteger()
 	i, overflow := chkOvf.SignedInt(ui)
 	if overflow {
-		decErr("simple: overflow converting %v to signed integer", ui)
+		d.d.errorf("simple: overflow converting %v to signed integer", ui)
+		return
 	}
 	if neg {
 		i = -i
 	}
 	if chkOvf.Int(i, bitsize) {
-		decErr("binc: overflow integer: %v", i)
+		d.d.errorf("binc: overflow integer: %v", i)
+		return
 	}
 	d.bdRead = false
 	return
@@ -495,10 +505,12 @@ func (d *bincDecDriver) DecodeInt(bitsize uint8) (i int64) {
 func (d *bincDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	ui, neg := d.decCheckInteger()
 	if neg {
-		decErr("Assigning negative signed value to unsigned type")
+		d.d.errorf("Assigning negative signed value to unsigned type")
+		return
 	}
 	if chkOvf.Uint(ui, bitsize) {
-		decErr("binc: overflow integer: %v", ui)
+		d.d.errorf("binc: overflow integer: %v", ui)
+		return
 	}
 	d.bdRead = false
 	return
@@ -520,7 +532,8 @@ func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 		} else if vs == bincSpNegInf {
 			return math.Inf(-1)
 		} else {
-			decErr("Invalid d.vs decoding float where d.vd=bincVdSpecial: %v", d.vs)
+			d.d.errorf("Invalid d.vs decoding float where d.vd=bincVdSpecial: %v", d.vs)
+			return
 		}
 	} else if vd == bincVdFloat {
 		f = d.decFloat()
@@ -528,7 +541,8 @@ func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 		f = float64(d.DecodeInt(64))
 	}
 	if chkOverflow32 && chkOvf.Float32(f) {
-		decErr("binc: float32 overflow: %v", f)
+		d.d.errorf("binc: float32 overflow: %v", f)
+		return
 	}
 	d.bdRead = false
 	return
@@ -544,7 +558,8 @@ func (d *bincDecDriver) DecodeBool() (b bool) {
 	} else if bd == (bincVdSpecial | bincSpTrue) {
 		b = true
 	} else {
-		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		return
 	}
 	d.bdRead = false
 	return
@@ -552,7 +567,8 @@ func (d *bincDecDriver) DecodeBool() (b bool) {
 
 func (d *bincDecDriver) ReadMapStart() (length int) {
 	if d.vd != bincVdMap {
-		decErr("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd)
+		d.d.errorf("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd)
+		return
 	}
 	length = d.decLen()
 	d.bdRead = false
@@ -561,7 +577,8 @@ func (d *bincDecDriver) ReadMapStart() (length int) {
 
 func (d *bincDecDriver) ReadArrayStart() (length int) {
 	if d.vd != bincVdArray {
-		decErr("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd)
+		d.d.errorf("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd)
+		return
 	}
 	length = d.decLen()
 	d.bdRead = false
@@ -628,7 +645,6 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
 		//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 {
 			symbol = uint16(d.r.readn1())
 		} else {
@@ -663,23 +679,26 @@ func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool)
 			case 3:
 				slen = int(bigen.Uint64(d.r.readx(8)))
 			}
-			bs2 = decByteSlice(d.r, slen, bs)
+			// since using symbols, do not store any part of
+			// the parameter bs in the map, as it might be a shared buffer.
+			// bs2 = decByteSlice(d.r, slen, bs)
+			bs2 = decByteSlice(d.r, slen, nil)
 			if withString {
 				s = string(bs2)
 			}
 			d.s = append(d.s, bincDecSymbol{symbol, s, bs2})
 		}
 	default:
-		decErr("Invalid d.vd. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x",
+		d.d.errorf("Invalid d.vd. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x",
 			bincVdString, bincVdByteArray, bincVdSymbol, d.vd)
+		return
 	}
 	d.bdRead = false
 	return
 }
 
 func (d *bincDecDriver) DecodeString() (s string) {
-	// using DecodeBytes does not allow for symbols, for which
-	// string version may be in the map.
+	// DecodeBytes does not accomodate symbols, whose impl stores string version in map.
 	// Use decStringAndBytes directly.
 	// return string(d.DecodeBytes(d.b[:], true, true))
 	_, s = d.decStringAndBytes(d.b[:], true, true)
@@ -702,8 +721,9 @@ func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
 	if d.vd == bincVdString || d.vd == bincVdByteArray {
 		clen = d.decLen()
 	} else {
-		decErr("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x",
+		d.d.errorf("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x",
 			bincVdString, bincVdByteArray, d.vd)
+		return
 	}
 	d.bdRead = false
 	if zerocopy {
@@ -716,9 +736,10 @@ func (d *bincDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut [
 	return decByteSlice(d.r, clen, bs)
 }
 
-func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, _ *Decoder) (realxtag uint64) {
+func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
 	if xtag > 0xff {
-		decErr("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		return
 	}
 	realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
 	realxtag = uint64(realxtag1)
@@ -740,19 +761,21 @@ func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []b
 		l := d.decLen()
 		xtag = d.r.readn1()
 		if verifyTag && xtag != tag {
-			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			return
 		}
 		xbs = d.r.readx(l)
 	} else if d.vd == bincVdByteArray {
 		xbs = d.DecodeBytes(nil, false, true)
 	} else {
-		decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd)
+		d.d.errorf("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd)
+		return
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *bincDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (d *bincDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -787,7 +810,8 @@ func (d *bincDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType, de
 			vt = valueTypeInt
 			v = int64(-1) // int8(-1)
 		default:
-			decErr("decodeNaked: Unrecognized special value 0x%x", d.vs)
+			d.d.errorf("decodeNaked: Unrecognized special value 0x%x", d.vs)
+			return
 		}
 	case bincVdSmallInt:
 		vt = valueTypeUint
@@ -832,7 +856,8 @@ func (d *bincDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType, de
 		vt = valueTypeMap
 		decodeFurther = true
 	default:
-		decErr("decodeNaked: Unrecognized d.vd: 0x%x", d.vd)
+		d.d.errorf("decodeNaked: Unrecognized d.vd: 0x%x", d.vd)
+		return
 	}
 
 	if !decodeFurther {
@@ -864,13 +889,12 @@ type BincHandle struct {
 	binaryEncodingType
 }
 
-func (h *BincHandle) newEncDriver(w encWriter) encDriver {
-	return &bincEncDriver{w: w}
+func (h *BincHandle) newEncDriver(e *Encoder) encDriver {
+	return &bincEncDriver{e: e, w: e.w}
 }
 
-func (h *BincHandle) newDecDriver(r decReader) decDriver {
-	_, ok := r.(*bytesDecReader)
-	return &bincDecDriver{r: r, h: h, br: ok}
+func (h *BincHandle) newDecDriver(d *Decoder) decDriver {
+	return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes}
 }
 
 var _ decDriver = (*bincDecDriver)(nil)

+ 40 - 26
codec/cbor.go

@@ -57,6 +57,7 @@ const (
 // -------------------
 
 type cborEncDriver struct {
+	e *Encoder
 	w encWriter
 	h *CborHandle
 	noBuiltInTypes
@@ -164,6 +165,7 @@ func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 // ----------------------
 
 type cborDecDriver struct {
+	d      *Decoder
 	h      *CborHandle
 	r      decReader
 	br     bool // bytes reader
@@ -181,7 +183,7 @@ func (d *cborDecDriver) readNextBd() {
 	d.bdType = valueTypeUnset
 }
 
-func (d *cborDecDriver) IsContainerType(vt valueType) bool {
+func (d *cborDecDriver) IsContainerType(vt valueType) (bv bool) {
 	switch vt {
 	case valueTypeNil:
 		return d.bd == cborBdNil
@@ -194,8 +196,8 @@ func (d *cborDecDriver) IsContainerType(vt valueType) bool {
 	case valueTypeMap:
 		return d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag)
 	}
-	decErr("isContainerType: unsupported parameter: %v", vt)
-	panic("unreachable")
+	d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+	return // "unreachable"
 }
 
 func (d *cborDecDriver) TryDecodeAsNil() bool {
@@ -235,7 +237,8 @@ func (d *cborDecDriver) decUint() (ui uint64) {
 		} else if v == 0x1b {
 			ui = uint64(bigen.Uint64(d.r.readx(8)))
 		} else {
-			decErr("decUint: Invalid descriptor: %v", d.bd)
+			d.d.errorf("decUint: Invalid descriptor: %v", d.bd)
+			return
 		}
 	}
 	return
@@ -250,7 +253,8 @@ func (d *cborDecDriver) decCheckInteger() (neg bool) {
 	} else if major == cborMajorNegInt {
 		neg = true
 	} else {
-		decErr("invalid major: %v (bd: %v)", major, d.bd)
+		d.d.errorf("invalid major: %v (bd: %v)", major, d.bd)
+		return
 	}
 	return
 }
@@ -262,16 +266,19 @@ func (d *cborDecDriver) DecodeInt(bitsize uint8) (i int64) {
 	var overflow bool
 	if neg {
 		if i, overflow = chkOvf.SignedInt(ui + 1); overflow {
-			decErr("cbor: overflow converting %v to signed integer", ui+1)
+			d.d.errorf("cbor: overflow converting %v to signed integer", ui+1)
+			return
 		}
 		i = -i
 	} else {
 		if i, overflow = chkOvf.SignedInt(ui); overflow {
-			decErr("cbor: overflow converting %v to signed integer", ui)
+			d.d.errorf("cbor: overflow converting %v to signed integer", ui)
+			return
 		}
 	}
 	if chkOvf.Int(i, bitsize) {
-		decErr("cbor: overflow integer: %v", i)
+		d.d.errorf("cbor: overflow integer: %v", i)
+		return
 	}
 	d.bdRead = false
 	return
@@ -279,11 +286,13 @@ func (d *cborDecDriver) DecodeInt(bitsize uint8) (i int64) {
 
 func (d *cborDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	if d.decCheckInteger() {
-		decErr("Assigning negative signed value to unsigned type")
+		d.d.errorf("Assigning negative signed value to unsigned type")
+		return
 	}
 	ui = d.decUint()
 	if chkOvf.Uint(ui, bitsize) {
-		decErr("cbor: overflow integer: %v", ui)
+		d.d.errorf("cbor: overflow integer: %v", ui)
+		return
 	}
 	d.bdRead = false
 	return
@@ -302,10 +311,12 @@ func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	} else if bd >= cborBaseUint && bd < cborBaseBytes {
 		f = float64(d.DecodeInt(64))
 	} else {
-		decErr("Float only valid from float16/32/64: Invalid descriptor: %v", bd)
+		d.d.errorf("Float only valid from float16/32/64: Invalid descriptor: %v", bd)
+		return
 	}
 	if chkOverflow32 && chkOvf.Float32(f) {
-		decErr("cbor: float32 overflow: %v", f)
+		d.d.errorf("cbor: float32 overflow: %v", f)
+		return
 	}
 	d.bdRead = false
 	return
@@ -320,7 +331,8 @@ func (d *cborDecDriver) DecodeBool() (b bool) {
 		b = true
 	} else if bd == cborBdFalse {
 	} else {
-		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		return
 	}
 	d.bdRead = false
 	return
@@ -353,7 +365,8 @@ func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
 			break
 		}
 		if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText {
-			decErr("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd)
+			d.d.errorf("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd)
+			return nil
 		}
 		n := d.decLen()
 		oldLen := len(bs)
@@ -403,7 +416,7 @@ func (d *cborDecDriver) DecodeString() (s string) {
 	return string(d.DecodeBytes(d.b[:], true, true))
 }
 
-func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, de *Decoder) (realxtag uint64) {
+func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -413,19 +426,20 @@ func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, de *Deco
 	if ext == nil {
 		re := rv.(*RawExt)
 		re.Tag = realxtag
-		de.decode(&re.Value)
+		d.d.decode(&re.Value)
 	} else if xtag != realxtag {
-		decErr("Wrong extension tag. Got %b. Expecting: %v", realxtag, xtag)
+		d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", realxtag, xtag)
+		return
 	} else {
 		var v interface{}
-		de.decode(&v)
+		d.d.decode(&v)
 		ext.UpdateExt(rv, v)
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *cborDecDriver) DecodeNaked(de *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (d *cborDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -488,11 +502,12 @@ func (d *cborDecDriver) DecodeNaked(de *Decoder) (v interface{}, vt valueType, d
 			ui := d.decUint()
 			d.bdRead = false
 			re.Tag = ui
-			de.decode(&re.Value)
+			d.d.decode(&re.Value)
 			v = &re
 			// decodeFurther = true
 		default:
-			decErr("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
+			d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
+			return
 		}
 	}
 
@@ -539,13 +554,12 @@ type CborHandle struct {
 	binaryEncodingType
 }
 
-func (h *CborHandle) newEncDriver(w encWriter) encDriver {
-	return &cborEncDriver{w: w, h: h}
+func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
+	return &cborEncDriver{e: e, w: e.w, h: h}
 }
 
-func (h *CborHandle) newDecDriver(r decReader) decDriver {
-	_, ok := r.(*bytesDecReader)
-	return &cborDecDriver{r: r, h: h, br: ok}
+func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
+	return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes}
 }
 
 var _ decDriver = (*cborDecDriver)(nil)

+ 2 - 2
codec/codec_test.go

@@ -466,7 +466,7 @@ func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
 		if err != nil {
 			continue
 		}
-		if h.isBinaryEncoding() {
+		if h.isBinary() {
 			logT(t, "         Encoded bytes: len: %v, %v\n", len(b0), b0)
 		} else {
 			logT(t, "         Encoded string: len: %v, %v\n", len(string(b0)), string(b0))
@@ -586,7 +586,7 @@ func testCodecMiscOne(t *testing.T, h Handle) {
 		logT(t, "------- Size must be > 40. Size: %d", len(b))
 		t.FailNow()
 	}
-	if h.isBinaryEncoding() {
+	if h.isBinary() {
 		logT(t, "------- b: %v", b)
 	} else {
 		logT(t, "------- b: %s", b)

+ 70 - 39
codec/decode.go

@@ -6,6 +6,7 @@ package codec
 import (
 	"encoding"
 	"errors"
+	"fmt"
 	"io"
 	"reflect"
 )
@@ -17,6 +18,11 @@ const (
 	msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v"
 )
 
+var (
+	onlyMapOrArrayCanDecodeIntoStructErr = errors.New("only encoded map or array can be decoded into a struct")
+	cannotDecodeIntoNilErr               = errors.New("cannot decode into nil")
+)
+
 // 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 {
@@ -53,7 +59,7 @@ type decDriver interface {
 	//for extensions, decodeNaked must completely decode them as a *RawExt.
 	//extensions should also use readx to decode them, for efficiency.
 	//kInterface will extract the detached byte slice if it has to pass it outside its realm.
-	DecodeNaked(*Decoder) (v interface{}, vt valueType, decodeFurther bool)
+	DecodeNaked() (v interface{}, vt valueType, decodeFurther bool)
 	DecodeInt(bitsize uint8) (i int64)
 	DecodeUint(bitsize uint8) (ui uint64)
 	DecodeFloat(chkOverflow32 bool) (f float64)
@@ -70,7 +76,7 @@ type decDriver interface {
 	DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte)
 
 	// decodeExt will decode into a *RawExt or into an extension.
-	DecodeExt(v interface{}, xtag uint64, ext Ext, d *Decoder) (realxtag uint64)
+	DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64)
 	// decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
 	ReadMapStart() int
 	ReadArrayStart() int
@@ -168,7 +174,9 @@ func (z *ioDecByteScanner) UnreadByte() (err error) {
 // ioDecReader is a decReader that reads off an io.Reader
 type ioDecReader struct {
 	br decReaderByteScanner
-	x  [scratchByteArrayLen]byte //temp byte array re-used internally for efficiency
+	// temp byte array re-used internally for efficiency during read.
+	// shares buffer with Decoder, so we keep size of struct within 8 words.
+	x  *[scratchByteArrayLen]byte
 	bs ioDecByteScanner
 }
 
@@ -223,6 +231,8 @@ func (z *ioDecReader) unreadn1() {
 
 // ------------------------------------
 
+var bytesDecReaderCannotUnreadErr = errors.New("cannot unread last byte read")
+
 // bytesDecReader is a decReader that reads off a byte slice with zero copying
 type bytesDecReader struct {
 	b []byte // data
@@ -232,7 +242,7 @@ type bytesDecReader struct {
 
 func (z *bytesDecReader) unreadn1() {
 	if z.c == 0 || len(z.b) == 0 {
-		decErr("cannot unread last byte read")
+		panic(bytesDecReaderCannotUnreadErr)
 	}
 	z.c--
 	z.a++
@@ -319,11 +329,11 @@ func (f decFnInfo) builtin(rv reflect.Value) {
 }
 
 func (f decFnInfo) rawExt(rv reflect.Value) {
-	f.dd.DecodeExt(rv.Addr().Interface(), 0, nil, f.d)
+	f.dd.DecodeExt(rv.Addr().Interface(), 0, nil)
 }
 
 func (f decFnInfo) ext(rv reflect.Value) {
-	f.dd.DecodeExt(rv.Addr().Interface(), f.xfTag, f.xfFn, f.d)
+	f.dd.DecodeExt(rv.Addr().Interface(), f.xfTag, f.xfFn)
 }
 
 func (f decFnInfo) getValueForUnmarshalInterface(rv reflect.Value, indir int8) (v interface{}) {
@@ -372,7 +382,7 @@ func (f decFnInfo) textUnmarshal(rv reflect.Value) {
 }
 
 func (f decFnInfo) kErr(rv reflect.Value) {
-	decErr("no decoding function defined for kind %v", rv.Kind())
+	f.d.errorf("no decoding function defined for kind %v", rv.Kind())
 }
 
 func (f decFnInfo) kString(rv reflect.Value) {
@@ -445,14 +455,14 @@ func (f decFnInfo) kInterfaceNaked() (rvn reflect.Value) {
 	// nil interface:
 	// use some hieristics to decode it appropriately
 	// based on the detected next value in the stream.
-	v, vt, decodeFurther := f.dd.DecodeNaked(f.d)
+	v, vt, decodeFurther := f.dd.DecodeNaked()
 	if vt == valueTypeNil {
 		return
 	}
 	// We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader).
 	if num := f.ti.rt.NumMethod(); num > 0 {
-		decErr("cannot decode non-nil codec value into nil %v (%v methods)",
-			f.ti.rt, num)
+		f.d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, num)
+		return
 	}
 	var useRvn bool
 	switch vt {
@@ -551,7 +561,8 @@ func (f decFnInfo) kStruct(rv reflect.Value) {
 		hasLen := containerLen >= 0
 		if hasLen {
 			for j := 0; j < containerLen; j++ {
-				rvkencname := f.dd.DecodeString()
+				// rvkencname := f.dd.DecodeString()
+				rvkencname := stringView(f.dd.DecodeBytes(f.d.b[:], true, true))
 				// rvksi := ti.getForEncName(rvkencname)
 				if k := fti.indexForEncName(rvkencname); k > -1 {
 					si := tisfi[k]
@@ -569,7 +580,8 @@ func (f decFnInfo) kStruct(rv reflect.Value) {
 				if j > 0 {
 					f.dd.ReadMapEntrySeparator()
 				}
-				rvkencname := f.dd.DecodeString()
+				// rvkencname := f.dd.DecodeString()
+				rvkencname := stringView(f.dd.DecodeBytes(f.d.b[:], true, true))
 				f.dd.ReadMapKVSeparator()
 				// rvksi := ti.getForEncName(rvkencname)
 				if k := fti.indexForEncName(rvkencname); k > -1 {
@@ -627,7 +639,8 @@ func (f decFnInfo) kStruct(rv reflect.Value) {
 		}
 		f.dd.ReadArrayEnd()
 	} else {
-		decErr("only encoded map or array can be decoded into a struct")
+		f.d.error(onlyMapOrArrayCanDecodeIntoStructErr)
+		return
 	}
 }
 
@@ -833,21 +846,25 @@ type rtidDecFn struct {
 
 // A Decoder reads and decodes an object from an input stream in the codec format.
 type Decoder struct {
-	// hopefully, reduce derefencing cost by laying the decReader inside the Decoder
-	r  decReader
-	rb bytesDecReader
-	ri ioDecReader
+	// hopefully, reduce derefencing cost by laying the decReader inside the Decoder.
+	// Try to put things that go together to fit within a cache line (8 words).
 
-	d  decDriver
-	h  *BasicHandle
-	hh Handle
-	f  map[uintptr]decFn
+	d decDriver
+	r decReader
 	//sa [32]rtidDecFn
 	s []rtidDecFn
-	b [scratchByteArrayLen]byte
+	h *BasicHandle
 
+	rb    bytesDecReader
+	hh    Handle
 	be    bool // is binary encoding
 	bytes bool // is bytes reader
+
+	ri ioDecReader
+	f  map[uintptr]decFn
+	_  uintptr // for alignment purposes, so next one starts from a cache line
+
+	b [scratchByteArrayLen]byte
 }
 
 // NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
@@ -855,8 +872,9 @@ type Decoder struct {
 // For efficiency, Users are encouraged to pass in a memory buffered reader
 // (eg bufio.Reader, bytes.Buffer).
 func NewDecoder(r io.Reader, h Handle) (d *Decoder) {
-	d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinaryEncoding()}
+	d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()}
 	//d.s = d.sa[:0]
+	d.ri.x = &d.b
 	d.ri.bs.r = r
 	var ok bool
 	d.ri.br, ok = r.(decReaderByteScanner)
@@ -864,19 +882,19 @@ func NewDecoder(r io.Reader, h Handle) (d *Decoder) {
 		d.ri.br = &d.ri.bs
 	}
 	d.r = &d.ri
-	d.d = h.newDecDriver(d.r)
+	d.d = h.newDecDriver(d)
 	return
 }
 
 // NewDecoderBytes returns a Decoder which efficiently decodes directly
 // from a byte slice with zero copying.
 func NewDecoderBytes(in []byte, h Handle) (d *Decoder) {
-	d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinaryEncoding(), bytes: true}
+	d = &Decoder{hh: h, h: h.getBasicHandle(), be: h.isBinary(), bytes: true}
 	//d.s = d.sa[:0]
 	d.rb.b = in
 	d.rb.a = len(in)
 	d.r = &d.rb
-	d.d = h.newDecDriver(d.r)
+	d.d = h.newDecDriver(d)
 	// d.d = h.newDecDriver(decReaderT{true, &d.rb, &d.ri})
 	return
 }
@@ -991,7 +1009,7 @@ func (d *Decoder) swallow() {
 		// dd.DecodeStringAsBytes(d.b[:])
 	default:
 		// these are all primitives, which we can get from decodeNaked
-		dd.DecodeNaked(d)
+		dd.DecodeNaked()
 	}
 }
 
@@ -1059,7 +1077,8 @@ func (d *Decoder) decode(iv interface{}) {
 
 	switch v := iv.(type) {
 	case nil:
-		decErr("cannot decode into nil.")
+		d.error(cannotDecodeIntoNilErr)
+		return
 
 	case Selfer:
 		v.CodecDecodeSelf(d)
@@ -1321,9 +1340,11 @@ func (d *Decoder) getDecFn(rt reflect.Type, checkAll bool) (fn decFn) {
 func (d *Decoder) structFieldNotFound(index int, rvkencname string) {
 	if d.h.ErrorIfNoField {
 		if index >= 0 {
-			decErr("no matching struct field found when decoding stream array at index %v", index)
+			d.errorf("no matching struct field found when decoding stream array at index %v", index)
+			return
 		} else if rvkencname != "" {
-			decErr("no matching struct field found when decoding stream map with key %s", rvkencname)
+			d.errorf("no matching struct field found when decoding stream map with key %s", rvkencname)
+			return
 		}
 	}
 	d.swallow()
@@ -1331,7 +1352,7 @@ func (d *Decoder) structFieldNotFound(index int, rvkencname string) {
 
 func (d *Decoder) arrayCannotExpand(sliceLen, streamLen int) {
 	if d.h.ErrorIfNoArrayExpand {
-		decErr("cannot expand array len during decode from %v to %v", sliceLen, streamLen)
+		d.errorf("cannot expand array len during decode from %v to %v", sliceLen, streamLen)
 	}
 }
 
@@ -1341,14 +1362,24 @@ func (d *Decoder) chkPtrValue(rv reflect.Value) {
 		return
 	}
 	if !rv.IsValid() {
-		decErr("cannot decode into a zero (ie invalid) reflect.Value")
+		d.error(cannotDecodeIntoNilErr)
+		return
 	}
 	if !rv.CanInterface() {
-		decErr("cannot decode into a value without an interface: %v", rv)
+		d.errorf("cannot decode into a value without an interface: %v", rv)
+		return
 	}
 	rvi := rv.Interface()
-	decErr("cannot decode into non-pointer or nil pointer. Got: %v, %T, %v",
-		rv.Kind(), rvi, rvi)
+	d.errorf("cannot decode into non-pointer or nil pointer. Got: %v, %T, %v", rv.Kind(), rvi, rvi)
+}
+
+func (d *Decoder) error(err error) {
+	panic(err)
+}
+
+func (d *Decoder) errorf(format string, params ...interface{}) {
+	err := fmt.Errorf(format, params...)
+	panic(err)
 }
 
 // --------------------------------------------------
@@ -1369,7 +1400,7 @@ func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) {
 		x.ct = valueTypeMap
 		clen = x.dd.ReadMapStart() * 2
 	} else {
-		decErr("only encoded map or array can be decoded into a slice")
+		d.errorf("only encoded map or array can be decoded into a slice")
 	}
 	return
 }
@@ -1394,9 +1425,9 @@ func (x decSliceHelper) End() {
 	}
 }
 
-func decErr(format string, params ...interface{}) {
-	doPanic(msgTagDec, format, params...)
-}
+// func decErr(format string, params ...interface{}) {
+// 	doPanic(msgTagDec, format, params...)
+// }
 
 func decByteSlice(r decReader, clen int, bs []byte) (bsOut []byte) {
 	if clen == 0 {

+ 27 - 17
codec/encode.go

@@ -5,6 +5,8 @@ package codec
 
 import (
 	"encoding"
+	"errors"
+	"fmt"
 	"io"
 	"reflect"
 	"sync"
@@ -134,7 +136,8 @@ func (o *simpleIoEncWriterWriter) WriteString(s string) (n int, err error) {
 	if o.sw != nil {
 		return o.sw.WriteString(s)
 	}
-	return o.w.Write([]byte(s))
+	// return o.w.Write([]byte(s))
+	return o.w.Write(bytesView(s))
 }
 
 func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) {
@@ -158,7 +161,7 @@ func (z *ioEncWriter) writeb(bs []byte) {
 		panic(err)
 	}
 	if n != len(bs) {
-		encErr("incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n)
+		panic(fmt.Errorf("incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n))
 	}
 }
 
@@ -168,7 +171,7 @@ func (z *ioEncWriter) writestr(s string) {
 		panic(err)
 	}
 	if n != len(s) {
-		encErr("incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n)
+		panic(fmt.Errorf("incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n))
 	}
 }
 
@@ -362,7 +365,7 @@ func (f encFnInfo) kInvalid(rv reflect.Value) {
 }
 
 func (f encFnInfo) kErr(rv reflect.Value) {
-	encErr("unsupported kind %s, for %#v", rv.Kind(), rv)
+	f.e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv)
 }
 
 func (f encFnInfo) kSlice(rv reflect.Value) {
@@ -407,7 +410,8 @@ func (f encFnInfo) kSlice(rv reflect.Value) {
 
 	if ti.mbs {
 		if l%2 == 1 {
-			encErr("mapBySlice requires even slice length, but got %v", l)
+			f.e.errorf("mapBySlice requires even slice length, but got %v", l)
+			return
 		}
 		f.ee.EncodeMapStart(l / 2)
 	} else {
@@ -475,7 +479,7 @@ func (f encFnInfo) kStruct(rv reflect.Value) {
 	var poolv interface{}
 	idxpool := newlen / 8
 	if encStructPoolLen != 4 {
-		panic("encStructPoolLen must be equal to 4") // defensive, in case it is changed
+		panic(errors.New("encStructPoolLen must be equal to 4")) // defensive, in case it is changed
 	}
 	if idxpool < encStructPoolLen {
 		pool = &encStructPool[idxpool]
@@ -724,16 +728,17 @@ type rtidEncFn struct {
 // An Encoder writes an object to an output stream in the codec format.
 type Encoder struct {
 	// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
+	e  encDriver
 	w  encWriter
+	s  []rtidEncFn
+	be bool // is binary encoding
+
 	wi ioEncWriter
 	wb bytesEncWriter
-
-	e  encDriver
 	h  *BasicHandle
+
 	hh Handle
 	f  map[uintptr]encFn
-	s  []rtidEncFn
-	be bool // is binary encoding
 }
 
 // NewEncoder returns an Encoder for encoding into an io.Writer.
@@ -741,7 +746,7 @@ type Encoder struct {
 // For efficiency, Users are encouraged to pass in a memory buffered writer
 // (eg bufio.Writer, bytes.Buffer).
 func NewEncoder(w io.Writer, h Handle) *Encoder {
-	e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinaryEncoding()}
+	e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()}
 	ww, ok := w.(ioEncWriterWriter)
 	if !ok {
 		sww := simpleIoEncWriterWriter{w: w}
@@ -752,7 +757,7 @@ func NewEncoder(w io.Writer, h Handle) *Encoder {
 	}
 	e.wi.w = ww
 	e.w = &e.wi
-	e.e = h.newEncDriver(e.w)
+	e.e = h.newEncDriver(e)
 	return e
 }
 
@@ -762,14 +767,14 @@ func NewEncoder(w io.Writer, h Handle) *Encoder {
 // 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 {
-	e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinaryEncoding()}
+	e := &Encoder{hh: h, h: h.getBasicHandle(), be: h.isBinary()}
 	in := *out
 	if in == nil {
 		in = make([]byte, defEncByteBufSize)
 	}
 	e.wb.b, e.wb.out = in, out
 	e.w = &e.wb
-	e.e = h.newEncDriver(e.w)
+	e.e = h.newEncDriver(e)
 	return e
 }
 
@@ -1111,6 +1116,11 @@ func (e *Encoder) getEncFn(rtid uintptr, rt reflect.Type, checkAll bool) (fn enc
 	return
 }
 
+func (e *Encoder) errorf(format string, params ...interface{}) {
+	err := fmt.Errorf(format, params...)
+	panic(err)
+}
+
 // ----------------------------------------
 
 const encStructPoolLen = 4
@@ -1155,6 +1165,6 @@ func init() {
 
 // ----------------------------------------
 
-func encErr(format string, params ...interface{}) {
-	doPanic(msgTagEnc, format, params...)
-}
+// func encErr(format string, params ...interface{}) {
+// 	doPanic(msgTagEnc, format, params...)
+// }

+ 36 - 23
codec/gen.go

@@ -5,6 +5,7 @@ package codec
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"go/format"
 	"io"
@@ -65,19 +66,26 @@ import (
 
 const GenVersion = 1 // increment this value each time codecgen changes fundamentally.
 
-const genCodecPkg = "codec1978"
-const genTempVarPfx = "yy"
+const (
+	genCodecPkg   = "codec1978"
+	genTempVarPfx = "yy"
 
-// ignore canBeNil parameter, and always set to true.
-// This is because nil can appear anywhere, so we should always check.
-const genAnythingCanBeNil = true
+	// ignore canBeNil parameter, and always set to true.
+	// This is because nil can appear anywhere, so we should always check.
+	genAnythingCanBeNil = true
 
-// if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function;
-// else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals
-// are not executed a lot.
-//
-// From testing, it didn't make much difference in runtime, so keep as true (one function only)
-const genUseOneFunctionForDecStructMap = true
+	// if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function;
+	// else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals
+	// are not executed a lot.
+	//
+	// From testing, it didn't make much difference in runtime, so keep as true (one function only)
+	genUseOneFunctionForDecStructMap = true
+)
+
+var (
+	genAllTypesSamePkgErr  = errors.New("All types must be in the same package")
+	genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice")
+)
 
 // genRunner holds some state used during a Gen run.
 type genRunner struct {
@@ -127,7 +135,7 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 	for _, t := range typ {
 		// fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", t.PkgPath(), t.Name())
 		if t.PkgPath() != x.bp {
-			panic("All types must be in the same package")
+			panic(genAllTypesSamePkgErr)
 		}
 		x.genRefPkgs(t)
 	}
@@ -154,7 +162,7 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 		x.line("\"" + k + "\"")
 	}
 	// add required packages
-	for _, k := range [...]string{"reflect", "unsafe", "runtime", "fmt"} {
+	for _, k := range [...]string{"reflect", "unsafe", "runtime", "fmt", "errors"} {
 		if _, ok := x.im[k]; !ok {
 			if k == "unsafe" && !x.unsafe {
 				continue
@@ -173,7 +181,10 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 	x.linef("codecSelverValueTypeArray%s = %v", x.xs, int64(valueTypeArray))
 	x.linef("codecSelverValueTypeMap%s = %v", x.xs, int64(valueTypeMap))
 	x.line(")")
-	x.line("var codecSelferBitsize" + x.xs + " = uint8(reflect.TypeOf(uint(0)).Bits())")
+	x.line("var (")
+	x.line("codecSelferBitsize" + x.xs + " = uint8(reflect.TypeOf(uint(0)).Bits())")
+	x.line("codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + " = errors.New(`only encoded map or array can be decoded into a struct`)")
+	x.line(")")
 	x.line("")
 
 	if x.unsafe {
@@ -235,7 +246,7 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 		case reflect.Map:
 			x.encMapFallback("v", rtid, t)
 		default:
-			panic("unexpected type. Expecting array/map/slice")
+			panic(genExpectArrayOrMapErr)
 		}
 		x.line("}")
 		x.line("")
@@ -251,7 +262,7 @@ func Gen(w io.Writer, buildTags, pkgName string, useUnsafe bool, typ ...reflect.
 		case reflect.Map:
 			x.decMapFallback("v", rtid, t)
 		default:
-			panic("unexpected type. Expecting array/map/slice")
+			panic(genExpectArrayOrMapErr)
 		}
 		x.line("}")
 		x.line("")
@@ -1262,7 +1273,8 @@ func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
 	x.line("}")
 	// else panic
 	x.line("} else { ")
-	x.line("panic(`only encoded map or array can be decoded into a struct`)")
+	x.line("panic(codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + ")")
+	// x.line("panic(`only encoded map or array can be decoded into a struct`)")
 	x.line("} ")
 }
 
@@ -1473,7 +1485,7 @@ func genInternalDecCommandAsString(s string) string {
 	case "bool":
 		return "dd.DecodeBool()"
 	default:
-		panic("unknown type for decode: " + s)
+		panic(errors.New("unknown type for decode: " + s))
 	}
 
 }
@@ -1554,7 +1566,7 @@ func genInternalInit() {
 // It is run by the program author alone.
 // Unfortunately, it has to be exported so that it can be called from a command line tool.
 // *** DO NOT USE ***
-func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) {
+func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) (err error) {
 	genInternalOnce.Do(genInternalInit)
 
 	gt := genInternalV
@@ -1564,24 +1576,25 @@ func GenInternalGoFile(r io.Reader, w io.Writer, safe bool) {
 
 	tmplstr, err := ioutil.ReadAll(r)
 	if err != nil {
-		panic(err)
+		return
 	}
 
 	if t, err = t.Parse(string(tmplstr)); err != nil {
-		panic(err)
+		return
 	}
 
 	var out bytes.Buffer
 	err = t.Execute(&out, gt)
 	if err != nil {
-		panic(err)
+		return
 	}
 
 	bout, err := format.Source(out.Bytes())
 	if err != nil {
 		w.Write(out.Bytes()) // write out if error, so we can still see.
 		// w.Write(bout) // write out if error, as much as possible, so we can still see.
-		panic(err)
+		return
 	}
 	w.Write(bout)
+	return
 }

+ 33 - 12
codec/helper.go

@@ -81,10 +81,29 @@ package codec
 //   - iterate through all s1, and for each one not marked, set value to zero
 //   - this involves checking the possible anonymous fields which are nil ptrs.
 //     too much work.
+//
+// ------------------------------------------
+// Error Handling is done within the library using panic.
+//
+// This way, the code doesn't have to keep checking if an error has happened,
+// and we don't have to keep sending the error value along with each call
+// or storing it in the En|Decoder and checking it constantly along the way.
+//
+// The disadvantage is that small functions which use panics cannot be inlined.
+// The code accounts for that by only using panics behind an interface;
+// since interface calls cannot be inlined, this is irrelevant.
+//
+// We considered storing the error is En|Decoder.
+//   - once it has its err field set, it cannot be used again.
+//   - panicing will be optional, controlled by const flag.
+//   - code should always check error first and return early.
+// We eventually decided against it as it makes the code clumsier to always
+// check for these error conditions.
 
 import (
 	"encoding"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"math"
 	"reflect"
@@ -205,6 +224,8 @@ var (
 	bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
 
 	chkOvf checkOverflow
+
+	noFieldNameToStructFieldInfoErr = errors.New("no field name passed to parseStructFieldInfo")
 )
 
 // Selfer defines methods by which a value can encode or decode itself.
@@ -248,9 +269,9 @@ func (x *BasicHandle) getBasicHandle() *BasicHandle {
 // is safe for concurrent access.
 type Handle interface {
 	getBasicHandle() *BasicHandle
-	newEncDriver(w encWriter) encDriver
-	newDecDriver(r decReader) decDriver
-	isBinaryEncoding() bool
+	newEncDriver(w *Encoder) encDriver
+	newDecDriver(r *Decoder) decDriver
+	isBinary() bool
 }
 
 // RawExt represents raw unprocessed extension data.
@@ -321,11 +342,11 @@ func (x bytesExt) UpdateExt(dest interface{}, v interface{}) {
 
 type binaryEncodingType struct{}
 
-func (_ binaryEncodingType) isBinaryEncoding() bool { return true }
+func (_ binaryEncodingType) isBinary() bool { return true }
 
 type textEncodingType struct{}
 
-func (_ textEncodingType) isBinaryEncoding() bool { return false }
+func (_ textEncodingType) isBinary() bool { return false }
 
 // noBuiltInTypes is embedded into many types which do not support builtins
 // e.g. msgpack, simple, cbor.
@@ -486,7 +507,7 @@ func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
 
 func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
 	if fname == "" {
-		panic("no field name passed to parseStructFieldInfo")
+		panic(noFieldNameToStructFieldInfoErr)
 	}
 	si := structFieldInfo{
 		encName: fname,
@@ -731,12 +752,12 @@ func panicToErr(err *error) {
 	}
 }
 
-func doPanic(tag string, format string, params ...interface{}) {
-	params2 := make([]interface{}, len(params)+1)
-	params2[0] = tag
-	copy(params2[1:], params)
-	panic(fmt.Errorf("%s: "+format, params2...))
-}
+// func doPanic(tag string, format string, params ...interface{}) {
+// 	params2 := make([]interface{}, len(params)+1)
+// 	params2[0] = tag
+// 	copy(params2[1:], params)
+// 	panic(fmt.Errorf("%s: "+format, params2...))
+// }
 
 func isMutableKind(k reflect.Kind) (v bool) {
 	return k == reflect.Int ||

+ 20 - 0
codec/helper_not_unsafe.go

@@ -0,0 +1,20 @@
+//+build !unsafe
+
+// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// stringView returns a view of the []byte as a string.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+func stringView(v []byte) string {
+	return string(v)
+}
+
+// bytesView returns a view of the string as a []byte.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+func bytesView(v string) []byte {
+	return []byte(v)
+}

+ 39 - 0
codec/helper_unsafe.go

@@ -0,0 +1,39 @@
+//+build unsafe
+
+// Copyright (c) 2012-2015 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 (
+	"unsafe"
+)
+
+// This file has unsafe variants of some helper methods.
+
+type unsafeString struct {
+	Data uintptr
+	Len  int
+}
+
+type unsafeBytes struct {
+	Data uintptr
+	Len  int
+	Cap  int
+}
+
+// stringView returns a view of the []byte as a string.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+func stringView(v []byte) string {
+	x := unsafeString{uintptr(unsafe.Pointer(&v[0])), len(v)}
+	return *(*string)(unsafe.Pointer(&x))
+}
+
+// bytesView returns a view of the string as a []byte.
+// In unsafe mode, it doesn't incur allocation and copying caused by conversion.
+// In regular safe mode, it is an allocation and copy.
+func bytesView(v string) []byte {
+	x := unsafeBytes{uintptr(unsafe.Pointer(&v)), len(v), len(v)}
+	return *(*[]byte)(unsafe.Pointer(&x))
+}

+ 68 - 47
codec/json.go

@@ -25,11 +25,12 @@ package codec
 //
 // Note:
 //   - encode does not beautify. There is no whitespace when encoding.
-//   - rpc calls which take single integer arguments or write single numeric arguments will not
+//   - rpc calls which take single integer arguments or write single numeric arguments will need care.
 
 import (
 	"bytes"
 	"encoding/base64"
+	"fmt"
 	"strconv"
 	"unicode/utf16"
 	"unicode/utf8"
@@ -81,6 +82,7 @@ const (
 )
 
 type jsonEncDriver struct {
+	e  *Encoder
 	w  encWriter
 	h  *JsonHandle
 	b  [64]byte // scratch
@@ -391,8 +393,9 @@ func (x *jsonNum) floatVal() (f float64) {
 		x.mantissa>>uint64MantissaBits != 0
 	if parseUsingStrConv {
 		var err error
-		if f, err = strconv.ParseFloat(string(x.bytes), 64); err != nil {
-			decErr("parse float: %s, %v", x.bytes, err)
+		if f, err = strconv.ParseFloat(stringView(x.bytes), 64); err != nil {
+			panic(fmt.Errorf("parse float: %s, %v", x.bytes, err))
+			return
 		}
 		if x.neg {
 			f = -f
@@ -415,6 +418,7 @@ func (x *jsonNum) floatVal() (f float64) {
 }
 
 type jsonDecDriver struct {
+	d    *Decoder
 	h    *JsonHandle
 	r    decReader // *bytesDecReader decReader
 	ct   valueType // container type. one of unset, array or map.
@@ -452,27 +456,29 @@ func (d *jsonDecDriver) CheckBreak() bool {
 	return b == '}' || b == ']'
 }
 
-func (d *jsonDecDriver) readStr(s []byte) {
-	if jsonValidateSymbols {
-		bs := d.b[:len(s)]
-		d.r.readb(bs)
-		if !bytes.Equal(bs, s) {
-			decErr("json: expecting %s: got %s", s, bs)
-		}
-	} else {
-		d.r.readx(len(s))
-	}
-	if jsonTrackSkipWhitespace {
-		d.wsSkipped = false
-	}
-}
+// func (d *jsonDecDriver) readStr(s []byte) {
+// 	if jsonValidateSymbols {
+// 		bs := d.b[:len(s)]
+// 		d.r.readb(bs)
+// 		if !bytes.Equal(bs, s) {
+// 			d.d.errorf("json: expecting %s: got %s", s, bs)
+//			return
+// 		}
+// 	} else {
+// 		d.r.readx(len(s))
+// 	}
+// 	if jsonTrackSkipWhitespace {
+// 		d.wsSkipped = false
+// 	}
+// }
 
 func (d *jsonDecDriver) readStrIdx(fromIdx, toIdx uint8) {
 	if jsonValidateSymbols {
 		bs := d.b[:(toIdx - fromIdx)]
 		d.r.readb(bs)
 		if !bytes.Equal(bs, jsonLiterals[fromIdx:toIdx]) {
-			decErr("json: expecting %s: got %s", jsonLiterals[fromIdx:toIdx], bs)
+			d.d.errorf("json: expecting %s: got %s", jsonLiterals[fromIdx:toIdx], bs)
+			return
 		}
 	} else {
 		d.r.readx(int(toIdx - fromIdx))
@@ -502,8 +508,8 @@ func (d *jsonDecDriver) DecodeBool() bool {
 		d.readStrIdx(1, 4) // rue
 		return true
 	}
-	decErr("json: decode bool: got first char %c", b)
-	panic("unreachable")
+	d.d.errorf("json: decode bool: got first char %c", b)
+	return false // "unreachable"
 }
 
 func (d *jsonDecDriver) ReadMapStart() int {
@@ -535,7 +541,8 @@ func (d *jsonDecDriver) ReadMapKVSeparator() {
 func (d *jsonDecDriver) expectChar(c uint8) {
 	b := d.skipWhitespace(false)
 	if b != c {
-		decErr("json: expect char %c but got char %c", c, b)
+		d.d.errorf("json: expect char %c but got char %c", c, b)
+		return
 	}
 	if jsonTrackSkipWhitespace {
 		d.wsSkipped = false
@@ -565,8 +572,8 @@ func (d *jsonDecDriver) IsContainerType(vt valueType) bool {
 	// case valueTypeNil, valueTypeBytes, valueTypeString, valueTypeArray, valueTypeMap:
 	// 	return d.ct == vt
 	// }
-	decErr("isContainerType: unsupported parameter: %v", vt)
-	panic("unreachable")
+	d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+	return false // "unreachable"
 }
 
 func (d *jsonDecDriver) decNum(storeBytes bool) {
@@ -575,7 +582,8 @@ func (d *jsonDecDriver) decNum(storeBytes bool) {
 	// If it is has a . or an e|E, decode as a float; else decode as an int.
 	b := d.skipWhitespace(false)
 	if !(b == '+' || b == '-' || b == '.' || (b >= '0' && b <= '9')) {
-		decErr("json: decNum: got first char '%c'", b)
+		d.d.errorf("json: decNum: got first char '%c'", b)
+		return
 	}
 
 	const cutoff = (1<<64-1)/uint64(10) + 1 // cutoff64(base)
@@ -717,17 +725,20 @@ func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
 	d.decNum(false)
 	n := &d.n
 	if n.manOverflow {
-		decErr("json: overflow integer after: %v", n.mantissa)
+		d.d.errorf("json: overflow integer after: %v", n.mantissa)
+		return
 	}
 	var u uint64
 	if n.exponent == 0 {
 		u = n.mantissa
 	} else if n.exponent < 0 {
-		decErr("json: fractional integer")
+		d.d.errorf("json: fractional integer")
+		return
 	} else if n.exponent > 0 {
 		var overflow bool
 		if u, overflow = n.uintExp(); overflow {
-			decErr("json: overflow integer")
+			d.d.errorf("json: overflow integer")
+			return
 		}
 	}
 	i = int64(u)
@@ -735,7 +746,8 @@ func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
 		i = -i
 	}
 	if chkOvf.Int(i, bitsize) {
-		decErr("json: overflow %v bits: %s", bitsize, n.bytes)
+		d.d.errorf("json: overflow %v bits: %s", bitsize, n.bytes)
+		return
 	}
 	// fmt.Printf("DecodeInt: %v\n", i)
 	return
@@ -745,23 +757,28 @@ func (d *jsonDecDriver) DecodeUint(bitsize uint8) (u uint64) {
 	d.decNum(false)
 	n := &d.n
 	if n.neg {
-		decErr("json: unsigned integer cannot be negative")
+		d.d.errorf("json: unsigned integer cannot be negative")
+		return
 	}
 	if n.manOverflow {
-		decErr("json: overflow integer after: %v", n.mantissa)
+		d.d.errorf("json: overflow integer after: %v", n.mantissa)
+		return
 	}
 	if n.exponent == 0 {
 		u = n.mantissa
 	} else if n.exponent < 0 {
-		decErr("json: fractional integer")
+		d.d.errorf("json: fractional integer")
+		return
 	} else if n.exponent > 0 {
 		var overflow bool
 		if u, overflow = n.uintExp(); overflow {
-			decErr("json: overflow integer")
+			d.d.errorf("json: overflow integer")
+			return
 		}
 	}
 	if chkOvf.Uint(u, bitsize) {
-		decErr("json: overflow %v bits: %s", bitsize, n.bytes)
+		d.d.errorf("json: overflow %v bits: %s", bitsize, n.bytes)
+		return
 	}
 	// fmt.Printf("DecodeUint: %v\n", u)
 	return
@@ -772,19 +789,20 @@ func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	n := &d.n
 	f = n.floatVal()
 	if chkOverflow32 && chkOvf.Float32(f) {
-		decErr("json: overflow float32: %v, %s", f, n.bytes)
+		d.d.errorf("json: overflow float32: %v, %s", f, n.bytes)
+		return
 	}
 	return
 }
 
-func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, de *Decoder) (realxtag uint64) {
+func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
 	if ext == nil {
 		re := rv.(*RawExt)
 		re.Tag = xtag
-		de.decode(&re.Value)
+		d.d.decode(&re.Value)
 	} else {
 		var v interface{}
-		de.decode(&v)
+		d.d.decode(&v)
 		ext.UpdateExt(rv, v)
 	}
 	return
@@ -840,7 +858,8 @@ func (d *jsonDecDriver) appendStringAsBytes(v []byte) []byte {
 				w2 := utf8.EncodeRune(d.bstr[:], rr)
 				v = append(v, d.bstr[:w2]...)
 			default:
-				decErr("json: unsupported escaped value: %c", c)
+				d.d.errorf("json: unsupported escaped value: %c", c)
+				return nil
 			}
 		} else {
 			v = append(v, c)
@@ -854,7 +873,8 @@ func (d *jsonDecDriver) appendStringAsBytes(v []byte) []byte {
 
 func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
 	if checkSlashU && !(d.r.readn1() == '\\' && d.r.readn1() == 'u') {
-		decErr(`json: unquoteStr: invalid unicode sequence. Expecting \u`)
+		d.d.errorf(`json: unquoteStr: invalid unicode sequence. Expecting \u`)
+		return 0
 	}
 	// u, _ := strconv.ParseUint(string(d.bstr[:4]), 16, 64)
 	var u uint32
@@ -867,14 +887,15 @@ func (d *jsonDecDriver) jsonU4(checkSlashU bool) rune {
 		} else if 'A' <= v && v <= 'Z' {
 			v = v - 'A' + 10
 		} else {
-			decErr(`json: unquoteStr: invalid hex char in \u unicode sequence: %q`, v)
+			d.d.errorf(`json: unquoteStr: invalid hex char in \u unicode sequence: %q`, v)
+			return 0
 		}
 		u = u*10 + uint32(v)
 	}
 	return rune(u)
 }
 
-func (d *jsonDecDriver) DecodeNaked(de *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (d *jsonDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	n := d.skipWhitespace(true)
 	switch n {
 	case 'n':
@@ -962,15 +983,15 @@ type JsonHandle struct {
 	textEncodingType
 }
 
-func (h *JsonHandle) newEncDriver(w encWriter) encDriver {
-	return &jsonEncDriver{w: w, h: h}
+func (h *JsonHandle) newEncDriver(e *Encoder) encDriver {
+	return &jsonEncDriver{e: e, w: e.w, h: h}
 }
 
-func (h *JsonHandle) newDecDriver(r decReader) decDriver {
+func (h *JsonHandle) newDecDriver(d *Decoder) decDriver {
 	// d := jsonDecDriver{r: r.(*bytesDecReader), h: h}
-	d := jsonDecDriver{r: r, h: h}
-	d.n.bytes = d.b[:]
-	return &d
+	hd := jsonDecDriver{d: d, r: d.r, h: h}
+	hd.n.bytes = d.b[:]
+	return &hd
 }
 
 var jsonEncodeTerminate = []byte{' '}

+ 42 - 27
codec/msgpack.go

@@ -102,6 +102,7 @@ var (
 //---------------------------------------------
 
 type msgpackEncDriver struct {
+	e *Encoder
 	w encWriter
 	h *MsgpackHandle
 	noBuiltInTypes
@@ -262,6 +263,7 @@ func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
 //---------------------------------------------
 
 type msgpackDecDriver struct {
+	d      *Decoder
 	r      decReader // *Decoder decReader decReaderT
 	h      *MsgpackHandle
 	b      [scratchByteArrayLen]byte
@@ -279,7 +281,7 @@ type msgpackDecDriver struct {
 // 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 *msgpackDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (d *msgpackDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -369,7 +371,8 @@ func (d *msgpackDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType,
 			v = &re
 			vt = valueTypeExt
 		default:
-			decErr("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+			d.d.errorf("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+			return
 		}
 	}
 	if !decodeFurther {
@@ -411,13 +414,15 @@ func (d *msgpackDecDriver) DecodeInt(bitsize uint8) (i int64) {
 		case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
 			i = int64(int8(d.bd))
 		default:
-			decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+			d.d.errorf("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+			return
 		}
 	}
 	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
 	if bitsize > 0 {
 		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
-			decErr("Overflow int value: %v", i)
+			d.d.errorf("Overflow int value: %v", i)
+			return
 		}
 	}
 	d.bdRead = false
@@ -442,40 +447,47 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 		if i := int64(int8(d.r.readn1())); i >= 0 {
 			ui = uint64(i)
 		} else {
-			decErr("Assigning negative signed value: %v, to unsigned type", i)
+			d.d.errorf("Assigning negative signed value: %v, to unsigned type", i)
+			return
 		}
 	case mpInt16:
 		if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 {
 			ui = uint64(i)
 		} else {
-			decErr("Assigning negative signed value: %v, to unsigned type", i)
+			d.d.errorf("Assigning negative signed value: %v, to unsigned type", i)
+			return
 		}
 	case mpInt32:
 		if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 {
 			ui = uint64(i)
 		} else {
-			decErr("Assigning negative signed value: %v, to unsigned type", i)
+			d.d.errorf("Assigning negative signed value: %v, to unsigned type", i)
+			return
 		}
 	case mpInt64:
 		if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 {
 			ui = uint64(i)
 		} else {
-			decErr("Assigning negative signed value: %v, to unsigned type", i)
+			d.d.errorf("Assigning negative signed value: %v, to unsigned type", i)
+			return
 		}
 	default:
 		switch {
 		case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
 			ui = uint64(d.bd)
 		case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
-			decErr("Assigning negative signed value: %v, to unsigned type", int(d.bd))
+			d.d.errorf("Assigning negative signed value: %v, to unsigned type", int(d.bd))
+			return
 		default:
-			decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+			d.d.errorf("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+			return
 		}
 	}
 	// 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)
+			d.d.errorf("Overflow uint value: %v", ui)
+			return
 		}
 	}
 	d.bdRead = false
@@ -495,7 +507,8 @@ func (d *msgpackDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 		f = float64(d.DecodeInt(0))
 	}
 	if chkOverflow32 && chkOvf.Float32(f) {
-		decErr("msgpack: float32 overflow: %v", f)
+		d.d.errorf("msgpack: float32 overflow: %v", f)
+		return
 	}
 	d.bdRead = false
 	return
@@ -511,7 +524,8 @@ func (d *msgpackDecDriver) DecodeBool() (b bool) {
 	} else if d.bd == mpTrue || d.bd == 1 {
 		b = true
 	} else {
-		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		return
 	}
 	d.bdRead = false
 	return
@@ -575,8 +589,8 @@ func (d *msgpackDecDriver) IsContainerType(vt valueType) bool {
 	case valueTypeMap:
 		return bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax)
 	}
-	decErr("isContainerType: unsupported parameter: %v", vt)
-	panic("unreachable")
+	d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+	return false // "unreachable"
 }
 
 func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) {
@@ -603,7 +617,8 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int)
 	} else if (ct.bFixMin & bd) == ct.bFixMin {
 		clen = int(ct.bFixMin ^ bd)
 	} else {
-		decErr("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+		d.d.errorf("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+		return
 	}
 	d.bdRead = false
 	return
@@ -638,14 +653,16 @@ func (d *msgpackDecDriver) readExtLen() (clen int) {
 	case mpExt32:
 		clen = int(bigen.Uint32(d.r.readx(4)))
 	default:
-		decErr("decoding ext bytes: found unexpected byte: %x", d.bd)
+		d.d.errorf("decoding ext bytes: found unexpected byte: %x", d.bd)
+		return
 	}
 	return
 }
 
-func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, dd *Decoder) (realxtag uint64) {
+func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
 	if xtag > 0xff {
-		decErr("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		return
 	}
 	realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
 	realxtag = uint64(realxtag1)
@@ -673,7 +690,8 @@ func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs
 		clen := d.readExtLen()
 		xtag = d.r.readn1()
 		if verifyTag && xtag != tag {
-			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			return
 		}
 		xbs = d.r.readx(clen)
 	}
@@ -704,15 +722,12 @@ type MsgpackHandle struct {
 	WriteExt bool
 }
 
-func (h *MsgpackHandle) newEncDriver(w encWriter) encDriver {
-	return &msgpackEncDriver{w: w, h: h}
+func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver {
+	return &msgpackEncDriver{e: e, w: e.w, h: h}
 }
 
-func (h *MsgpackHandle) newDecDriver(r decReader) decDriver {
-	_, ok := r.(*bytesDecReader)
-	return &msgpackDecDriver{r: r, h: h, br: ok}
-	// d := r.(*Decoder)
-	// return &msgpackDecDriver{r: d, h: h, br: d.bytes}
+func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver {
+	return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes}
 }
 
 //--------------------------------------------------

+ 4 - 4
codec/noop.go

@@ -49,8 +49,8 @@ type noopDrv struct {
 func (h *noopDrv) r(v int) int { return h.rand.Intn(v) }
 func (h *noopDrv) m(v int) int { h.i++; return h.i % v }
 
-func (h *noopDrv) newEncDriver(w encWriter) encDriver { return h }
-func (h *noopDrv) newDecDriver(r decReader) decDriver { return h }
+func (h *noopDrv) newEncDriver(_ *Encoder) encDriver { return h }
+func (h *noopDrv) newDecDriver(_ *Decoder) decDriver { return h }
 
 // --- encDriver
 
@@ -120,11 +120,11 @@ func (h *noopDrv) TryDecodeAsNil() bool {
 		return h.m(8) == 0
 	}
 }
-func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext, d *Decoder) uint64 {
+func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext) uint64 {
 	return 0
 }
 
-func (h *noopDrv) DecodeNaked(d *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (h *noopDrv) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	// use h.r (random) not h.m() because h.m() could cause the same value to be given.
 	var sk int
 	if h.mk {

+ 41 - 25
codec/simple.go

@@ -26,6 +26,7 @@ const (
 )
 
 type simpleEncDriver struct {
+	e *Encoder
 	h *SimpleHandle
 	w encWriter
 	noBuiltInTypes
@@ -145,6 +146,7 @@ func (e *simpleEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
 //------------------------------------
 
 type simpleDecDriver struct {
+	d      *Decoder
 	h      *SimpleHandle
 	r      decReader
 	bdRead bool
@@ -180,8 +182,8 @@ func (d *simpleDecDriver) IsContainerType(vt valueType) bool {
 		const x uint8 = simpleVdMap
 		return d.bd == x || d.bd == x+1 || d.bd == x+2 || d.bd == x+3 || d.bd == x+4
 	}
-	decErr("isContainerType: unsupported parameter: %v", vt)
-	panic("unreachable")
+	d.d.errorf("isContainerType: unsupported parameter: %v", vt)
+	return false // "unreachable"
 }
 
 func (d *simpleDecDriver) TryDecodeAsNil() bool {
@@ -221,11 +223,13 @@ func (d *simpleDecDriver) decCheckInteger() (ui uint64, neg bool) {
 		ui = uint64(bigen.Uint64(d.r.readx(8)))
 		neg = true
 	default:
-		decErr("decIntAny: Integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd)
+		d.d.errorf("decIntAny: Integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd)
+		return
 	}
 	// don't do this check, because callers may only want the unsigned value.
 	// if ui > math.MaxInt64 {
-	// 	decErr("decIntAny: Integer out of range for signed int64: %v", ui)
+	// 	d.d.errorf("decIntAny: Integer out of range for signed int64: %v", ui)
+	//		return
 	// }
 	return
 }
@@ -234,13 +238,15 @@ func (d *simpleDecDriver) DecodeInt(bitsize uint8) (i int64) {
 	ui, neg := d.decCheckInteger()
 	i, overflow := chkOvf.SignedInt(ui)
 	if overflow {
-		decErr("simple: overflow converting %v to signed integer", ui)
+		d.d.errorf("simple: overflow converting %v to signed integer", ui)
+		return
 	}
 	if neg {
 		i = -i
 	}
 	if chkOvf.Int(i, bitsize) {
-		decErr("simple: overflow integer: %v", i)
+		d.d.errorf("simple: overflow integer: %v", i)
+		return
 	}
 	d.bdRead = false
 	return
@@ -249,10 +255,12 @@ func (d *simpleDecDriver) DecodeInt(bitsize uint8) (i int64) {
 func (d *simpleDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	ui, neg := d.decCheckInteger()
 	if neg {
-		decErr("Assigning negative signed value to unsigned type")
+		d.d.errorf("Assigning negative signed value to unsigned type")
+		return
 	}
 	if chkOvf.Uint(ui, bitsize) {
-		decErr("simple: overflow integer: %v", ui)
+		d.d.errorf("simple: overflow integer: %v", ui)
+		return
 	}
 	d.bdRead = false
 	return
@@ -270,11 +278,13 @@ func (d *simpleDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 		if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 {
 			f = float64(d.DecodeInt(64))
 		} else {
-			decErr("Float only valid from float32/64: Invalid descriptor: %v", d.bd)
+			d.d.errorf("Float only valid from float32/64: Invalid descriptor: %v", d.bd)
+			return
 		}
 	}
 	if chkOverflow32 && chkOvf.Float32(f) {
-		decErr("msgpack: float32 overflow: %v", f)
+		d.d.errorf("msgpack: float32 overflow: %v", f)
+		return
 	}
 	d.bdRead = false
 	return
@@ -289,7 +299,8 @@ func (d *simpleDecDriver) DecodeBool() (b bool) {
 		b = true
 	} else if d.bd == simpleVdFalse {
 	} else {
-		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+		return
 	}
 	d.bdRead = false
 	return
@@ -316,17 +327,19 @@ func (d *simpleDecDriver) decLen() int {
 	case 3:
 		ui := uint64(bigen.Uint32(d.r.readx(4)))
 		if chkOvf.Uint(ui, intBitsize) {
-			decErr("simple: overflow integer: %v", ui)
+			d.d.errorf("simple: overflow integer: %v", ui)
+			return 0
 		}
 		return int(ui)
 	case 4:
 		ui := bigen.Uint64(d.r.readx(8))
 		if chkOvf.Uint(ui, intBitsize) {
-			decErr("simple: overflow integer: %v", ui)
+			d.d.errorf("simple: overflow integer: %v", ui)
+			return 0
 		}
 		return int(ui)
 	}
-	decErr("decLen: Cannot read length: bd%8 must be in range 0..4. Got: %d", d.bd%8)
+	d.d.errorf("decLen: Cannot read length: bd%8 must be in range 0..4. Got: %d", d.bd%8)
 	return -1
 }
 
@@ -354,9 +367,10 @@ func (d *simpleDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut
 	return decByteSlice(d.r, clen, bs)
 }
 
-func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext, _ *Decoder) (realxtag uint64) {
+func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
 	if xtag > 0xff {
-		decErr("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		d.d.errorf("decodeExt: tag must be <= 0xff; got: %v", xtag)
+		return
 	}
 	realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag))
 	realxtag = uint64(realxtag1)
@@ -379,19 +393,21 @@ func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs [
 		l := d.decLen()
 		xtag = d.r.readn1()
 		if verifyTag && xtag != tag {
-			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+			return
 		}
 		xbs = d.r.readx(l)
 	case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
 		xbs = d.DecodeBytes(nil, false, true)
 	default:
-		decErr("Invalid d.bd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd)
+		d.d.errorf("Invalid d.bd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd)
+		return
 	}
 	d.bdRead = false
 	return
 }
 
-func (d *simpleDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType, decodeFurther bool) {
+func (d *simpleDecDriver) DecodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
 	if !d.bdRead {
 		d.readNextBd()
 	}
@@ -442,7 +458,8 @@ func (d *simpleDecDriver) DecodeNaked(_ *Decoder) (v interface{}, vt valueType,
 		vt = valueTypeMap
 		decodeFurther = true
 	default:
-		decErr("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
+		d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
+		return
 	}
 
 	if !decodeFurther {
@@ -476,13 +493,12 @@ type SimpleHandle struct {
 	binaryEncodingType
 }
 
-func (h *SimpleHandle) newEncDriver(w encWriter) encDriver {
-	return &simpleEncDriver{w: w, h: h}
+func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver {
+	return &simpleEncDriver{e: e, w: e.w, h: h}
 }
 
-func (h *SimpleHandle) newDecDriver(r decReader) decDriver {
-	_, ok := r.(*bytesDecReader)
-	return &simpleDecDriver{r: r, h: h, br: ok}
+func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver {
+	return &simpleDecDriver{d: d, r: d.r, h: h, br: d.bytes}
 }
 
 var _ decDriver = (*simpleDecDriver)(nil)