github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/utils/pantoerr/panic_utils.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pantoerr 16 17 import "github.com/dolthub/dolt/go/store/d" 18 19 // RecoverPanic is used to convert panics to errors. The attic-labs noms codebase loves to panic. This is not 20 // idiomatic for Go code. RecoverPanic wraps the cause of the panic retrieved from the recover call, and implements 21 // the error interface so it can be treated like a standard error. 22 type RecoveredPanic struct { 23 PanicCause interface{} 24 ErrMsg string 25 } 26 27 // Error returns the error message 28 func (rp *RecoveredPanic) Error() string { 29 return rp.ErrMsg 30 } 31 32 func IsRecoveredPanic(err error) bool { 33 _, ok := err.(*RecoveredPanic) 34 35 return ok 36 } 37 38 func GetRecoveredPanicCause(err error) interface{} { 39 rp, ok := err.(*RecoveredPanic) 40 41 if !ok { 42 panic("Check with IsRecoveredPanic before calling GetRecoveredPanicCause") 43 } 44 45 return rp.PanicCause 46 } 47 48 // Runs the function given, recovering from any panics and returning the given error instance instead. The 49 // function can optionally return an error of its own, which will be returned in the non-panic case. 50 func PanicToErrorInstance(errInstance error, f func() error) error { 51 var err error 52 func() { 53 defer func() { 54 if r := recover(); r != nil { 55 err = errInstance 56 } 57 }() 58 err = f() 59 }() 60 61 return err 62 } 63 64 // Runs the function given, recovering from any panics and returning a RecoveredPanic error with the errMsg given. The 65 // function can optionally return an error of its own, which will be returned in the non-panic case. 66 func PanicToError(errMsg string, f func() error) error { 67 var err error 68 func() { 69 defer func() { 70 if r := recover(); r != nil { 71 if re, ok := r.(d.WrappedError); ok { 72 r = d.Unwrap(re) 73 } 74 75 err = &RecoveredPanic{r, errMsg} 76 } 77 }() 78 err = f() 79 }() 80 81 return err 82 } 83 84 // Same as PanicToError, but for functions that don't return errors except in the case of panic. 85 func PanicToErrorNil(errMsg string, f func()) error { 86 var err error 87 func() { 88 defer func() { 89 if r := recover(); r != nil { 90 if re, ok := r.(d.WrappedError); ok { 91 r = d.Unwrap(re) 92 } 93 94 err = &RecoveredPanic{r, errMsg} 95 } 96 }() 97 f() 98 }() 99 100 return err 101 }