-
Notifications
You must be signed in to change notification settings - Fork 1
/
errors.go
170 lines (140 loc) · 4.06 KB
/
errors.go
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//
// Copyright (C) 2020 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/fogfish/errors
//
// Package errors provides type safe constructs to annotate Golang errors
// with the context and handle opaque errors without boilerplate
// https://tech.fog.fish/2022/07/05/assert-golang-errors-for-behavior.html#opaque-errors
//
// It solves a problem of annotate errors with the context so that
// consequent debugging of opaque error handling becomes an easy job.
// Instead of using `fmt.Errorf` to include the execution context to the error,
// it defines a type safe wrapping of errors.
package faults
import (
"fmt"
"runtime"
)
// Type creates a basic context for the error. The context produces an error like
// `[function line] text defined by context: original error`
//
// const errSome = errors.Type("something is failed")
type Type string
// New wraps error into the context.
// The function expands the context with arguments.
//
// if err := doSomething(); err != nil {
// return nil, errSome.New(err)
// }
func (e Type) New(err error, args ...any) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
msg := string(e)
if len(args) > 0 {
msg = fmt.Sprintf(msg, args...)
}
return fmt.Errorf("[%s %d] "+msg+": %w", name, line, err)
}
// Fast creates a basic context for the error but skips usage of runtime package.
//
// const errSome = errors.Fast("something is failed")
type Fast string
// New wraps error into the context.
// The function expands the context with arguments.
//
// if err := doSomething(); err != nil {
// return nil, errSome.New(err)
// }
func (e Fast) New(err error, args ...any) error {
msg := string(e)
if len(args) > 0 {
msg = fmt.Sprintf(msg, args...)
}
return fmt.Errorf(msg+": %w", err)
}
// Safe1 creates an error context with 1 argument
//
// const errSome = errors.Safe1[string]("something is failed %s")
type Safe1[A any] string
// New wraps error into the context.
// The function expands the context with arguments.
//
// if err := doSomething(); err != nil {
// return nil, errSome.New(err, "foo")
// }
func (safe Safe1[A]) New(err error, a A) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
return fmt.Errorf("[%s %d] "+string(safe)+": %w", name, line, a, err)
}
// Safe2 creates an error context with 2 argument
type Safe2[A, B any] string
// New wraps error into the context.
func (safe Safe2[A, B]) New(err error, a A, b A) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
return fmt.Errorf("[%s %d] "+string(safe)+": %w", name, line, a, b, err)
}
// Safe3 creates an error context with 3 argument
type Safe3[A, B, C any] string
// New wraps error into the context.
func (safe Safe3[A, B, C]) New(err error, a A, b A, c C) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
return fmt.Errorf("[%s %d] "+string(safe)+": %w", name, line, a, b, c, err)
}
// Safe4 creates an error context with 4 argument
type Safe4[A, B, C, D any] string
// New wraps error into the context.
func (safe Safe4[A, B, C, D]) New(err error, a A, b A, c C, d D) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
return fmt.Errorf("[%s %d] "+string(safe)+": %w", name, line, a, b, c, d, err)
}
// Safe5 creates an error context with 5 argument
type Safe5[A, B, C, D, E any] string
// New wraps error into the context.
func (safe Safe5[A, B, C, D, E]) New(err error, a A, b A, c C, d D, e E) error {
var (
name string
line int
)
if pc, _, ln, ok := runtime.Caller(1); ok {
name = runtime.FuncForPC(pc).Name()
line = ln
}
return fmt.Errorf("[%s %d] "+string(safe)+": %w", name, line, a, b, c, d, e, err)
}