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/go1 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]
