Skip to content

Commit 4a30688

Browse files
committed
HandlerFn renames & support for multiple handler functions
1 parent 7920fdf commit 4a30688

File tree

2 files changed

+117
-68
lines changed

2 files changed

+117
-68
lines changed

internal/handler/handler.go

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import (
1818

1919
type (
2020
// we want these to be type aliases, so they are much nicer to use
21-
PanicHandler = func(p any)
22-
ErrorHandler = func(err error) error // this is only proper type that work
23-
NilHandler = func(err error) error // these two are the same
21+
PanicFn = func(p any)
22+
ErrorFn = func(err error) error // this is only proper type that work
23+
NilFn = func(err error) error // these two are the same
2424

2525
//CheckHandler = func(noerr bool, err error) error
2626
CheckHandler = func(noerr bool)
@@ -41,13 +41,13 @@ type Info struct {
4141
// These are called if handler.Process caller sets it. If they aren't set
4242
// default implementations are used. NOTE. We have to use both which means
4343
// that we get nilHandler call if recovery() is called by any other
44-
// handler then we call still ErrorHandler and get the error from Any. It
44+
// handler then we call still ErrorFn and get the error from Any. It
4545
// goes for other way around: we get error but nilHandler is only one to
4646
// set, we use that for the error (which is accessed from the closure).
47-
ErrorHandler // If nil default implementation is used.
48-
NilHandler // If nil default (pre-defined here) implementation is used.
47+
ErrorFn // If nil default implementation is used.
48+
NilFn // If nil default (pre-defined here) implementation is used.
4949

50-
PanicHandler // If nil panic() is called.
50+
PanicFn // If nil panic() is called.
5151

5252
CheckHandler // this would be for cases where there isn't any error, but
5353
// this should be the last defer.
@@ -77,8 +77,8 @@ func (i *Info) callNilHandler() {
7777
if i.safeErr() != nil {
7878
i.checkErrorTracer()
7979
}
80-
if i.NilHandler != nil {
81-
*i.Err = i.NilHandler(i.werr)
80+
if i.NilFn != nil {
81+
*i.Err = i.NilFn(i.werr)
8282
i.werr = *i.Err // remember change both our errors!
8383
} else {
8484
i.defaultNilHandler()
@@ -100,8 +100,8 @@ func (i *Info) checkErrorTracer() {
100100

101101
func (i *Info) callErrorHandler() {
102102
i.checkErrorTracer()
103-
if i.ErrorHandler != nil {
104-
*i.Err = i.ErrorHandler(i.Any.(error))
103+
if i.ErrorFn != nil {
104+
*i.Err = i.ErrorFn(i.Any.(error))
105105
i.werr = *i.Err // remember change both our errors!
106106
} else {
107107
i.defaultErrorHandler()
@@ -120,8 +120,8 @@ func (i *Info) checkPanicTracer() {
120120

121121
func (i *Info) callPanicHandler() {
122122
i.checkPanicTracer()
123-
if i.PanicHandler != nil {
124-
i.PanicHandler(i.Any)
123+
if i.PanicFn != nil {
124+
i.PanicFn(i.Any)
125125
} else {
126126
panic(i.Any)
127127
}
@@ -153,8 +153,8 @@ func (i *Info) buildFmtErr() {
153153
}
154154

155155
func (i *Info) safeCallErrorHandler() {
156-
if i.ErrorHandler != nil {
157-
*i.Err = i.ErrorHandler(i.werr)
156+
if i.ErrorFn != nil {
157+
*i.Err = i.ErrorFn(i.werr)
158158
}
159159
}
160160

@@ -172,8 +172,8 @@ func (i *Info) defaultNilHandler() {
172172
}
173173

174174
func (i *Info) safeCallNilHandler() {
175-
if i.NilHandler != nil {
176-
*i.Err = i.NilHandler(i.werr)
175+
if i.NilFn != nil {
176+
*i.Err = i.NilFn(i.werr)
177177
}
178178
}
179179

@@ -285,9 +285,9 @@ func PreProcess(errPtr *error, info *Info, a ...any) error {
285285
}
286286
}
287287
}
288-
defCatchCallMode := info.PanicHandler == nil && info.CallerName == "Catch"
288+
defCatchCallMode := info.PanicFn == nil && info.CallerName == "Catch"
289289
if defCatchCallMode {
290-
info.PanicHandler = PanicNoop
290+
info.PanicFn = PanicNoop
291291
}
292292

293293
Process(info)
@@ -317,14 +317,26 @@ func _(a ...any) bool {
317317
}
318318

319319
func subProcess(info *Info, a ...any) {
320+
// not that switch cannot be 0: see call side
320321
switch len(a) {
321-
case 2: // currently we support only this order of 2 handlers in Catch
322+
case 0:
323+
msg := `---
324+
programming error: subProcess: case 0:
325+
---`
326+
fmt.Fprintln(os.Stderr, color.Red()+msg+color.Reset())
327+
case 1:
328+
processArg(info, 0, a...)
329+
default: // case 2, 3, ...
322330
processArg(info, 0, a...)
323-
if _, ok := a[1].(PanicHandler); ok {
331+
if _, ok := a[1].(PanicFn); ok {
324332
processArg(info, 1, a...)
333+
} else if _, ok := a[1].(ErrorFn); ok {
334+
// check second ^ and then change the rest by combining them to
335+
// one that we set to proper places: ErrorFn and NilFn
336+
hfn := Pipeline(AssertErrHandlers(a))
337+
info.ErrorFn = hfn
338+
info.NilFn = hfn
325339
}
326-
default:
327-
processArg(info, 0, a...)
328340
}
329341
}
330342

@@ -333,15 +345,15 @@ func processArg(info *Info, i int, a ...any) {
333345
case string:
334346
info.Format = first
335347
info.Args = a[i+1:]
336-
case ErrorHandler: // err2.Catch uses this
337-
info.ErrorHandler = first
338-
info.NilHandler = first
339-
case PanicHandler: // err2.Catch uses this
340-
info.PanicHandler = first
348+
case ErrorFn: // err2.Catch uses this
349+
info.ErrorFn = first
350+
info.NilFn = first
351+
case PanicFn: // err2.Catch uses this
352+
info.PanicFn = first
341353
case CheckHandler:
342354
info.CheckHandler = first
343355
case nil:
344-
info.NilHandler = NilNoop
356+
info.NilFn = NilNoop
345357
default:
346358
// we don't panic here because we can already be in recovery, but lets
347359
// try to show an RED error message at least.
@@ -386,3 +398,40 @@ func LogOutput(lvl int, s string) (err error) {
386398
fmt.Fprintln(w, s)
387399
return nil
388400
}
401+
402+
// Pipeline is a helper to call several error handlers in a sequence.
403+
//
404+
// defer err2.Handle(&err, err2.Pipeline(err2.Log, MapToHTTPErr))
405+
func Pipeline(f []ErrorFn) ErrorFn {
406+
return func(err error) error {
407+
for _, handler := range f {
408+
err = handler(err)
409+
}
410+
return err
411+
}
412+
}
413+
414+
func bugAssertErrHandlers(handlerFns ...any) (hs []ErrorFn) {
415+
hs = make([]ErrorFn, 0, len(handlerFns))
416+
for _, a := range handlerFns {
417+
if fn, ok := a.(ErrorFn); ok {
418+
hs = append(hs, fn)
419+
} else {
420+
return nil
421+
}
422+
}
423+
return hs
424+
}
425+
426+
func AssertErrHandlers(handlerFns []any) (hs []ErrorFn) {
427+
count := len(handlerFns)
428+
hs = make([]ErrorFn, 0, count)
429+
for _, a := range handlerFns {
430+
if fn, ok := a.(ErrorFn); ok {
431+
hs = append(hs, fn)
432+
} else {
433+
return nil
434+
}
435+
}
436+
return hs
437+
}

internal/handler/handler_test.go

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,21 @@ func TestProcess(t *testing.T) {
3030
}{
3131
{"all nil and our handlers",
3232
args{Info: handler.Info{
33-
Any: nil,
34-
Err: &nilError,
35-
NilHandler: nilHandler,
36-
ErrorHandler: errorHandler,
37-
PanicHandler: panicHandler,
33+
Any: nil,
34+
Err: &nilError,
35+
NilFn: nilHandler,
36+
ErrorFn: errorHandler,
37+
PanicFn: panicHandler,
3838
}},
3939
want{
4040
errStr: "error",
4141
}},
4242
{"error is transported in panic",
4343
args{Info: handler.Info{
44-
Any: errors.New("error"),
45-
Err: &nilError,
46-
ErrorHandler: errorHandler,
47-
PanicHandler: panicHandler,
44+
Any: errors.New("error"),
45+
Err: &nilError,
46+
ErrorFn: errorHandler,
47+
PanicFn: panicHandler,
4848
}},
4949
want{
5050
panicCalled: false,
@@ -53,48 +53,48 @@ func TestProcess(t *testing.T) {
5353
}},
5454
{"runtime.Error is transported in panic",
5555
args{Info: handler.Info{
56-
Any: myErrRT,
57-
Err: &nilError,
58-
NilHandler: nilHandler,
59-
ErrorHandler: errorHandler,
60-
PanicHandler: panicHandler,
56+
Any: myErrRT,
57+
Err: &nilError,
58+
NilFn: nilHandler,
59+
ErrorFn: errorHandler,
60+
PanicFn: panicHandler,
6161
}},
6262
want{
6363
panicCalled: true,
6464
errStr: "error",
6565
}},
6666
{"panic is transported in panic",
6767
args{Info: handler.Info{
68-
Any: "panic",
69-
Err: &nilError,
70-
NilHandler: nilHandler,
71-
ErrorHandler: errorHandler,
72-
PanicHandler: panicHandler,
68+
Any: "panic",
69+
Err: &nilError,
70+
NilFn: nilHandler,
71+
ErrorFn: errorHandler,
72+
PanicFn: panicHandler,
7373
}},
7474
want{
7575
panicCalled: true,
7676
errStr: "error",
7777
}},
7878
{"error in panic and default format print",
7979
args{Info: handler.Info{
80-
Any: errors.New("error"),
81-
Err: &nilError,
82-
Format: "format %v",
83-
Args: []any{"test"},
84-
PanicHandler: panicHandler,
80+
Any: errors.New("error"),
81+
Err: &nilError,
82+
Format: "format %v",
83+
Args: []any{"test"},
84+
PanicFn: panicHandler,
8585
}},
8686
want{
8787
panicCalled: false,
8888
errStr: "error",
8989
}},
9090
{"error transported in panic and our OWN handler",
9191
args{Info: handler.Info{
92-
Any: errors.New("error"),
93-
Err: &nilError,
94-
Format: "format %v",
95-
Args: []any{"test"},
96-
ErrorHandler: errorHandlerForAnnotate,
97-
PanicHandler: panicHandler,
92+
Any: errors.New("error"),
93+
Err: &nilError,
94+
Format: "format %v",
95+
Args: []any{"test"},
96+
ErrorFn: errorHandlerForAnnotate,
97+
PanicFn: panicHandler,
9898
}},
9999
want{
100100
panicCalled: false,
@@ -103,10 +103,10 @@ func TestProcess(t *testing.T) {
103103
}},
104104
{"error is transported in error val",
105105
args{Info: handler.Info{
106-
Any: nil,
107-
Err: &myErrVal,
108-
ErrorHandler: errorHandler,
109-
PanicHandler: panicHandler,
106+
Any: nil,
107+
Err: &myErrVal,
108+
ErrorFn: errorHandler,
109+
PanicFn: panicHandler,
110110
}},
111111
want{
112112
panicCalled: false,
@@ -196,11 +196,11 @@ func TestPreProcess(t *testing.T) {
196196
{"all nil and our handlers",
197197
args{
198198
Info: handler.Info{
199-
Any: nil,
200-
Err: &nilError,
201-
NilHandler: nilHandler,
202-
ErrorHandler: errorHandlerForAnnotate,
203-
PanicHandler: panicHandler,
199+
Any: nil,
200+
Err: &nilError,
201+
NilFn: nilHandler,
202+
ErrorFn: errorHandlerForAnnotate,
203+
PanicFn: panicHandler,
204204
},
205205
a: []any{"test"}}, // no affec because
206206
want{

0 commit comments

Comments
 (0)