github.com/haraldrudell/parl@v0.4.176/panic-to-err.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package parl
     7  
     8  import "github.com/haraldrudell/parl/perrors"
     9  
    10  const (
    11  	panicToErrAnnotation = "recover from panic: message:"
    12  )
    13  
    14  // PanicToErr recovers active panic, aggregating errors in errp
    15  //   - PanicToErr does not provide enclosing function. For that,
    16  //     use RecoverErr: “recover from panic in pack.Func…”
    17  //   - errp cannot be nil
    18  //   - if isPanic is non-nil and active panic, it is set to true
    19  //
    20  // sample error message, including message in the panic value and the code line
    21  // causing the panic:
    22  //
    23  //	recover from panic: message: “runtime error: invalid memory address or nil pointer dereference” at parl.panicFunction()-panic-to-err_test.go:96
    24  //
    25  // Usage:
    26  //
    27  //	func someFunc() (isPanic bool, err error) {
    28  //	  defer parl.PanicToErr(&err, &isPanic)
    29  //
    30  //	func someGoroutine(g parl.Go) {
    31  //	  var err error
    32  //	  defer g.Register().Done(&err)
    33  //	  defer parl.PanicToErr(&err)
    34  func PanicToErr(errp *error, isPanic ...*bool) {
    35  	if errp == nil {
    36  		panic(NilError("errp"))
    37  	}
    38  
    39  	// if no panic, noop
    40  	//	- recover invocation must be directly in the PanicToErr function
    41  	var panicValue = recover()
    42  	if panicValue == nil {
    43  		return // no panic active return
    44  	}
    45  
    46  	// set isPanic if non-nil
    47  	if len(isPanic) > 0 {
    48  		if isPanicp := isPanic[0]; isPanicp != nil {
    49  			*isPanicp = true
    50  		}
    51  	}
    52  
    53  	// append panic to *errp
    54  	//	- for panic detector to work there needs to be at least one stack frame after runtime’s
    55  	//		panic handler
    56  	//	- because PanicToErr is invoked directly by the runtime, possibly runtime.gopanic,
    57  	//		the PanicToErr stack frame must be included.
    58  	//		Therefore, 0 argument to processRecover
    59  	*errp = perrors.AppendError(*errp, processRecoverValue(panicToErrAnnotation, panicValue, 0))
    60  }