github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/core/elvish/util/throw.go (about) 1 package util 2 3 // Thrown wraps an error that was raised by Throw, so that it can be recognized 4 // by Catch. 5 type Thrown struct { 6 Wrapped error 7 } 8 9 func (t Thrown) Error() string { 10 return "thrown: " + t.Wrapped.Error() 11 } 12 13 // Throw panics with err wrapped properly so that it can be catched by Catch. 14 func Throw(err error) { 15 panic(Thrown{err}) 16 } 17 18 // Catch tries to catch an error thrown by Throw and stop the panic. If the 19 // panic is not caused by Throw, the panic is not stopped. It should be called 20 // directly from defer. 21 func Catch(perr *error) { 22 r := recover() 23 if r == nil { 24 return 25 } 26 if exc, ok := r.(Thrown); ok { 27 *perr = exc.Wrapped 28 } else { 29 panic(r) 30 } 31 } 32 33 // PCall calls a function and catches anything Thrown'n and returns it. It does 34 // not protect against panics not using Throw, nor can it distinguish between 35 // nothing thrown and Throw(nil). 36 func PCall(f func()) (e error) { 37 defer Catch(&e) 38 f() 39 // If we reach here, f didn't throw anything. 40 return nil 41 } 42 43 // Throws returns whether calling f throws out a certain error (using Throw). It 44 // is useful for testing. 45 func Throws(f func(), e error) bool { 46 return PCall(f) == e 47 } 48 49 // ThrowsAny returns whether calling f throws out anything that is not nil. It 50 // is useful for testing. 51 func ThrowsAny(f func()) bool { 52 return PCall(f) != nil 53 } 54 55 // DoesntThrow returns whether calling f does not throw anything. It is useful 56 // for testing. 57 func DoesntThrow(f func()) bool { 58 return PCall(f) == nil 59 }