github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/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  }