Browse Source

codec: En|Decode should have at most 1 defer call

Ugorji Nwoke 7 years ago
parent
commit
6f05ff1f01
3 changed files with 34 additions and 21 deletions
  1. 16 8
      codec/decode.go
  2. 16 4
      codec/encode.go
  3. 2 9
      codec/helper.go

+ 16 - 8
codec/decode.go

@@ -2008,9 +2008,7 @@ func (d *Decoder) naked() *decNaked {
 // 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.
 func (d *Decoder) Decode(v interface{}) (err error) {
-	// need to call defer directly, else it seems the recover is not fully handled
-	defer panicToErrs2(d, &d.err, &err)
-	defer d.alwaysAtEnd()
+	defer d.deferred(&err)
 	d.MustDecode(v)
 	return
 }
@@ -2031,11 +2029,15 @@ func (d *Decoder) MustDecode(v interface{}) {
 	// xprintf(">>>>>>>> >>>>>>>> num decFns: %v\n", d.cf.sn)
 }
 
-// // this is not a smart swallow, as it allocates objects and does unnecessary work.
-// func (d *Decoder) swallowViaHammer() {
-// 	var blank interface{}
-// 	d.decodeValueNoFn(reflect.ValueOf(&blank).Elem())
-// }
+func (d *Decoder) deferred(err1 *error) {
+	d.alwaysAtEnd()
+	if recoverPanicToErr {
+		if x := recover(); x != nil {
+			panicValToErr(d, x, err1)
+			panicValToErr(d, x, &d.err)
+		}
+	}
+}
 
 func (d *Decoder) alwaysAtEnd() {
 	if d.n != nil {
@@ -2046,6 +2048,12 @@ func (d *Decoder) alwaysAtEnd() {
 	d.codecFnPooler.alwaysAtEnd()
 }
 
+// // this is not a smart swallow, as it allocates objects and does unnecessary work.
+// func (d *Decoder) swallowViaHammer() {
+// 	var blank interface{}
+// 	d.decodeValueNoFn(reflect.ValueOf(&blank).Elem())
+// }
+
 func (d *Decoder) swallow() {
 	// smarter decode that just swallows the content
 	dd := d.d

+ 16 - 4
codec/encode.go

@@ -1063,9 +1063,12 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 // Encode writes an object into a stream.
 //
 // Encoding can be configured via the struct tag for the fields.
-// The "codec" key in struct field's tag value is the key name,
+// The key (in the struct tags) that we look at is configurable.
+//
+// By default, we look up the "codec" key in the struct field's tags,
+// and fall bak to the "json" key if "codec" is absent.
+// That key in struct field's tag value is the key name,
 // followed by an optional comma and options.
-// 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
 // can create a field called _struct, and set flags on it. The options
@@ -1141,8 +1144,7 @@ func (e *Encoder) ResetBytes(out *[]byte) {
 // Some formats support symbols (e.g. binc) and will properly encode the string
 // only once in the stream, and use a tag to refer to it thereafter.
 func (e *Encoder) Encode(v interface{}) (err error) {
-	defer panicToErrs2(e, &e.err, &err)
-	defer e.alwaysAtEnd()
+	defer e.deferred(&err)
 	e.MustEncode(v)
 	return
 }
@@ -1159,6 +1161,16 @@ func (e *Encoder) MustEncode(v interface{}) {
 	e.alwaysAtEnd()
 }
 
+func (e *Encoder) deferred(err1 *error) {
+	e.alwaysAtEnd()
+	if recoverPanicToErr {
+		if x := recover(); x != nil {
+			panicValToErr(e, x, err1)
+			panicValToErr(e, x, &e.err)
+		}
+	}
+}
+
 // func (e *Encoder) alwaysAtEnd() {
 // 	e.codecFnPooler.alwaysAtEnd()
 // }

+ 2 - 9
codec/helper.go

@@ -1547,6 +1547,8 @@ func isEmptyStruct(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool)
 // }
 
 func panicToErr(h errstrDecorator, err *error) {
+	// Note: This method MUST be called directly from defer i.e. defer panicToErr ...
+	// else it seems the recover is not fully handled
 	if recoverPanicToErr {
 		if x := recover(); x != nil {
 			// fmt.Printf("panic'ing with: %v\n", x)
@@ -1556,15 +1558,6 @@ func panicToErr(h errstrDecorator, err *error) {
 	}
 }
 
-func panicToErrs2(h errstrDecorator, err1, err2 *error) {
-	if recoverPanicToErr {
-		if x := recover(); x != nil {
-			panicValToErr(h, x, err1)
-			panicValToErr(h, x, err2)
-		}
-	}
-}
-
 func panicValToErr(h errstrDecorator, v interface{}, err *error) {
 	switch xerr := v.(type) {
 	case nil: