2016-02-17 02:14:05 +08:00
|
|
|
package util
|
2013-11-16 19:34:13 +08:00
|
|
|
|
2017-01-29 08:51:22 +08:00
|
|
|
// Thrown wraps an error that was raised by Throw, so that it can be recognized
|
|
|
|
// by Catch.
|
|
|
|
type Thrown struct {
|
2017-09-29 22:14:55 +08:00
|
|
|
Wrapped error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t Thrown) Error() string {
|
|
|
|
return "thrown: " + t.Wrapped.Error()
|
2013-11-16 19:34:13 +08:00
|
|
|
}
|
|
|
|
|
2015-02-09 19:11:47 +08:00
|
|
|
// Throw panics with err wrapped properly so that it can be catched by Catch.
|
|
|
|
func Throw(err error) {
|
2017-01-29 08:51:22 +08:00
|
|
|
panic(Thrown{err})
|
2013-11-16 19:34:13 +08:00
|
|
|
}
|
|
|
|
|
2015-02-09 19:11:47 +08:00
|
|
|
// Catch tries to catch an error thrown by Throw and stop the panic. If the
|
2017-05-21 09:08:18 +08:00
|
|
|
// panic is not caused by Throw, the panic is not stopped. It should be called
|
|
|
|
// directly from defer.
|
2015-02-09 19:11:47 +08:00
|
|
|
func Catch(perr *error) {
|
2013-11-16 19:34:13 +08:00
|
|
|
r := recover()
|
|
|
|
if r == nil {
|
|
|
|
return
|
|
|
|
}
|
2017-01-29 08:51:22 +08:00
|
|
|
if exc, ok := r.(Thrown); ok {
|
2017-09-29 22:14:55 +08:00
|
|
|
*perr = exc.Wrapped
|
2013-11-16 19:34:13 +08:00
|
|
|
} else {
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}
|
2017-05-21 09:08:18 +08:00
|
|
|
|
|
|
|
// PCall calls a function and catches anything Thrown'n and returns it. It does
|
|
|
|
// not protect against panics not using Throw, nor can it distinguish between
|
|
|
|
// nothing thrown and Throw(nil).
|
|
|
|
func PCall(f func()) (e error) {
|
|
|
|
defer Catch(&e)
|
|
|
|
f()
|
|
|
|
// If we reach here, f didn't throw anything.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Throws returns whether calling f throws out a certain error (using Throw). It
|
|
|
|
// is useful for testing.
|
|
|
|
func Throws(f func(), e error) bool {
|
|
|
|
return PCall(f) == e
|
|
|
|
}
|
|
|
|
|
2017-12-19 09:37:52 +08:00
|
|
|
// ThrowsAny returns whether calling f throws out anything that is not nil. It
|
|
|
|
// is useful for testing.
|
2017-09-29 22:03:54 +08:00
|
|
|
func ThrowsAny(f func()) bool {
|
2017-09-29 22:02:44 +08:00
|
|
|
return PCall(f) != nil
|
|
|
|
}
|
|
|
|
|
2017-05-21 09:08:18 +08:00
|
|
|
// DoesntThrow returns whether calling f does not throw anything. It is useful
|
|
|
|
// for testing.
|
|
|
|
func DoesntThrow(f func()) bool {
|
|
|
|
return PCall(f) == nil
|
|
|
|
}
|