Browse Source

codec: streamline panic/recover error handling, manage compatibility with codecgen and support structs where fields are encoded as numbers

Add diagnostic information (encode format, num bytes read, etc) to error on panic-recover.
This required the following changes:
- errors are either exposed as a string or an error, and used as the panic value
- on recover (in Encoder.Encode or Decoder.Decode), we add diagnostics to the panic value and return as error

encDriver for a handle should not check for overflow32 - instead, just expose a DecodeFloat64() method

We currently keep some deprecated methods alive in (en|de)cDriver, so that codecgen will not need to be re-done.
Instead, for compatibility in codecgen, make the r variable a struct wrapping (en|de)cDriver.
Thereafter, add the compatibility functions, so they can be removed from (en|de)cDriver.

Make clear that float overflow doesn't mean that the number maintains its precision.

In JSON, always encode and decode as float64.
If not, we lose precision when we encode as float32 and decode back as float64 (e.g. for math.MaxFloat32).

Support encoding/decoding structs where the encoded stream should use number codes for the field names (instead of strings).
This is now supported by configuring the key type on the _struct field,
and supported in codecgen and in the reflection-based general support.
See documentation on (*Encoder).Encode.
Ugorji Nwoke 8 years ago
parent
commit
4d084a8659

+ 4 - 5
codec/binc.go

@@ -554,7 +554,7 @@ func (d *bincDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	return
 	return
 }
 }
 
 
-func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+func (d *bincDecDriver) DecodeFloat64() (f float64) {
 	if !d.bdRead {
 	if !d.bdRead {
 		d.readNextBd()
 		d.readNextBd()
 	}
 	}
@@ -578,10 +578,6 @@ func (d *bincDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	} else {
 	} else {
 		f = float64(d.DecodeInt(64))
 		f = float64(d.DecodeInt(64))
 	}
 	}
-	if chkOverflow32 && chkOvf.Float32(f) {
-		d.d.errorf("binc: float32 overflow: %v", f)
-		return
-	}
 	d.bdRead = false
 	d.bdRead = false
 	return
 	return
 }
 }
@@ -938,6 +934,9 @@ type BincHandle struct {
 	noElemSeparators
 	noElemSeparators
 }
 }
 
 
+// Name returns the name of the handle: binc
+func (h *BincHandle) Name() string { return "binc" }
+
 // SetBytesExt sets an extension
 // SetBytesExt sets an extension
 func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})

+ 9 - 13
codec/cbor.go

@@ -389,7 +389,7 @@ func (d *cborDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	return
 	return
 }
 }
 
 
-func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+func (d *cborDecDriver) DecodeFloat64() (f float64) {
 	if !d.bdRead {
 	if !d.bdRead {
 		d.readNextBd()
 		d.readNextBd()
 	}
 	}
@@ -405,10 +405,6 @@ func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 		d.d.errorf("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
 		return
 	}
 	}
-	if chkOverflow32 && chkOvf.Float32(f) {
-		d.d.errorf("cbor: float32 overflow: %v", f)
-		return
-	}
 	d.bdRead = false
 	d.bdRead = false
 	return
 	return
 }
 }
@@ -544,17 +540,17 @@ func (d *cborDecDriver) decodeTime(xtag uint64) (t time.Time) {
 	case 0:
 	case 0:
 		var err error
 		var err error
 		if t, err = time.Parse(time.RFC3339, stringView(d.DecodeStringAsBytes())); err != nil {
 		if t, err = time.Parse(time.RFC3339, stringView(d.DecodeStringAsBytes())); err != nil {
-			d.d.error(err)
+			d.d.errorv(err)
 		}
 		}
 	case 1:
 	case 1:
 		// decode an int64 or a float, and infer time.Time from there.
 		// decode an int64 or a float, and infer time.Time from there.
 		// for floats, round to microseconds, as that is what is guaranteed to fit well.
 		// for floats, round to microseconds, as that is what is guaranteed to fit well.
 		switch {
 		switch {
 		case d.bd == cborBdFloat16, d.bd == cborBdFloat32:
 		case d.bd == cborBdFloat16, d.bd == cborBdFloat32:
-			f1, f2 := math.Modf(d.DecodeFloat(true))
+			f1, f2 := math.Modf(d.DecodeFloat64())
 			t = time.Unix(int64(f1), int64(f2*1e9))
 			t = time.Unix(int64(f1), int64(f2*1e9))
 		case d.bd == cborBdFloat64:
 		case d.bd == cborBdFloat64:
-			f1, f2 := math.Modf(d.DecodeFloat(false))
+			f1, f2 := math.Modf(d.DecodeFloat64())
 			t = time.Unix(int64(f1), int64(f2*1e9))
 			t = time.Unix(int64(f1), int64(f2*1e9))
 		case d.bd >= cborBaseUint && d.bd < cborBaseNegInt, d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
 		case d.bd >= cborBaseUint && d.bd < cborBaseNegInt, d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
 			t = time.Unix(d.DecodeInt(64), 0)
 			t = time.Unix(d.DecodeInt(64), 0)
@@ -608,12 +604,9 @@ func (d *cborDecDriver) DecodeNaked() {
 	case cborBdTrue:
 	case cborBdTrue:
 		n.v = valueTypeBool
 		n.v = valueTypeBool
 		n.b = true
 		n.b = true
-	case cborBdFloat16, cborBdFloat32:
+	case cborBdFloat16, cborBdFloat32, cborBdFloat64:
 		n.v = valueTypeFloat
 		n.v = valueTypeFloat
-		n.f = d.DecodeFloat(true)
-	case cborBdFloat64:
-		n.v = valueTypeFloat
-		n.f = d.DecodeFloat(false)
+		n.f = d.DecodeFloat64()
 	case cborBdIndefiniteBytes:
 	case cborBdIndefiniteBytes:
 		n.v = valueTypeBytes
 		n.v = valueTypeBytes
 		n.l = d.DecodeBytes(nil, false)
 		n.l = d.DecodeBytes(nil, false)
@@ -705,6 +698,9 @@ type CborHandle struct {
 	TimeRFC3339 bool
 	TimeRFC3339 bool
 }
 }
 
 
+// Name returns the name of the handle: cbor
+func (h *CborHandle) Name() string { return "cbor" }
+
 // SetInterfaceExt sets an extension
 // SetInterfaceExt sets an extension
 func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
 func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
 	return h.SetExt(rt, tag, &setExtWrapper{i: ext})
 	return h.SetExt(rt, tag, &setExtWrapper{i: ext})

+ 2 - 2
codec/codec_test.go

@@ -366,12 +366,12 @@ func testInit() {
 	// and use on some places for testSimpleH e.g. for time.Time and wrapInt64
 	// and use on some places for testSimpleH e.g. for time.Time and wrapInt64
 	var (
 	var (
 		myExtEncFn = func(x BytesExt, rv reflect.Value) (bs []byte, err error) {
 		myExtEncFn = func(x BytesExt, rv reflect.Value) (bs []byte, err error) {
-			defer panicToErr(&err)
+			defer panicToErr(errstrDecoratorDef{}, &err)
 			bs = x.WriteExt(rv.Interface())
 			bs = x.WriteExt(rv.Interface())
 			return
 			return
 		}
 		}
 		myExtDecFn = func(x BytesExt, rv reflect.Value, bs []byte) (err error) {
 		myExtDecFn = func(x BytesExt, rv reflect.Value, bs []byte) (err error) {
-			defer panicToErr(&err)
+			defer panicToErr(errstrDecoratorDef{}, &err)
 			x.ReadExt(rv.Interface(), bs)
 			x.ReadExt(rv.Interface(), bs)
 			return
 			return
 		}
 		}

+ 58 - 59
codec/decode.go

@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"reflect"
 	"reflect"
+	"strconv"
 	"sync"
 	"sync"
 	"time"
 	"time"
 )
 )
@@ -20,8 +21,11 @@ const (
 )
 )
 
 
 var (
 var (
-	errOnlyMapOrArrayCanDecodeIntoStruct = errors.New("only encoded map or array can be decoded into a struct")
-	errCannotDecodeIntoNil               = errors.New("cannot decode into nil")
+	errstrOnlyMapOrArrayCanDecodeIntoStruct = "only encoded map or array can be decoded into a struct"
+	errstrCannotDecodeIntoNil               = "cannot decode into nil"
+
+	errmsgExpandSliceOverflow     = "expand slice: slice overflow"
+	errmsgExpandSliceCannotChange = "expand slice: cannot change"
 
 
 	errDecUnreadByteNothingToRead   = errors.New("cannot unread - nothing has been read")
 	errDecUnreadByteNothingToRead   = errors.New("cannot unread - nothing has been read")
 	errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read")
 	errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read")
@@ -63,9 +67,6 @@ type decDriver interface {
 	ContainerType() (vt valueType)
 	ContainerType() (vt valueType)
 	// IsBuiltinType(rt uintptr) bool
 	// IsBuiltinType(rt uintptr) bool
 
 
-	// Deprecated: left here for now so that old codecgen'ed filed will work. TODO: remove.
-	DecodeBuiltin(rt uintptr, v interface{})
-
 	// DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt.
 	// DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt.
 	// For maps and arrays, it will not do the decoding in-band, but will signal
 	// For maps and arrays, it will not do the decoding in-band, but will signal
 	// the decoder, so that is done later, by setting the decNaked.valueType field.
 	// the decoder, so that is done later, by setting the decNaked.valueType field.
@@ -78,11 +79,12 @@ type decDriver interface {
 	// extensions should also use readx to decode them, for efficiency.
 	// 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.
 	// kInterface will extract the detached byte slice if it has to pass it outside its realm.
 	DecodeNaked()
 	DecodeNaked()
+
 	DecodeInt(bitsize uint8) (i int64)
 	DecodeInt(bitsize uint8) (i int64)
 	DecodeUint(bitsize uint8) (ui uint64)
 	DecodeUint(bitsize uint8) (ui uint64)
-	DecodeFloat(chkOverflow32 bool) (f float64)
+
+	DecodeFloat64() (f float64)
 	DecodeBool() (b bool)
 	DecodeBool() (b bool)
-	DecodeTime() (t time.Time)
 	// DecodeString can also decode symbols.
 	// DecodeString can also decode symbols.
 	// It looks redundant as DecodeBytes is available.
 	// It looks redundant as DecodeBytes is available.
 	// However, some codecs (e.g. binc) support symbols and can
 	// However, some codecs (e.g. binc) support symbols and can
@@ -99,6 +101,9 @@ type decDriver interface {
 	// decodeExt will decode into a *RawExt or into an extension.
 	// decodeExt will decode into a *RawExt or into an extension.
 	DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64)
 	DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64)
 	// decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
 	// decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
+
+	DecodeTime() (t time.Time)
+
 	ReadArrayStart() int
 	ReadArrayStart() int
 	ReadArrayElem()
 	ReadArrayElem()
 	ReadArrayEnd()
 	ReadArrayEnd()
@@ -1125,6 +1130,22 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
 	rv.Set(rvn2)
 	rv.Set(rvn2)
 }
 }
 
 
+func decStructFieldKey(dd decDriver, keyType valueType, b *[scratchByteArrayLen]byte) (rvkencname []byte) {
+	switch keyType {
+	case valueTypeString:
+		rvkencname = (dd.DecodeStringAsBytes())
+	case valueTypeInt:
+		rvkencname = (strconv.AppendInt(b[:0], dd.DecodeInt(64), 10))
+	case valueTypeUint:
+		rvkencname = (strconv.AppendUint(b[:0], dd.DecodeUint(64), 10))
+	case valueTypeFloat:
+		rvkencname = (strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64))
+	default: // string
+		rvkencname = (dd.DecodeStringAsBytes())
+	}
+	return
+}
+
 func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 	fti := f.ti
 	fti := f.ti
 	dd := d.d
 	dd := d.d
@@ -1140,14 +1161,12 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 		tisfi := fti.sfi
 		tisfi := fti.sfi
 		hasLen := containerLen >= 0
 		hasLen := containerLen >= 0
 
 
+		var rvkencname string
 		for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
 		for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
-			// rvkencname := dd.DecodeString()
 			if elemsep {
 			if elemsep {
 				dd.ReadMapElemKey()
 				dd.ReadMapElemKey()
 			}
 			}
-			rvkencnameB := dd.DecodeStringAsBytes()
-			rvkencname := stringView(rvkencnameB)
-			// rvksi := ti.getForEncName(rvkencname)
+			rvkencname = stringView(decStructFieldKey(dd, fti.keyType, &d.b))
 			if elemsep {
 			if elemsep {
 				dd.ReadMapElemValue()
 				dd.ReadMapElemValue()
 			}
 			}
@@ -1197,7 +1216,7 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 		}
 		}
 		dd.ReadArrayEnd()
 		dd.ReadArrayEnd()
 	} else {
 	} else {
-		d.error(errOnlyMapOrArrayCanDecodeIntoStruct)
+		d.errorstr(errstrOnlyMapOrArrayCanDecodeIntoStruct)
 		return
 		return
 	}
 	}
 }
 }
@@ -1365,7 +1384,11 @@ func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) {
 				} else { // if f.seq == seqTypeSlice
 				} else { // if f.seq == seqTypeSlice
 					// rv = reflect.Append(rv, reflect.Zero(rtelem0)) // uses append logic, plus varargs
 					// rv = reflect.Append(rv, reflect.Zero(rtelem0)) // uses append logic, plus varargs
 					var rvcap2 int
 					var rvcap2 int
-					rv9, rvcap2, rvChanged = d.expandSliceRV(rv, ti.rt, rvCanset, rtelem0Size, 1, rvlen, rvcap)
+					var rvErrmsg2 string
+					rv9, rvcap2, rvChanged, rvErrmsg2 = expandSliceRV(rv, ti.rt, rvCanset, rtelem0Size, 1, rvlen, rvcap)
+					if rvErrmsg2 != "" {
+						d.errorf(rvErrmsg2)
+					}
 					rvlen++
 					rvlen++
 					if rvChanged {
 					if rvChanged {
 						rv = rv9
 						rv = rv9
@@ -1765,6 +1788,7 @@ type decReaderSwitch struct {
 
 
 // A Decoder reads and decodes an object from an input stream in the codec format.
 // A Decoder reads and decodes an object from an input stream in the codec format.
 type Decoder struct {
 type Decoder struct {
+	panicHdl
 	// hopefully, reduce derefencing cost by laying the decReader inside the Decoder.
 	// 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).
 	// Try to put things that go together to fit within a cache line (8 words).
 
 
@@ -1961,7 +1985,7 @@ func (d *Decoder) ResetBytes(in []byte) {
 // Note: we allow nil values in the stream anywhere except for map keys.
 // Note: we allow nil values in the stream anywhere except for map keys.
 // A nil value in the encoded stream where a map key is expected is treated as an error.
 // A nil value in the encoded stream where a map key is expected is treated as an error.
 func (d *Decoder) Decode(v interface{}) (err error) {
 func (d *Decoder) Decode(v interface{}) (err error) {
-	defer panicToErrs2(&d.err, &err)
+	defer panicToErrs2(d, &d.err, &err)
 	d.MustDecode(v)
 	d.MustDecode(v)
 	return
 	return
 }
 }
@@ -2109,7 +2133,7 @@ func (d *Decoder) decode(iv interface{}) {
 	// check nil and interfaces explicitly,
 	// check nil and interfaces explicitly,
 	// so that type switches just have a run of constant non-interface types.
 	// so that type switches just have a run of constant non-interface types.
 	if iv == nil {
 	if iv == nil {
-		d.error(errCannotDecodeIntoNil)
+		d.errorstr(errstrCannotDecodeIntoNil)
 		return
 		return
 	}
 	}
 	if v, ok := iv.(Selfer); ok {
 	if v, ok := iv.(Selfer); ok {
@@ -2150,9 +2174,13 @@ func (d *Decoder) decode(iv interface{}) {
 	case *uint64:
 	case *uint64:
 		*v = d.d.DecodeUint(64)
 		*v = d.d.DecodeUint(64)
 	case *float32:
 	case *float32:
-		*v = float32(d.d.DecodeFloat(true))
+		f64 := d.d.DecodeFloat64()
+		if chkOvf.Float32(f64) {
+			d.errorf("float32 overflow: %v", f64)
+		}
+		*v = float32(f64)
 	case *float64:
 	case *float64:
-		*v = d.d.DecodeFloat(false)
+		*v = d.d.DecodeFloat64()
 	case *[]uint8:
 	case *[]uint8:
 		*v = d.d.DecodeBytes(*v, false)
 		*v = d.d.DecodeBytes(*v, false)
 	case []uint8:
 	case []uint8:
@@ -2266,7 +2294,7 @@ func (d *Decoder) ensureDecodeable(rv reflect.Value) (rv2 reflect.Value) {
 		return
 		return
 	}
 	}
 	if !rv.IsValid() {
 	if !rv.IsValid() {
-		d.error(errCannotDecodeIntoNil)
+		d.errorstr(errstrCannotDecodeIntoNil)
 		return
 		return
 	}
 	}
 	if !rv.CanInterface() {
 	if !rv.CanInterface() {
@@ -2279,42 +2307,6 @@ func (d *Decoder) ensureDecodeable(rv reflect.Value) (rv2 reflect.Value) {
 	return
 	return
 }
 }
 
 
-// func (d *Decoder) chkPtrValue(rv reflect.Value) {
-// 	// We can only decode into a non-nil pointer
-// 	if rv.Kind() == reflect.Ptr && !rv.IsNil() {
-// 		return
-// 	}
-// 	d.errNotValidPtrValue(rv)
-// }
-
-// func (d *Decoder) errNotValidPtrValue(rv reflect.Value) {
-// 	if !rv.IsValid() {
-// 		d.error(errCannotDecodeIntoNil)
-// 		return
-// 	}
-// 	if !rv.CanInterface() {
-// 		d.errorf("cannot decode into a value without an interface: %v", rv)
-// 		return
-// 	}
-// 	rvi := rv2i(rv)
-// 	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) errorvf(format string, params ...interface{}) (err error) {
-	params2 := make([]interface{}, len(params)+1)
-	params2[0] = d.r.numread()
-	copy(params2[1:], params)
-	return fmt.Errorf("[pos %d]: "+format, params2...)
-}
-
-func (d *Decoder) errorf(format string, params ...interface{}) {
-	panic(d.errorvf(format, params...))
-}
-
 // Possibly get an interned version of a string
 // Possibly get an interned version of a string
 //
 //
 // This should mostly be used for map keys, where the key type is string.
 // This should mostly be used for map keys, where the key type is string.
@@ -2349,6 +2341,10 @@ func (d *Decoder) rawBytes() []byte {
 	return bs2
 	return bs2
 }
 }
 
 
+func (d *Decoder) wrapErrstr(v interface{}, err *error) {
+	*err = fmt.Errorf("%s decode error [pos %d]: %v", d.hh.Name(), d.r.numread(), v)
+}
+
 // --------------------------------------------------
 // --------------------------------------------------
 
 
 // decSliceHelper assists when decoding into a slice, from a map or an array in the stream.
 // decSliceHelper assists when decoding into a slice, from a map or an array in the stream.
@@ -2469,11 +2465,12 @@ func decInferLen(clen, maxlen, unit int) (rvlen int) {
 	return
 	return
 }
 }
 
 
-func (d *Decoder) expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize, num, slen, scap int) (
-	s2 reflect.Value, scap2 int, changed bool) {
+func expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize, num, slen, scap int) (
+	s2 reflect.Value, scap2 int, changed bool, err string) {
 	l1 := slen + num // new slice length
 	l1 := slen + num // new slice length
 	if l1 < slen {
 	if l1 < slen {
-		d.errorf("expand slice: slice overflow")
+		err = errmsgExpandSliceOverflow
+		return
 	}
 	}
 	if l1 <= scap {
 	if l1 <= scap {
 		if s.CanSet() {
 		if s.CanSet() {
@@ -2483,12 +2480,14 @@ func (d *Decoder) expandSliceRV(s reflect.Value, st reflect.Type, canChange bool
 			scap2 = scap
 			scap2 = scap
 			changed = true
 			changed = true
 		} else {
 		} else {
-			d.errorf("expand slice: cannot change")
+			err = errmsgExpandSliceCannotChange
+			return
 		}
 		}
 		return
 		return
 	}
 	}
 	if !canChange {
 	if !canChange {
-		d.errorf("expand slice: cannot change")
+		err = errmsgExpandSliceCannotChange
+		return
 	}
 	}
 	scap2 = growCap(scap, stElemSize, num)
 	scap2 = growCap(scap, stElemSize, num)
 	s2 = reflect.MakeSlice(st, l1, scap2)
 	s2 = reflect.MakeSlice(st, l1, scap2)

+ 65 - 152
codec/encode.go

@@ -11,6 +11,7 @@ import (
 	"io"
 	"io"
 	"reflect"
 	"reflect"
 	"sort"
 	"sort"
+	"strconv"
 	"sync"
 	"sync"
 	"time"
 	"time"
 )
 )
@@ -178,30 +179,6 @@ type simpleIoEncWriter struct {
 	io.Writer
 	io.Writer
 }
 }
 
 
-// type bufIoEncWriter struct {
-// 	w   io.Writer
-// 	buf []byte
-// 	err error
-// }
-
-// func (x *bufIoEncWriter) Write(b []byte) (n int, err error) {
-// 	if x.err != nil {
-// 		return 0, x.err
-// 	}
-// 	if cap(x.buf)-len(x.buf) >= len(b) {
-// 		x.buf = append(x.buf, b)
-// 		return len(b), nil
-// 	}
-// 	n, err = x.w.Write(x.buf)
-// 	if err != nil {
-// 		x.err = err
-// 		return 0, x.err
-// 	}
-// 	n, err = x.w.Write(b)
-// 	x.err = err
-// 	return
-// }
-
 // ioEncWriter implements encWriter and can write to an io.Writer implementation
 // ioEncWriter implements encWriter and can write to an io.Writer implementation
 type ioEncWriter struct {
 type ioEncWriter struct {
 	w  io.Writer
 	w  io.Writer
@@ -271,84 +248,6 @@ func (z *ioEncWriter) atEndOfEncode() {
 	}
 	}
 }
 }
 
 
-// // ----------------------------------------
-
-// // bytesEncWriter implements encWriter and can write to an byte slice.
-// // It is used by Marshal function.
-// type bytesEncWriter struct {
-// 	b   []byte
-// 	c   int     // cursor
-// 	out *[]byte // write out on atEndOfEncode
-// }
-
-// func (z *bytesEncWriter) writeb(s []byte) {
-// 	oc, a := z.growNoAlloc(len(s))
-// 	if a {
-// 		z.growAlloc(len(s), oc)
-// 	}
-// 	copy(z.b[oc:], s)
-// }
-
-// func (z *bytesEncWriter) writestr(s string) {
-// 	oc, a := z.growNoAlloc(len(s))
-// 	if a {
-// 		z.growAlloc(len(s), oc)
-// 	}
-// 	copy(z.b[oc:], s)
-// }
-
-// func (z *bytesEncWriter) writen1(b1 byte) {
-// 	oc, a := z.growNoAlloc(1)
-// 	if a {
-// 		z.growAlloc(1, oc)
-// 	}
-// 	z.b[oc] = b1
-// }
-
-// func (z *bytesEncWriter) writen2(b1, b2 byte) {
-// 	oc, a := z.growNoAlloc(2)
-// 	if a {
-// 		z.growAlloc(2, oc)
-// 	}
-// 	z.b[oc+1] = b2
-// 	z.b[oc] = b1
-// }
-
-// func (z *bytesEncWriter) atEndOfEncode() {
-// 	*(z.out) = z.b[:z.c]
-// }
-
-// // have a growNoalloc(n int), which can be inlined.
-// // if allocation is needed, then call growAlloc(n int)
-
-// func (z *bytesEncWriter) growNoAlloc(n int) (oldcursor int, allocNeeded bool) {
-// 	oldcursor = z.c
-// 	z.c = z.c + n
-// 	if z.c > len(z.b) {
-// 		if z.c > cap(z.b) {
-// 			allocNeeded = true
-// 		} else {
-// 			z.b = z.b[:cap(z.b)]
-// 		}
-// 	}
-// 	return
-// }
-
-// func (z *bytesEncWriter) growAlloc(n int, oldcursor int) {
-// 	// appendslice logic (if cap < 1024, *2, else *1.25): more expensive. many copy calls.
-// 	// bytes.Buffer model (2*cap + n): much better
-// 	// bs := make([]byte, 2*cap(z.b)+n)
-// 	bs := make([]byte, growCap(cap(z.b), 1, n))
-// 	copy(bs, z.b[:oldcursor])
-// 	z.b = bs
-// }
-
-// func (z *bytesEncWriter) reset(in []byte, out *[]byte) {
-// 	z.out = out
-// 	z.b = in
-// 	z.c = 0
-// }
-
 // ---------------------------------------------
 // ---------------------------------------------
 
 
 // bytesEncAppender implements encWriter and can write to an byte slice.
 // bytesEncAppender implements encWriter and can write to an byte slice.
@@ -384,16 +283,6 @@ func (z *bytesEncAppender) reset(in []byte, out *[]byte) {
 // }
 // }
 
 
 func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
-	// rev := rv2i(rv).(RawExt)
-	// e.e.EncodeRawExt(&rev, e)
-	// var re *RawExt
-	// if rv.CanAddr() {
-	// 	re = rv2i(rv.Addr()).(*RawExt)
-	// } else {
-	// 	rev := rv2i(rv).(RawExt)
-	// 	re = &rev
-	// }
-	// e.e.EncodeRawExt(re, e)
 	e.e.EncodeRawExt(rv2i(rv).(*RawExt), e)
 	e.e.EncodeRawExt(rv2i(rv).(*RawExt), e)
 }
 }
 
 
@@ -580,37 +469,29 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
 		ee.WriteMapStart(len(tisfi))
 		ee.WriteMapStart(len(tisfi))
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
-		if !elemsep {
+		if elemsep {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
-				if asSymbols {
-					ee.EncodeSymbol(si.encName)
-				} else {
-					ee.EncodeString(cUTF8, si.encName)
-				}
+				ee.WriteMapElemKey()
+				encStructFieldKey(ee, fti.keyType, si.encName, asSymbols)
+				ee.WriteMapElemValue()
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
 		} else {
 		} else {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
-				ee.WriteMapElemKey()
-				if asSymbols {
-					ee.EncodeSymbol(si.encName)
-				} else {
-					ee.EncodeString(cUTF8, si.encName)
-				}
-				ee.WriteMapElemValue()
+				encStructFieldKey(ee, fti.keyType, si.encName, asSymbols)
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
 		}
 		}
 		ee.WriteMapEnd()
 		ee.WriteMapEnd()
 	} else {
 	} else {
 		ee.WriteArrayStart(len(tisfi))
 		ee.WriteArrayStart(len(tisfi))
-		if !elemsep {
+		if elemsep {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
+				ee.WriteArrayElem()
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
 		} else {
 		} else {
 			for _, si := range tisfi {
 			for _, si := range tisfi {
-				ee.WriteArrayElem()
 				e.encodeValue(sfn.field(si), nil, true)
 				e.encodeValue(sfn.field(si), nil, true)
 			}
 			}
 		}
 		}
@@ -618,6 +499,30 @@ func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) {
 	}
 	}
 }
 }
 
 
+func encStructFieldKey(ee encDriver, keyType valueType, s string, asSymbols bool) {
+	var m must
+	switch keyType {
+	case valueTypeString:
+		if asSymbols {
+			ee.EncodeSymbol(s)
+		} else {
+			ee.EncodeString(cUTF8, s)
+		}
+	case valueTypeInt:
+		ee.EncodeInt(m.Int(strconv.ParseInt(s, 10, 64)))
+	case valueTypeUint:
+		ee.EncodeUint(m.Uint(strconv.ParseUint(s, 10, 64)))
+	case valueTypeFloat:
+		ee.EncodeFloat64(m.Float(strconv.ParseFloat(s, 64)))
+	default: // string
+		if asSymbols {
+			ee.EncodeSymbol(s)
+		} else {
+			ee.EncodeString(cUTF8, s)
+		}
+	}
+}
+
 func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 	fti := f.ti
 	fti := f.ti
 	elemsep := e.esep
 	elemsep := e.esep
@@ -694,39 +599,31 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) {
 		ee.WriteMapStart(newlen)
 		ee.WriteMapStart(newlen)
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
 		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
-		if !elemsep {
+		if elemsep {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
 				kv = fkvs[j]
-				if asSymbols {
-					ee.EncodeSymbol(kv.v)
-				} else {
-					ee.EncodeString(cUTF8, kv.v)
-				}
+				ee.WriteMapElemKey()
+				encStructFieldKey(ee, fti.keyType, kv.v, asSymbols)
+				ee.WriteMapElemValue()
 				e.encodeValue(kv.r, nil, true)
 				e.encodeValue(kv.r, nil, true)
 			}
 			}
 		} else {
 		} else {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
 				kv = fkvs[j]
 				kv = fkvs[j]
-				ee.WriteMapElemKey()
-				if asSymbols {
-					ee.EncodeSymbol(kv.v)
-				} else {
-					ee.EncodeString(cUTF8, kv.v)
-				}
-				ee.WriteMapElemValue()
+				encStructFieldKey(ee, fti.keyType, kv.v, asSymbols)
 				e.encodeValue(kv.r, nil, true)
 				e.encodeValue(kv.r, nil, true)
 			}
 			}
 		}
 		}
 		ee.WriteMapEnd()
 		ee.WriteMapEnd()
 	} else {
 	} else {
 		ee.WriteArrayStart(newlen)
 		ee.WriteArrayStart(newlen)
-		if !elemsep {
+		if elemsep {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
+				ee.WriteArrayElem()
 				e.encodeValue(fkvs[j].r, nil, true)
 				e.encodeValue(fkvs[j].r, nil, true)
 			}
 			}
 		} else {
 		} else {
 			for j := 0; j < newlen; j++ {
 			for j := 0; j < newlen; j++ {
-				ee.WriteArrayElem()
 				e.encodeValue(fkvs[j].r, nil, true)
 				e.encodeValue(fkvs[j].r, nil, true)
 			}
 			}
 		}
 		}
@@ -1055,6 +952,7 @@ type encWriterSwitch struct {
 
 
 // An Encoder writes an object to an output stream in the codec format.
 // An Encoder writes an object to an output stream in the codec format.
 type Encoder struct {
 type Encoder struct {
+	panicHdl
 	// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
 	// hopefully, reduce derefencing cost by laying the encWriter inside the Encoder
 	e encDriver
 	e encDriver
 	// NOTE: Encoder shouldn't call it's write methods,
 	// NOTE: Encoder shouldn't call it's write methods,
@@ -1180,7 +1078,14 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 // Note that the "json" key is used in the absence of the "codec" key.
 // Note that the "json" key is used in the absence of the "codec" key.
 //
 //
 // To set an option on all fields (e.g. omitempty on all fields), you
 // 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.
+// can create a field called _struct, and set flags on it. The options
+// which can be set on _struct are:
+//    - omitempty: so all fields are omitted if empty
+//    - toarray: so struct is encoded as an array
+//    - int: so struct key names are encoded as signed integers (instead of strings)
+//    - uint: so struct key names are encoded as unsigned integers (instead of strings)
+//    - float: so struct key names are encoded as floats (instead of strings)
+// More details on these below.
 //
 //
 // Struct values "usually" encode as maps. Each exported struct field is encoded unless:
 // Struct values "usually" encode as maps. Each exported struct field is encoded unless:
 //    - the field's tag is "-", OR
 //    - the field's tag is "-", OR
@@ -1188,6 +1093,13 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 //
 //
 // When encoding as a map, the first string in the tag (before the comma)
 // When encoding as a map, the first string in the tag (before the comma)
 // is the map key string to use when encoding.
 // is the map key string to use when encoding.
+// ...
+// This key is typically encoded as a string.
+// However, there are instances where the encoded stream has mapping keys encoded as numbers.
+// For example, some cbor streams have keys as integer codes in the stream, but they should map
+// to fields in a structured object. Consequently, a struct is the natural representation in code.
+// For these, you can configure the struct to encode/decode the keys as numbers (instead of string).
+// This is done with the int,uint or float option on the _struct field (see above).
 //
 //
 // However, struct values may encode as arrays. This happens when:
 // However, struct values may encode as arrays. This happens when:
 //    - StructToArray Encode option is set, OR
 //    - StructToArray Encode option is set, OR
@@ -1220,7 +1132,13 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 //      }
 //      }
 //
 //
 //      type MyStruct struct {
 //      type MyStruct struct {
-//          _struct bool    `codec:",toarray"`   //encode struct as an array
+//          _struct bool    `codec:",toarray"`     //encode struct as an array
+//      }
+//
+//      type MyStruct struct {
+//          _struct bool    `codec:",uint"`        //encode struct with "unsigned integer" keys
+//          Field1 string   `codec:"1"`            //encode Field1 key using: EncodeInt(1)
+//          Field2 string   `codec:"2"`            //encode Field2 key using: EncodeInt(2)
 //      }
 //      }
 //
 //
 // The mode of encoding is based on the type of the value. When a value is seen:
 // The mode of encoding is based on the type of the value. When a value is seen:
@@ -1233,7 +1151,7 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 // Some formats support symbols (e.g. binc) and will properly encode the string
 // 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.
 // only once in the stream, and use a tag to refer to it thereafter.
 func (e *Encoder) Encode(v interface{}) (err error) {
 func (e *Encoder) Encode(v interface{}) (err error) {
-	defer panicToErrs2(&e.err, &err)
+	defer panicToErrs2(e, &e.err, &err)
 	e.MustEncode(v)
 	e.MustEncode(v)
 	return
 	return
 }
 }
@@ -1445,11 +1363,6 @@ func (e *Encoder) rawBytes(vv Raw) {
 	e.asis(v)
 	e.asis(v)
 }
 }
 
 
-func (e *Encoder) errorf(format string, params ...interface{}) {
-	err := fmt.Errorf(format, params...)
-	panic(err)
-}
-
-func (e *Encoder) error(err error) {
-	panic(err)
+func (e *Encoder) wrapErrstr(v interface{}, err *error) {
+	*err = fmt.Errorf("%s encode error: %v", e.hh.Name(), v)
 }
 }

+ 66 - 66
codec/fast-path.generated.go

@@ -16473,7 +16473,7 @@ func (_ fastpathT) DecSliceFloat32V(v []float32, canChange bool, d *Decoder) (_
 		} else if dd.TryDecodeAsNil() {
 		} else if dd.TryDecodeAsNil() {
 			v[j] = 0
 			v[j] = 0
 		} else {
 		} else {
-			v[j] = float32(dd.DecodeFloat(true))
+			v[j] = float32(chkFloat32(dd.DecodeFloat64()))
 		}
 		}
 	}
 	}
 	if canChange {
 	if canChange {
@@ -16569,7 +16569,7 @@ func (_ fastpathT) DecSliceFloat64V(v []float64, canChange bool, d *Decoder) (_
 		} else if dd.TryDecodeAsNil() {
 		} else if dd.TryDecodeAsNil() {
 			v[j] = 0
 			v[j] = 0
 		} else {
 		} else {
-			v[j] = dd.DecodeFloat(false)
+			v[j] = dd.DecodeFloat64()
 		}
 		}
 	}
 	}
 	if canChange {
 	if canChange {
@@ -18616,7 +18616,7 @@ func (_ fastpathT) DecMapIntfFloat32V(v map[interface{}]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -18679,7 +18679,7 @@ func (_ fastpathT) DecMapIntfFloat64V(v map[interface{}]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -19574,7 +19574,7 @@ func (_ fastpathT) DecMapStringFloat32V(v map[string]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -19633,7 +19633,7 @@ func (_ fastpathT) DecMapStringFloat64V(v map[string]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -19739,7 +19739,7 @@ func (_ fastpathT) DecMapFloat32IntfV(v map[float32]interface{}, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -19803,7 +19803,7 @@ func (_ fastpathT) DecMapFloat32StringV(v map[float32]string, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -19862,7 +19862,7 @@ func (_ fastpathT) DecMapFloat32UintV(v map[float32]uint, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -19921,7 +19921,7 @@ func (_ fastpathT) DecMapFloat32Uint8V(v map[float32]uint8, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -19980,7 +19980,7 @@ func (_ fastpathT) DecMapFloat32Uint16V(v map[float32]uint16, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20039,7 +20039,7 @@ func (_ fastpathT) DecMapFloat32Uint32V(v map[float32]uint32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20098,7 +20098,7 @@ func (_ fastpathT) DecMapFloat32Uint64V(v map[float32]uint64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20157,7 +20157,7 @@ func (_ fastpathT) DecMapFloat32UintptrV(v map[float32]uintptr, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20216,7 +20216,7 @@ func (_ fastpathT) DecMapFloat32IntV(v map[float32]int, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20275,7 +20275,7 @@ func (_ fastpathT) DecMapFloat32Int8V(v map[float32]int8, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20334,7 +20334,7 @@ func (_ fastpathT) DecMapFloat32Int16V(v map[float32]int16, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20393,7 +20393,7 @@ func (_ fastpathT) DecMapFloat32Int32V(v map[float32]int32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20452,7 +20452,7 @@ func (_ fastpathT) DecMapFloat32Int64V(v map[float32]int64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20511,7 +20511,7 @@ func (_ fastpathT) DecMapFloat32Float32V(v map[float32]float32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20524,7 +20524,7 @@ func (_ fastpathT) DecMapFloat32Float32V(v map[float32]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -20570,7 +20570,7 @@ func (_ fastpathT) DecMapFloat32Float64V(v map[float32]float64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20583,7 +20583,7 @@ func (_ fastpathT) DecMapFloat32Float64V(v map[float32]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -20629,7 +20629,7 @@ func (_ fastpathT) DecMapFloat32BoolV(v map[float32]bool, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = float32(dd.DecodeFloat(true))
+		mk = float32(chkFloat32(dd.DecodeFloat64()))
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20689,7 +20689,7 @@ func (_ fastpathT) DecMapFloat64IntfV(v map[float64]interface{}, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20753,7 +20753,7 @@ func (_ fastpathT) DecMapFloat64StringV(v map[float64]string, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20812,7 +20812,7 @@ func (_ fastpathT) DecMapFloat64UintV(v map[float64]uint, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20871,7 +20871,7 @@ func (_ fastpathT) DecMapFloat64Uint8V(v map[float64]uint8, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20930,7 +20930,7 @@ func (_ fastpathT) DecMapFloat64Uint16V(v map[float64]uint16, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -20989,7 +20989,7 @@ func (_ fastpathT) DecMapFloat64Uint32V(v map[float64]uint32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21048,7 +21048,7 @@ func (_ fastpathT) DecMapFloat64Uint64V(v map[float64]uint64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21107,7 +21107,7 @@ func (_ fastpathT) DecMapFloat64UintptrV(v map[float64]uintptr, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21166,7 +21166,7 @@ func (_ fastpathT) DecMapFloat64IntV(v map[float64]int, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21225,7 +21225,7 @@ func (_ fastpathT) DecMapFloat64Int8V(v map[float64]int8, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21284,7 +21284,7 @@ func (_ fastpathT) DecMapFloat64Int16V(v map[float64]int16, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21343,7 +21343,7 @@ func (_ fastpathT) DecMapFloat64Int32V(v map[float64]int32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21402,7 +21402,7 @@ func (_ fastpathT) DecMapFloat64Int64V(v map[float64]int64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21461,7 +21461,7 @@ func (_ fastpathT) DecMapFloat64Float32V(v map[float64]float32, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21474,7 +21474,7 @@ func (_ fastpathT) DecMapFloat64Float32V(v map[float64]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -21520,7 +21520,7 @@ func (_ fastpathT) DecMapFloat64Float64V(v map[float64]float64, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -21533,7 +21533,7 @@ func (_ fastpathT) DecMapFloat64Float64V(v map[float64]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -21579,7 +21579,7 @@ func (_ fastpathT) DecMapFloat64BoolV(v map[float64]bool, canChange bool,
 		if esep {
 		if esep {
 			dd.ReadMapElemKey()
 			dd.ReadMapElemKey()
 		}
 		}
-		mk = dd.DecodeFloat(false)
+		mk = dd.DecodeFloat64()
 		if esep {
 		if esep {
 			dd.ReadMapElemValue()
 			dd.ReadMapElemValue()
 		}
 		}
@@ -22424,7 +22424,7 @@ func (_ fastpathT) DecMapUintFloat32V(v map[uint]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -22483,7 +22483,7 @@ func (_ fastpathT) DecMapUintFloat64V(v map[uint]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -23374,7 +23374,7 @@ func (_ fastpathT) DecMapUint8Float32V(v map[uint8]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -23433,7 +23433,7 @@ func (_ fastpathT) DecMapUint8Float64V(v map[uint8]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -24324,7 +24324,7 @@ func (_ fastpathT) DecMapUint16Float32V(v map[uint16]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -24383,7 +24383,7 @@ func (_ fastpathT) DecMapUint16Float64V(v map[uint16]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -25274,7 +25274,7 @@ func (_ fastpathT) DecMapUint32Float32V(v map[uint32]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -25333,7 +25333,7 @@ func (_ fastpathT) DecMapUint32Float64V(v map[uint32]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -26224,7 +26224,7 @@ func (_ fastpathT) DecMapUint64Float32V(v map[uint64]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -26283,7 +26283,7 @@ func (_ fastpathT) DecMapUint64Float64V(v map[uint64]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -27174,7 +27174,7 @@ func (_ fastpathT) DecMapUintptrFloat32V(v map[uintptr]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -27233,7 +27233,7 @@ func (_ fastpathT) DecMapUintptrFloat64V(v map[uintptr]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -28124,7 +28124,7 @@ func (_ fastpathT) DecMapIntFloat32V(v map[int]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -28183,7 +28183,7 @@ func (_ fastpathT) DecMapIntFloat64V(v map[int]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -29074,7 +29074,7 @@ func (_ fastpathT) DecMapInt8Float32V(v map[int8]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -29133,7 +29133,7 @@ func (_ fastpathT) DecMapInt8Float64V(v map[int8]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -30024,7 +30024,7 @@ func (_ fastpathT) DecMapInt16Float32V(v map[int16]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -30083,7 +30083,7 @@ func (_ fastpathT) DecMapInt16Float64V(v map[int16]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -30974,7 +30974,7 @@ func (_ fastpathT) DecMapInt32Float32V(v map[int32]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -31033,7 +31033,7 @@ func (_ fastpathT) DecMapInt32Float64V(v map[int32]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -31924,7 +31924,7 @@ func (_ fastpathT) DecMapInt64Float32V(v map[int64]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -31983,7 +31983,7 @@ func (_ fastpathT) DecMapInt64Float64V(v map[int64]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -32874,7 +32874,7 @@ func (_ fastpathT) DecMapBoolFloat32V(v map[bool]float32, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = float32(dd.DecodeFloat(true))
+		mv = float32(chkFloat32(dd.DecodeFloat64()))
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}
@@ -32933,7 +32933,7 @@ func (_ fastpathT) DecMapBoolFloat64V(v map[bool]float64, canChange bool,
 			}
 			}
 			continue
 			continue
 		}
 		}
-		mv = dd.DecodeFloat(false)
+		mv = dd.DecodeFloat64()
 		if v != nil {
 		if v != nil {
 			v[mk] = mv
 			v[mk] = mv
 		}
 		}

+ 41 - 4
codec/gen-helper.generated.go

@@ -25,21 +25,53 @@ const GenVersion = 8
 // When static codecs are created for types, they will use this value
 // When static codecs are created for types, they will use this value
 // to perform encoding or decoding of primitives or known slice or map types.
 // to perform encoding or decoding of primitives or known slice or map types.
 
 
+type genHelperEncDriver struct {
+	encDriver
+}
+
+func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
+	encStructFieldKey(x.encDriver, keyType, s, false)
+}
+
+type genHelperDecDriver struct {
+	decDriver
+}
+
+func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[scratchByteArrayLen]byte) []byte {
+	return decStructFieldKey(x.decDriver, keyType, buf)
+}
+func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+	f = x.DecodeFloat64()
+	if chkOverflow32 && chkOvf.Float32(f) {
+		panicv.errorf("float32 overflow: %v", f)
+	}
+	return
+}
+func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
+	f = x.DecodeFloat64()
+	if chkOvf.Float32(f) {
+		panicv.errorf("float32 overflow: %v", f)
+	}
+	return
+}
+
 // GenHelperEncoder is exported so that it can be used externally by codecgen.
 // GenHelperEncoder is exported so that it can be used externally by codecgen.
 //
 //
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee encDriver) {
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
 	ge = genHelperEncoder{e: e}
 	ge = genHelperEncoder{e: e}
-	ee = e.e
+	ee = genHelperEncDriver{e.e}
 	return
 	return
 }
 }
 
 
 // GenHelperDecoder is exported so that it can be used externally by codecgen.
 // GenHelperDecoder is exported so that it can be used externally by codecgen.
 //
 //
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd decDriver) {
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
 	gd = genHelperDecoder{d: d}
 	gd = genHelperDecoder{d: d}
-	dd = d.d
+	dd = genHelperDecDriver{d.d}
 	return
 	return
 }
 }
 
 
@@ -165,6 +197,11 @@ func (f genHelperDecoder) DecScratchBuffer() []byte {
 	return f.d.b[:]
 	return f.d.b[:]
 }
 }
 
 
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchArrayBuffer() *[scratchByteArrayLen]byte {
+	return &f.d.b
+}
+
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
 func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
 	// println(">>>>>>>>> DecFallback")
 	// println(">>>>>>>>> DecFallback")

+ 40 - 4
codec/gen-helper.go.tmpl

@@ -25,21 +25,53 @@ const GenVersion = {{ .Version }}
 // When static codecs are created for types, they will use this value
 // When static codecs are created for types, they will use this value
 // to perform encoding or decoding of primitives or known slice or map types.
 // to perform encoding or decoding of primitives or known slice or map types.
 
 
+type genHelperEncDriver struct {
+	encDriver
+}
+
+func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) {
+	encStructFieldKey(x.encDriver, keyType, s, false)
+}
+
+type genHelperDecDriver struct {
+	decDriver
+}
+
+func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {}
+func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[scratchByteArrayLen]byte) []byte {
+	return decStructFieldKey(x.decDriver, keyType, buf)
+}
+func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+	f = x.DecodeFloat64()
+	if chkOverflow32 && chkOvf.Float32(f) {
+		panicv.errorf("float32 overflow: %v", f)
+	}
+	return
+}
+func (x genHelperDecDriver) DecodeFloat32As64() (f float64) {
+	f = x.DecodeFloat64()
+	if chkOvf.Float32(f) {
+		panicv.errorf("float32 overflow: %v", f)
+	}
+	return
+}
+
 // GenHelperEncoder is exported so that it can be used externally by codecgen.
 // GenHelperEncoder is exported so that it can be used externally by codecgen.
 //
 //
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee encDriver) {
+func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) {
 	ge = genHelperEncoder{e:e}
 	ge = genHelperEncoder{e:e}
-	ee = e.e
+	ee = genHelperEncDriver{e.e}
 	return 
 	return 
 }
 }
 
 
 // GenHelperDecoder is exported so that it can be used externally by codecgen.
 // GenHelperDecoder is exported so that it can be used externally by codecgen.
 //
 //
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
 // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.
-func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd decDriver) {
+func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) {
 	gd = genHelperDecoder{d:d}
 	gd = genHelperDecoder{d:d}
-	dd = d.d
+	dd = genHelperDecDriver{d.d}
 	return
 	return
 }
 }
 
 
@@ -149,6 +181,10 @@ func (f genHelperDecoder) DecScratchBuffer() []byte {
 	return f.d.b[:]
 	return f.d.b[:]
 }
 }
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
+func (f genHelperDecoder) DecScratchArrayBuffer() *[scratchByteArrayLen]byte {
+	return &f.d.b
+}
+// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE*
 func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
 func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) {
 	// println(">>>>>>>>> DecFallback")
 	// println(">>>>>>>>> DecFallback")
 	rv := reflect.ValueOf(iv)
 	rv := reflect.ValueOf(iv)

+ 24 - 15
codec/gen.go

@@ -252,9 +252,15 @@ func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
 	x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
 	x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
 	x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
 	x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
 	x.linef("// ----- value types used ----")
 	x.linef("// ----- value types used ----")
-	x.linef("codecSelferValueTypeArray%s = %v", x.xs, int64(valueTypeArray))
-	x.linef("codecSelferValueTypeMap%s = %v", x.xs, int64(valueTypeMap))
-	// These are no longer needed, as there are functions created for them
+	for _, vt := range [...]valueType{
+		valueTypeArray, valueTypeMap, valueTypeString,
+		valueTypeInt, valueTypeUint, valueTypeFloat} {
+		x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt))
+	}
+
+	// x.linef("codecSelferValueTypeArray%s = %v", x.xs, int64(valueTypeArray))
+	// x.linef("codecSelferValueTypeMap%s = %v", x.xs, int64(valueTypeMap))
+	// // These are no longer needed, as there are functions created for them
 	// x.linef("// ----- containerStateValues ----")
 	// x.linef("// ----- containerStateValues ----")
 	// x.linef("codecSelferKcontainerMapKey%s = %v", x.xs, int64(containerMapKey))
 	// x.linef("codecSelferKcontainerMapKey%s = %v", x.xs, int64(containerMapKey))
 	// x.linef("codecSelferKcontainerMapValue%s = %v", x.xs, int64(containerMapValue))
 	// x.linef("codecSelferKcontainerMapValue%s = %v", x.xs, int64(containerMapValue))
@@ -987,7 +993,8 @@ func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
 			x.linef("if %s[%v] {", numfieldsvar, j)
 			x.linef("if %s[%v] {", numfieldsvar, j)
 		}
 		}
 		x.line("r.WriteMapElemKey()") // x.linef("z.EncSendContainerState(codecSelferKcontainerMapKey%s)", x.xs)
 		x.line("r.WriteMapElemKey()") // x.linef("z.EncSendContainerState(codecSelferKcontainerMapKey%s)", x.xs)
-		x.line("r.EncodeString(codecSelferCcUTF8" + x.xs + ", `" + si.encName + "`)")
+		// x.line("r.EncodeString(codecSelferCcUTF8" + x.xs + ", `" + si.encName + "`)")
+		x.linef("r.EncStructFieldKey(codecSelferValueType%s%s, `%s`)", ti.keyType.String(), x.xs, si.encName)
 		x.line("r.WriteMapElemValue()") // x.linef("z.EncSendContainerState(codecSelferKcontainerMapValue%s)", x.xs)
 		x.line("r.WriteMapElemValue()") // x.linef("z.EncSendContainerState(codecSelferKcontainerMapValue%s)", x.xs)
 		if labelUsed {
 		if labelUsed {
 			x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
 			x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
@@ -1238,10 +1245,10 @@ func (x *genRunner) dec(varname string, t reflect.Type) {
 		x.line("*((*uintptr)(" + varname + ")) = uintptr(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
 		x.line("*((*uintptr)(" + varname + ")) = uintptr(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
 
 
 	case reflect.Float32:
 	case reflect.Float32:
-		x.line("*((*float32)(" + varname + ")) = float32(r.DecodeFloat(true))")
+		x.line("*((*float32)(" + varname + ")) = float32(r.DecodeFloat32As64())")
 		//x.line("z.DecFloat32((*float32)(" + varname + "))")
 		//x.line("z.DecFloat32((*float32)(" + varname + "))")
 	case reflect.Float64:
 	case reflect.Float64:
-		x.line("*((*float64)(" + varname + ")) = float64(r.DecodeFloat(false))")
+		x.line("*((*float64)(" + varname + ")) = r.DecodeFloat64()")
 		// x.line("z.DecFloat64((*float64)(" + varname + "))")
 		// x.line("z.DecFloat64((*float64)(" + varname + "))")
 
 
 	case reflect.Bool:
 	case reflect.Bool:
@@ -1331,9 +1338,9 @@ func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAs
 		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
 		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
 
 
 	case reflect.Float32:
 	case reflect.Float32:
-		x.linef("%s = r.DecodeFloat(true)", varname)
+		x.linef("%s = r.DecodeFloat32As64()", varname)
 	case reflect.Float64:
 	case reflect.Float64:
-		x.linef("%s = r.DecodeFloat(false)", varname)
+		x.linef("%s = r.DecodeFloat64()", varname)
 
 
 	case reflect.Bool:
 	case reflect.Bool:
 		x.linef("%s = r.DecodeBool()", varname)
 		x.linef("%s = r.DecodeBool()", varname)
@@ -1496,6 +1503,7 @@ func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintpt
 
 
 func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
 func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
 	tpfx := genTempVarPfx
 	tpfx := genTempVarPfx
+	ti := x.ti.get(rtid, t)
 	i := x.varsfx()
 	i := x.varsfx()
 	kName := tpfx + "s" + i
 	kName := tpfx + "s" + i
 
 
@@ -1503,9 +1511,8 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
 	// x.line("var " + kName + "Slc = " + kName + "Arr[:] // default slice to decode into")
 	// x.line("var " + kName + "Slc = " + kName + "Arr[:] // default slice to decode into")
 	// use the scratch buffer to avoid allocation (most field names are < 32).
 	// use the scratch buffer to avoid allocation (most field names are < 32).
 
 
-	x.line("var " + kName + "Slc = z.DecScratchBuffer() // default slice to decode into")
-
-	x.line("_ = " + kName + "Slc")
+	// x.line("var " + kName + "Slc = z.DecScratchBuffer() // default slice to decode into")
+	// x.line("_ = " + kName + "Slc")
 	switch style {
 	switch style {
 	case genStructMapStyleLenPrefix:
 	case genStructMapStyleLenPrefix:
 		x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
 		x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
@@ -1518,9 +1525,11 @@ func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t ref
 		x.line("} else { if r.CheckBreak() { break }; }")
 		x.line("} else { if r.CheckBreak() { break }; }")
 	}
 	}
 	x.line("r.ReadMapElemKey()") // f("z.DecSendContainerState(codecSelferKcontainerMapKey%s)", x.xs)
 	x.line("r.ReadMapElemKey()") // f("z.DecSendContainerState(codecSelferKcontainerMapKey%s)", x.xs)
-	x.line(kName + "Slc = r.DecodeStringAsBytes()")
+	// x.line(kName + "Slc = r.DecodeStringAsBytes()")
 	// let string be scoped to this loop alone, so it doesn't escape.
 	// let string be scoped to this loop alone, so it doesn't escape.
-	x.line(kName + " := string(" + kName + "Slc)")
+	// x.line(kName + " := string(" + kName + "Slc)")
+	x.linef("%s := z.StringView(r.DecStructFieldKey(codecSelferValueType%s%s, z.DecScratchArrayBuffer()))",
+		kName, ti.keyType.String(), x.xs)
 	x.line("r.ReadMapElemValue()") // f("z.DecSendContainerState(codecSelferKcontainerMapValue%s)", x.xs)
 	x.line("r.ReadMapElemValue()") // f("z.DecSendContainerState(codecSelferKcontainerMapValue%s)", x.xs)
 	x.decStructMapSwitch(kName, varname, rtid, t)
 	x.decStructMapSwitch(kName, varname, rtid, t)
 
 
@@ -1891,9 +1900,9 @@ func genInternalDecCommandAsString(s string) string {
 	case "string":
 	case "string":
 		return "dd.DecodeString()"
 		return "dd.DecodeString()"
 	case "float32":
 	case "float32":
-		return "float32(dd.DecodeFloat(true))"
+		return "float32(chkFloat32(dd.DecodeFloat64()))"
 	case "float64":
 	case "float64":
-		return "dd.DecodeFloat(false)"
+		return "dd.DecodeFloat64()"
 	case "bool":
 	case "bool":
 		return "dd.DecodeBool()"
 		return "dd.DecodeBool()"
 	default:
 	default:

+ 151 - 18
codec/helper.go

@@ -102,6 +102,7 @@ import (
 	"encoding/binary"
 	"encoding/binary"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"io"
 	"math"
 	"math"
 	"os"
 	"os"
 	"reflect"
 	"reflect"
@@ -138,8 +139,8 @@ var (
 )
 )
 
 
 var refBitset bitset32
 var refBitset bitset32
-
 var pool pooler
 var pool pooler
+var panicv panicHdl
 
 
 func init() {
 func init() {
 	pool.init()
 	pool.init()
@@ -442,6 +443,7 @@ func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo)
 // and not modified while in use. Such a pre-configured Handle
 // and not modified while in use. Such a pre-configured Handle
 // is safe for concurrent access.
 // is safe for concurrent access.
 type Handle interface {
 type Handle interface {
+	Name() string
 	getBasicHandle() *BasicHandle
 	getBasicHandle() *BasicHandle
 	newEncDriver(w *Encoder) encDriver
 	newEncDriver(w *Encoder) encDriver
 	newDecDriver(r *Decoder) decDriver
 	newDecDriver(r *Decoder) decDriver
@@ -733,7 +735,7 @@ type structFieldInfo struct {
 	is        [maxLevelsEmbedding]uint16 // (recursive/embedded) field index in struct
 	is        [maxLevelsEmbedding]uint16 // (recursive/embedded) field index in struct
 	nis       uint8                      // num levels of embedding. if 1, then it's not embedded.
 	nis       uint8                      // num levels of embedding. if 1, then it's not embedded.
 	omitEmpty bool
 	omitEmpty bool
-	toArray   bool // if field is _struct, is the toArray set?
+	// toArray   bool // if field is _struct, is the toArray set?
 }
 }
 
 
 func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
 func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
@@ -764,6 +766,35 @@ func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Valu
 // 	return v
 // 	return v
 // }
 // }
 
 
+func parseStructInfo(stag string) (toArray, omitEmpty bool, keytype valueType) {
+	keytype = valueTypeString // default
+	if stag == "" {
+		return
+	}
+	for i, s := range strings.Split(stag, ",") {
+		if i == 0 {
+		} else {
+			switch s {
+			case "omitempty":
+				omitEmpty = true
+			case "toarray":
+				toArray = true
+			case "int":
+				keytype = valueTypeInt
+			case "uint":
+				keytype = valueTypeUint
+			case "float":
+				keytype = valueTypeFloat
+				// case "bool":
+				// 	keytype = valueTypeBool
+			case "string":
+				keytype = valueTypeString
+			}
+		}
+	}
+	return
+}
+
 func parseStructFieldInfo(fname string, stag string) (si *structFieldInfo) {
 func parseStructFieldInfo(fname string, stag string) (si *structFieldInfo) {
 	// if fname == "" {
 	// if fname == "" {
 	// 	panic(errNoFieldNameToStructFieldInfo)
 	// 	panic(errNoFieldNameToStructFieldInfo)
@@ -779,10 +810,11 @@ func parseStructFieldInfo(fname string, stag string) (si *structFieldInfo) {
 				si.encName = s
 				si.encName = s
 			}
 			}
 		} else {
 		} else {
-			if s == "omitempty" {
+			switch s {
+			case "omitempty":
 				si.omitEmpty = true
 				si.omitEmpty = true
-			} else if s == "toarray" {
-				si.toArray = true
+				// case "toarray":
+				// 	si.toArray = true
 			}
 			}
 		}
 		}
 	}
 	}
@@ -934,7 +966,8 @@ type typeInfo struct {
 	cs  bool // T is a Selfer
 	cs  bool // T is a Selfer
 	csp bool // *T is a Selfer
 	csp bool // *T is a Selfer
 
 
-	toArray bool // whether this (struct) type should be encoded as an array
+	toArray bool      // whether this (struct) type should be encoded as an array
+	keyType valueType // what type of key: default is string
 }
 }
 
 
 // define length beyond which we do a binary search instead of a linear search.
 // define length beyond which we do a binary search instead of a linear search.
@@ -1063,9 +1096,9 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 	if rk == reflect.Struct {
 	if rk == reflect.Struct {
 		var omitEmpty bool
 		var omitEmpty bool
 		if f, ok := rt.FieldByName(structInfoFieldName); ok {
 		if f, ok := rt.FieldByName(structInfoFieldName); ok {
-			siInfo := parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag))
-			ti.toArray = siInfo.toArray
-			omitEmpty = siInfo.omitEmpty
+			ti.toArray, omitEmpty, ti.keyType = parseStructInfo(x.structTag(f.Tag))
+		} else {
+			ti.keyType = valueTypeString
 		}
 		}
 		pp, pi := pool.tiLoad()
 		pp, pi := pool.tiLoad()
 		pv := pi.(*typeInfoLoadArray)
 		pv := pi.(*typeInfoLoadArray)
@@ -1293,24 +1326,44 @@ func xprintf(format string, a ...interface{}) {
 	}
 	}
 }
 }
 
 
-func panicToErr(err *error) {
+func panicToErr(h errstrDecorator, err *error) {
 	if recoverPanicToErr {
 	if recoverPanicToErr {
 		if x := recover(); x != nil {
 		if x := recover(); x != nil {
 			// if false && xDebug {
 			// if false && xDebug {
 			// 	fmt.Printf("panic'ing with: %v\n", x)
 			// 	fmt.Printf("panic'ing with: %v\n", x)
 			// 	debug.PrintStack()
 			// 	debug.PrintStack()
 			// }
 			// }
-			panicValToErr(x, err)
+			panicValToErr(h, x, err)
 		}
 		}
 	}
 	}
 }
 }
 
 
-func panicToErrs2(err1, err2 *error) {
+func panicToErrs2(h errstrDecorator, err1, err2 *error) {
 	if recoverPanicToErr {
 	if recoverPanicToErr {
 		if x := recover(); x != nil {
 		if x := recover(); x != nil {
-			panicValToErr(x, err1)
-			panicValToErr(x, err2)
+			panicValToErr(h, x, err1)
+			panicValToErr(h, x, err2)
+		}
+	}
+}
+
+func panicValToErr(h errstrDecorator, v interface{}, err *error) {
+	switch xerr := v.(type) {
+	case nil:
+	case error:
+		switch xerr {
+		case nil:
+		case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized: // treat as special (bubble up)
+			*err = xerr
+		default:
+			h.wrapErrstr(xerr.Error(), err)
 		}
 		}
+	case string:
+		if xerr != "" {
+			h.wrapErrstr(xerr, err)
+		}
+	default:
+		h.wrapErrstr(v, err)
 	}
 	}
 }
 }
 
 
@@ -1620,9 +1673,29 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
 
 
 // ----
 // ----
 
 
-// these functions must be inlinable, and not call anybody
+func chkFloat32(f float64) (f32 float32) {
+	// f32 = float32(f)
+	if chkOvf.Float32(f) {
+		panicv.errorf("float32 overflow: %v", f)
+	}
+	return float32(f)
+}
+
+// these "checkOverflow" functions must be inlinable, and not call anybody.
+// Overflow means that the value cannot be represented without wrapping/overflow.
+// Overflow=false does not mean that the value can be represented without losing precision
+// (especially for floating point).
+
 type checkOverflow struct{}
 type checkOverflow struct{}
 
 
+// func (checkOverflow) Float16(f float64) (overflow bool) {
+// 	panicv.errorf("unimplemented")
+// 	if f < 0 {
+// 		f = -f
+// 	}
+// 	return math.MaxFloat32 < f && f <= math.MaxFloat64
+// }
+
 func (checkOverflow) Float32(f float64) (overflow bool) {
 func (checkOverflow) Float32(f float64) (overflow bool) {
 	if f < 0 {
 	if f < 0 {
 		f = -f
 		f = -f
@@ -1657,15 +1730,16 @@ func (checkOverflow) SignedInt(v uint64) (i int64, overflow bool) {
 	if pos {
 	if pos {
 		if ui2 > math.MaxInt64 {
 		if ui2 > math.MaxInt64 {
 			overflow = true
 			overflow = true
-			return
+		} else {
+			i = int64(v)
 		}
 		}
 	} else {
 	} else {
 		if ui2 > math.MaxInt64-1 {
 		if ui2 > math.MaxInt64-1 {
 			overflow = true
 			overflow = true
-			return
+		} else {
+			i = int64(v)
 		}
 		}
 	}
 	}
-	i = int64(v)
 	return
 	return
 }
 }
 
 
@@ -1964,3 +2038,62 @@ func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) {
 func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
 func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) {
 	return &p.tiload, p.tiload.Get()
 	return &p.tiload, p.tiload.Get()
 }
 }
+
+type panicHdl struct{}
+
+func (panicHdl) errorv(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
+
+func (panicHdl) errorstr(message string) {
+	if message != "" {
+		panic(message)
+	}
+}
+
+func (panicHdl) errorf(format string, params ...interface{}) {
+	if format != "" {
+		if len(params) == 0 {
+			panic(format)
+		} else {
+			panic(fmt.Sprintf(format, params...))
+		}
+	}
+}
+
+type errstrDecorator interface {
+	wrapErrstr(interface{}, *error)
+}
+
+type errstrDecoratorDef struct{}
+
+func (errstrDecoratorDef) wrapErrstr(v interface{}, e *error) { *e = fmt.Errorf("%v", v) }
+
+type must struct{}
+
+func (must) String(s string, err error) string {
+	if err != nil {
+		panicv.errorv(err)
+	}
+	return s
+}
+func (must) Int(s int64, err error) int64 {
+	if err != nil {
+		panicv.errorv(err)
+	}
+	return s
+}
+func (must) Uint(s uint64, err error) uint64 {
+	if err != nil {
+		panicv.errorv(err)
+	}
+	return s
+}
+func (must) Float(s float64, err error) float64 {
+	if err != nil {
+		panicv.errorv(err)
+	}
+	return s
+}

+ 0 - 15
codec/helper_internal.go

@@ -7,25 +7,10 @@ package codec
 // so porting to different environment is easy (just update functions).
 // so porting to different environment is easy (just update functions).
 
 
 import (
 import (
-	"errors"
-	"fmt"
 	"reflect"
 	"reflect"
 	"time"
 	"time"
 )
 )
 
 
-func panicValToErr(panicVal interface{}, err *error) {
-	switch xerr := panicVal.(type) {
-	case nil:
-	case error:
-		*err = xerr
-	case string:
-		*err = errors.New(xerr)
-	default:
-		*err = fmt.Errorf("%v", panicVal)
-	}
-	return
-}
-
 func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
 func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool {
 	switch v.Kind() {
 	switch v.Kind() {
 	case reflect.Invalid:
 	case reflect.Invalid:

+ 6 - 2
codec/helper_not_unsafe.go

@@ -117,11 +117,15 @@ func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) {
 }
 }
 
 
 func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
-	rv.SetFloat(d.d.DecodeFloat(true))
+	fv := d.d.DecodeFloat64()
+	if chkOvf.Float32(fv) {
+		d.errorf("float32 overflow: %v", fv)
+	}
+	rv.SetFloat(fv)
 }
 }
 
 
 func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
-	rv.SetFloat(d.d.DecodeFloat(false))
+	rv.SetFloat(d.d.DecodeFloat64())
 }
 }
 
 
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {

+ 6 - 2
codec/helper_unsafe.go

@@ -174,13 +174,17 @@ func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) {
 }
 }
 
 
 func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) {
+	fv := d.d.DecodeFloat64()
+	if chkOvf.Float32(fv) {
+		d.errorf("float32 overflow: %v", fv)
+	}
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*float32)(urv.ptr) = float32(d.d.DecodeFloat(true))
+	*(*float32)(urv.ptr) = float32(fv)
 }
 }
 
 
 func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) {
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
 	urv := (*unsafeReflectValue)(unsafe.Pointer(&rv))
-	*(*float64)(urv.ptr) = d.d.DecodeFloat(false)
+	*(*float64)(urv.ptr) = d.d.DecodeFloat64()
 }
 }
 
 
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {
 func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) {

+ 49 - 19
codec/json.go

@@ -311,20 +311,17 @@ func (e *jsonEncDriver) EncodeBool(b bool) {
 }
 }
 
 
 func (e *jsonEncDriver) EncodeFloat32(f float32) {
 func (e *jsonEncDriver) EncodeFloat32(f float32) {
-	e.encodeFloat(float64(f), 32)
+	// e.encodeFloat(float64(f), 32)
+	e.EncodeFloat64(float64(f))
 }
 }
 
 
 func (e *jsonEncDriver) EncodeFloat64(f float64) {
 func (e *jsonEncDriver) EncodeFloat64(f float64) {
-	e.encodeFloat(f, 64)
-}
-
-func (e *jsonEncDriver) encodeFloat(f float64, bits int) {
 	var blen int
 	var blen int
 	// instead of using 'g', specify whether to use 'e' or 'f'
 	// instead of using 'g', specify whether to use 'e' or 'f'
 	var abs = math.Abs(f)
 	var abs = math.Abs(f)
 	var fmt byte
 	var fmt byte
 	var prec int = -1
 	var prec int = -1
-	if abs != 0 && (bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21)) {
+	if abs != 0 && (abs < 1e-6 || abs >= 1e21) {
 		fmt = 'e'
 		fmt = 'e'
 	} else {
 	} else {
 		fmt = 'f'
 		fmt = 'f'
@@ -341,15 +338,51 @@ func (e *jsonEncDriver) encodeFloat(f float64, bits int) {
 	}
 	}
 
 
 	if e.h.MapKeyAsString && e.c == containerMapKey {
 	if e.h.MapKeyAsString && e.c == containerMapKey {
-		blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, bits))
+		blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, 64))
 		e.b[0] = '"'
 		e.b[0] = '"'
 		e.b[blen-1] = '"'
 		e.b[blen-1] = '"'
 	} else {
 	} else {
-		blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, bits))
+		blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64))
 	}
 	}
 	e.w.writeb(e.b[:blen])
 	e.w.writeb(e.b[:blen])
 }
 }
 
 
+// func (e *jsonEncDriver) EncodeFloat64(f float64) {
+// 	e.encodeFloat(f, 64)
+// }
+
+// func (e *jsonEncDriver) encodeFloat(f float64, bits int) {
+// 	var blen int
+// 	// instead of using 'g', specify whether to use 'e' or 'f'
+// 	var abs = math.Abs(f)
+// 	var fmt byte
+// 	var prec int = -1
+// 	if abs != 0 && (bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21)) {
+// 		fmt = 'e'
+// 	} else {
+// 		fmt = 'f'
+// 		// set prec to 1 iff mod is 0.
+// 		//     better than using jsonIsFloatBytesB2 to check if a . or E in the float bytes.
+// 		// this ensures that every float has an e or .0 in it.
+// 		if abs <= 1 {
+// 			if abs == 0 || abs == 1 {
+// 				prec = 1
+// 			}
+// 		} else if _, mod := math.Modf(abs); mod == 0 {
+// 			prec = 1
+// 		}
+// 	}
+
+// 	if e.h.MapKeyAsString && e.c == containerMapKey {
+// 		blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, bits))
+// 		e.b[0] = '"'
+// 		e.b[blen-1] = '"'
+// 	} else {
+// 		blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, bits))
+// 	}
+// 	e.w.writeb(e.b[:blen])
+// }
+
 func (e *jsonEncDriver) EncodeInt(v int64) {
 func (e *jsonEncDriver) EncodeInt(v int64) {
 	x := e.h.IntegerAsString
 	x := e.h.IntegerAsString
 	if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.h.MapKeyAsString && e.c == containerMapKey) {
 	if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.h.MapKeyAsString && e.c == containerMapKey) {
@@ -708,7 +741,7 @@ func (d *jsonDecDriver) DecodeTime() (t time.Time) {
 	}
 	}
 	t, err := time.Parse(time.RFC3339, stringView(d.bs))
 	t, err := time.Parse(time.RFC3339, stringView(d.bs))
 	if err != nil {
 	if err != nil {
-		d.d.error(err)
+		d.d.errorv(err)
 	}
 	}
 	return
 	return
 }
 }
@@ -762,22 +795,16 @@ func (d *jsonDecDriver) DecodeInt(bitsize uint8) (i int64) {
 	bs := d.decNumBytes()
 	bs := d.decNumBytes()
 	i, err := strconv.ParseInt(stringView(bs), 10, int(bitsize))
 	i, err := strconv.ParseInt(stringView(bs), 10, int(bitsize))
 	if err != nil {
 	if err != nil {
-		d.d.errorf("json: decode int from %s: %v", bs, err)
-		return
+		d.d.errorv(err)
 	}
 	}
 	return
 	return
 }
 }
 
 
-func (d *jsonDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+func (d *jsonDecDriver) DecodeFloat64() (f float64) {
 	bs := d.decNumBytes()
 	bs := d.decNumBytes()
-	bitsize := 64
-	if chkOverflow32 {
-		bitsize = 32
-	}
-	f, err := strconv.ParseFloat(stringView(bs), bitsize)
+	f, err := strconv.ParseFloat(stringView(bs), 64)
 	if err != nil {
 	if err != nil {
-		d.d.errorf("json: decode float from %s: %v", bs, err)
-		return
+		d.d.errorv(err)
 	}
 	}
 	return
 	return
 }
 }
@@ -1149,6 +1176,9 @@ type JsonHandle struct {
 	MapKeyAsString bool
 	MapKeyAsString bool
 }
 }
 
 
+// Name returns the name of the handle: json
+func (h *JsonHandle) Name() string { return "json" }
+
 func (h *JsonHandle) hasElemSeparators() bool { return true }
 func (h *JsonHandle) hasElemSeparators() bool { return true }
 
 
 // SetInterfaceExt sets an extension
 // SetInterfaceExt sets an extension

File diff suppressed because it is too large
+ 116 - 112
codec/mammoth2_codecgen_generated_test.go


+ 4 - 5
codec/msgpack.go

@@ -559,7 +559,7 @@ func (d *msgpackDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 }
 }
 
 
 // float can either be decoded from msgpack type: float, double or intX
 // float can either be decoded from msgpack type: float, double or intX
-func (d *msgpackDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+func (d *msgpackDecDriver) DecodeFloat64() (f float64) {
 	if !d.bdRead {
 	if !d.bdRead {
 		d.readNextBd()
 		d.readNextBd()
 	}
 	}
@@ -570,10 +570,6 @@ func (d *msgpackDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 	} else {
 	} else {
 		f = float64(d.DecodeInt(0))
 		f = float64(d.DecodeInt(0))
 	}
 	}
-	if chkOverflow32 && chkOvf.Float32(f) {
-		d.d.errorf("msgpack: float32 overflow: %v", f)
-		return
-	}
 	d.bdRead = false
 	d.bdRead = false
 	return
 	return
 }
 }
@@ -890,6 +886,9 @@ type MsgpackHandle struct {
 	noElemSeparators
 	noElemSeparators
 }
 }
 
 
+// Name returns the name of the handle: msgpack
+func (h *MsgpackHandle) Name() string { return "msgpack" }
+
 // SetBytesExt sets an extension
 // SetBytesExt sets an extension
 func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})

+ 1 - 1
codec/rpc.go

@@ -103,7 +103,7 @@ func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2 bool) (err error) {
 }
 }
 
 
 func (c *rpcCodec) swallow(err *error) {
 func (c *rpcCodec) swallow(err *error) {
-	defer panicToErr(err)
+	defer panicToErr(c.dec, err)
 	c.dec.swallow()
 	c.dec.swallow()
 }
 }
 
 

+ 8 - 9
codec/simple.go

@@ -206,7 +206,7 @@ func (e *simpleEncDriver) EncodeTime(t time.Time) {
 	}
 	}
 	v, err := t.MarshalBinary()
 	v, err := t.MarshalBinary()
 	if err != nil {
 	if err != nil {
-		e.e.error(err)
+		e.e.errorv(err)
 		return
 		return
 	}
 	}
 	// time.Time marshalbinary takes about 14 bytes.
 	// time.Time marshalbinary takes about 14 bytes.
@@ -346,7 +346,7 @@ func (d *simpleDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
 	return
 	return
 }
 }
 
 
-func (d *simpleDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
+func (d *simpleDecDriver) DecodeFloat64() (f float64) {
 	if !d.bdRead {
 	if !d.bdRead {
 		d.readNextBd()
 		d.readNextBd()
 	}
 	}
@@ -362,10 +362,6 @@ func (d *simpleDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
 			return
 			return
 		}
 		}
 	}
 	}
-	if chkOverflow32 && chkOvf.Float32(f) {
-		d.d.errorf("msgpack: float32 overflow: %v", f)
-		return
-	}
 	d.bdRead = false
 	d.bdRead = false
 	return
 	return
 }
 }
@@ -501,7 +497,7 @@ func (d *simpleDecDriver) DecodeTime() (t time.Time) {
 	clen := int(d.r.readn1())
 	clen := int(d.r.readn1())
 	b := d.r.readx(clen)
 	b := d.r.readx(clen)
 	if err := (&t).UnmarshalBinary(b); err != nil {
 	if err := (&t).UnmarshalBinary(b); err != nil {
-		d.d.error(err)
+		d.d.errorv(err)
 	}
 	}
 	return
 	return
 }
 }
@@ -576,10 +572,10 @@ func (d *simpleDecDriver) DecodeNaked() {
 		n.i = d.DecodeInt(64)
 		n.i = d.DecodeInt(64)
 	case simpleVdFloat32:
 	case simpleVdFloat32:
 		n.v = valueTypeFloat
 		n.v = valueTypeFloat
-		n.f = d.DecodeFloat(true)
+		n.f = d.DecodeFloat64()
 	case simpleVdFloat64:
 	case simpleVdFloat64:
 		n.v = valueTypeFloat
 		n.v = valueTypeFloat
-		n.f = d.DecodeFloat(false)
+		n.f = d.DecodeFloat64()
 	case simpleVdTime:
 	case simpleVdTime:
 		n.v = valueTypeTime
 		n.v = valueTypeTime
 		n.t = d.DecodeTime()
 		n.t = d.DecodeTime()
@@ -639,6 +635,9 @@ type SimpleHandle struct {
 	EncZeroValuesAsNil bool
 	EncZeroValuesAsNil bool
 }
 }
 
 
+// Name returns the name of the handle: simple
+func (h *SimpleHandle) Name() string { return "simple" }
+
 // SetBytesExt sets an extension
 // SetBytesExt sets an extension
 func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) {
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})
 	return h.SetExt(rt, tag, &setExtWrapper{b: ext})

Some files were not shown because too many files changed in this diff