github.com/ladydascalie/elvish@v0.0.0-20170703214355-2964dd3ece7f/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  	Error error
     7  }
     8  
     9  // Throw panics with err wrapped properly so that it can be catched by Catch.
    10  func Throw(err error) {
    11  	panic(Thrown{err})
    12  }
    13  
    14  // Catch tries to catch an error thrown by Throw and stop the panic. If the
    15  // panic is not caused by Throw, the panic is not stopped. It should be called
    16  // directly from defer.
    17  func Catch(perr *error) {
    18  	r := recover()
    19  	if r == nil {
    20  		return
    21  	}
    22  	if exc, ok := r.(Thrown); ok {
    23  		*perr = exc.Error
    24  	} else {
    25  		panic(r)
    26  	}
    27  }
    28  
    29  // PCall calls a function and catches anything Thrown'n and returns it. It does
    30  // not protect against panics not using Throw, nor can it distinguish between
    31  // nothing thrown and Throw(nil).
    32  func PCall(f func()) (e error) {
    33  	defer Catch(&e)
    34  	f()
    35  	// If we reach here, f didn't throw anything.
    36  	return nil
    37  }
    38  
    39  // Throws returns whether calling f throws out a certain error (using Throw). It
    40  // is useful for testing.
    41  func Throws(f func(), e error) bool {
    42  	return PCall(f) == e
    43  }
    44  
    45  // DoesntThrow returns whether calling f does not throw anything. It is useful
    46  // for testing.
    47  func DoesntThrow(f func()) bool {
    48  	return PCall(f) == nil
    49  }