diff --git a/try/try.go b/try/try.go index 399cd40..f24576b 100644 --- a/try/try.go +++ b/try/try.go @@ -47,7 +47,14 @@ type call struct { } // FromErr wraps a standard error into a try-compatible one with extended stack info. -func FromErr(err error) *tryErr { +func FromErr(err error) Err { + // If the error is already try-compatible, return + //nolint:errorlint + cterr, ok := err.(Err) + if ok { + return cterr + } + terr := &tryErr{err: err, callStack: []call{}} pc, _, _, ok := runtime.Caller(0) @@ -82,7 +89,7 @@ func FromErr(err error) *tryErr { } // NewErr creates a new try-compatible error with extended stack info. -func NewErr(msg string) *tryErr { +func NewErr(msg string) Err { return FromErr(errors.New(msg)) } @@ -179,9 +186,6 @@ func check(args []interface{}) { // return errors there is a Catch function. Note! The handler function f is // called only when err != nil. func Handle(err *Err, f func()) { - // This and Catch are similar but we need to call recover() here because - // how it works with defer. We cannot refactor these to use same function. - // We put real panic objects back and keep only those which are // carrying our errors. We must also call all of the handlers in defer // stack. @@ -208,9 +212,6 @@ func Handle(err *Err, f func()) { // Catch function per non error returning function. See Handle for more // information. func Catch(f func(err Err)) { - // This and Handle are similar but we need to call recover here because how - // it works with defer. We cannot refactor these 2 to use same function. - if r := recover(); r != nil { e, ok := r.(Err) if !ok { @@ -223,9 +224,6 @@ func Catch(f func(err Err)) { // CatchAll is a helper function to catch and write handlers for all errors and // all panics thrown in the current go routine. func CatchAll(errorHandler func(err Err), panicHandler func(v interface{})) { - // This and Handle are similar but we need to call recover here because how - // it works with defer. We cannot refactor these 2 to use same function. - if r := recover(); r != nil { e, ok := r.(Err) if ok { @@ -256,9 +254,6 @@ func CatchTrace(exit int) { // their errors. If you want to annotate errors see Annotate for more // information. func Return(err *Err) { - // This and Handle are similar but we need to call recover here because how - // it works with defer. We cannot refactor these two to use same function. - if r := recover(); r != nil { e, ok := r.(Err) if !ok { @@ -268,13 +263,19 @@ func Return(err *Err) { } } -// Annotate is for annotating an error. It's similar to Returnf but it takes only -// two arguments: a prefix string and a pointer to error. It adds ": " between -// the prefix and the error text automatically. -func Annotate(err *Err, msg string) { - // This and Handle are similar but we need to call recover here because how - // it works with defer. We cannot refactor these two to use same function. +// ReturnStd is like Return, but it returns the Go standard error type. +func ReturnStd(err *error) { + if r := recover(); r != nil { + e, ok := r.(Err) + if !ok { + panic(r) // Not ours, carry on panicking + } + *err = e.Unwrap() + } +} +// Annotate adds additional messages to the error. +func Annotate(err *Err, msg string) { if r := recover(); r != nil { e, ok := r.(Err) if !ok { diff --git a/try/try_test.go b/try/try_test.go index ab7ee0d..fac96ee 100644 --- a/try/try_test.go +++ b/try/try_test.go @@ -206,6 +206,36 @@ func TestErrCompare(t *testing.T) { } } +func TestReturnStd(t *testing.T) { + tf := func() (err error) { + defer ReturnStd(&err) + String(throw()) + return + } + + err := tf() + + if err.Error() != "this is an ERROR" { + t.Fail() + } +} + +func TestCheckTryErr(t *testing.T) { + testErr := NewErr("TestErr") + + tf := func() (err Err) { + defer Return(&err) + Check(testErr) + return + } + + err := tf() + + if err != testErr { + t.Fail() + } +} + func ExampleReturn() { var err Err defer Return(&err)