NO-JIRA: Clean up marshal/unmarshal error handling

Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/eafd0810
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/eafd0810
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/eafd0810

Branch: refs/heads/master
Commit: eafd08104e232c911686b05f419a3c970706a554
Parents: 0f156d7
Author: Alan Conway <[email protected]>
Authored: Tue Jan 17 16:16:23 2017 -0500
Committer: Alan Conway <[email protected]>
Committed: Tue Jan 17 19:43:58 2017 -0500

----------------------------------------------------------------------
 .../go/src/qpid.apache.org/amqp/marshal.go      | 41 ++++++++++++-----
 .../go/src/qpid.apache.org/amqp/unmarshal.go    | 46 ++++++++++++--------
 2 files changed, 59 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eafd0810/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go 
b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index e3d4e10..b6adf90 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -29,12 +29,25 @@ import (
        "unsafe"
 )
 
-func dataError(prefix string, data *C.pn_data_t) error {
-       err := PnError(C.pn_data_error(data))
-       if err != nil {
-               err = fmt.Errorf("%s: %s", prefix, err.Error())
+// Error returned if Go data cannot be marshaled as an AMQP type.
+type MarshalError struct {
+       // The Go type.
+       GoType reflect.Type
+       s      string
+}
+
+func (e MarshalError) Error() string { return e.s }
+
+func newMarshalError(v interface{}, s string) *MarshalError {
+       t := reflect.TypeOf(v)
+       return &MarshalError{GoType: t, s: fmt.Sprintf("cannot marshal %s: %s", 
t, s)}
+}
+
+func dataMarshalError(v interface{}, data *C.pn_data_t) error {
+       if pe := PnError(C.pn_data_error(data)); pe != nil {
+               return newMarshalError(v, pe.Error())
        }
-       return err
+       return nil
 }
 
 /*
@@ -87,7 +100,16 @@ Described types.
 
 */
 func Marshal(v interface{}, buffer []byte) (outbuf []byte, err error) {
-       defer doRecover(&err)
+       defer func() {
+               if r := recover(); r != nil {
+                       if merr, ok := r.(*MarshalError); ok {
+                               err = merr
+                       } else {
+                               panic(r)
+                       }
+               }
+       }()
+
        data := C.pn_data(0)
        defer C.pn_data_free(data)
        marshal(v, data)
@@ -97,7 +119,7 @@ func Marshal(v interface{}, buffer []byte) (outbuf []byte, 
err error) {
                case n == int(C.PN_OVERFLOW):
                        return buf, overflow
                case n < 0:
-                       return buf, dataError("marshal error", data)
+                       return buf, dataMarshalError(v, data)
                default:
                        return buf[:n], nil
                }
@@ -189,11 +211,10 @@ func marshal(v interface{}, data *C.pn_data_t) {
                case reflect.Slice:
                        putList(data, v)
                default:
-                       panic(fmt.Errorf("cannot marshal %s to AMQP", 
reflect.TypeOf(v)))
+                       panic(newMarshalError(v, "no conversion"))
                }
        }
-       err := dataError("marshal", data)
-       if err != nil {
+       if err := dataMarshalError(v, data); err != nil {
                panic(err)
        }
        return

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eafd0810/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go 
b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index 9b9cfd3..d56cbd2 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -38,28 +38,39 @@ type UnmarshalError struct {
        AMQPType string
        // The Go type.
        GoType reflect.Type
-}
 
-func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
-       return &UnmarshalError{C.pn_type_t(pnType).String(), reflect.TypeOf(v)}
+       s string
 }
 
-func (e UnmarshalError) Error() string {
+func (e UnmarshalError) Error() string { return e.s }
+
+func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
+       e := &UnmarshalError{AMQPType: C.pn_type_t(pnType).String(), GoType: 
reflect.TypeOf(v)}
        if e.GoType.Kind() != reflect.Ptr {
-               return fmt.Sprintf("cannot unmarshal to type %s, not a 
pointer", e.GoType)
+               e.s = fmt.Sprintf("cannot unmarshal to type %s, not a pointer", 
e.GoType)
        } else {
-               return fmt.Sprintf("cannot unmarshal AMQP %s to %s", 
e.AMQPType, e.GoType)
+               e.s = fmt.Sprintf("cannot unmarshal AMQP %s to %s", e.AMQPType, 
e.GoType)
        }
+       return e
 }
 
-func doRecover(err *error) {
-       r := recover()
-       switch r := r.(type) {
-       case nil:
-       case *UnmarshalError:
-               *err = r
-       default:
-               panic(r)
+func newUnmarshalErrorData(data *C.pn_data_t, v interface{}) *UnmarshalError {
+       err := PnError(C.pn_data_error(data))
+       if err == nil {
+               return nil
+       }
+       e := newUnmarshalError(C.pn_data_type(data), v)
+       e.s = e.s + ": " + err.Error()
+       return e
+}
+
+func recoverUnmarshal(err *error) {
+       if r := recover(); r != nil {
+               if uerr, ok := r.(*UnmarshalError); ok {
+                       *err = uerr
+               } else {
+                       panic(r)
+               }
        }
 }
 
@@ -99,7 +110,7 @@ func (d *Decoder) Buffered() io.Reader {
 // See the documentation for Unmarshal for details about the conversion of 
AMQP into a Go value.
 //
 func (d *Decoder) Decode(v interface{}) (err error) {
-       defer doRecover(&err)
+       defer recoverUnmarshal(&err)
        data := C.pn_data(0)
        defer C.pn_data_free(data)
        var n int
@@ -181,7 +192,7 @@ AMQP maps with mixed/unhashable key types need an alternate 
representation.
 Described types.
 */
 func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
-       defer doRecover(&err)
+       defer recoverUnmarshal(&err)
 
        data := C.pn_data(0)
        defer C.pn_data_free(data)
@@ -433,8 +444,7 @@ func unmarshal(v interface{}, data *C.pn_data_t) {
                        panic(newUnmarshalError(pnType, v))
                }
        }
-       err := dataError("unmarshaling", data)
-       if err != nil {
+       if err := newUnmarshalErrorData(data, v); err != nil {
                panic(err)
        }
        return


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to