-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexceptions.go
More file actions
93 lines (87 loc) · 2.17 KB
/
exceptions.go
File metadata and controls
93 lines (87 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Package exceptions provides helper functions to leverage Go's `panic`, `recover` and `defer`
// as an "exceptions" system.
//
// The `panic`, `recover` and the added runtime type checking is slow when compared to
// simply returning errors.
// So it should be used where a little latency in case of errors is not an issue.
//
// It defines `Try` and `TryCatch[E any]`.
package exceptions
import (
"github.com/pkg/errors"
"runtime"
)
// convertRuntimePanic converts a runtime panic error to something with a printable stack.
func convertRuntimePanic(e any) any {
if e == nil {
return e
}
runtimeErr, ok := e.(runtime.Error)
if !ok {
// Not a runtime error.
return e
}
return errors.Wrap(runtimeErr, "runtime panic: ")
}
// Try calls `fn` and return any exception (`panic`) that may occur.
//
// Runtime panics are converted to an error with a stack-trace, to facilitate debugging.
//
// Example:
//
// var x ResultType
// e := Try(func() { x = DoSomething() })
// if e != nil {
// if eInt, ok := e.(int); ok {
// errorInt = e
// } else if err, ok := e.(err); ok {
// klog.Errorf("%v", e)
// } else {
// panic(e)
// }
// }
func Try(fn func()) (exception any) {
defer func() {
exception = recover()
exception = convertRuntimePanic(exception)
}()
fn()
return
}
// TryCatch executes `fn` and in case of `panic`, it recovers if of the type `E`.
// For a `panic` of any other type, it simply re-throws the `panic`.
//
// Runtime panics are converted to errors.Error, with a stack trace.
//
// Example:
//
// var x ResultType
// err := TryCatch[error](func() { x = DoSomething() })
// if err != nil {
// // Handle error ...
// }
func TryCatch[E any](fn func()) (exception E) {
defer func() {
e := recover()
if e == nil {
// No exceptions.
return
}
e = convertRuntimePanic(e)
var ok bool
exception, ok = e.(E)
if !ok {
// Re-throw an exception of a different type.
panic(e)
}
// Return the recovered exception.
return
}()
fn()
return
}
// Panicf is a shortcut to `panic(errors.Errorf(format, args...))`.
// It throws an error with a stack-trace and the formatted message.
func Panicf(format string, args ...any) {
panic(errors.Errorf(format, args...))
}