Skip to content

Commit 521f737

Browse files
author
Dmitriy Matrenichev
committed
feat: add xerrors package which contains additions to the std errors
The additions are: - TypeIs which is basically a wrapper around errors.As - Tagged error type which allows to add type tags to the error chain. - TagIs which is similar to TypeIs but shorter. Signed-off-by: Dmitriy Matrenichev <[email protected]>
1 parent 726e066 commit 521f737

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

xerrors/xerrors.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
// Package xerrors contains the additions to std errors package.
6+
package xerrors
7+
8+
import (
9+
"errors"
10+
"fmt"
11+
)
12+
13+
// TypeIs is wrapper around errors.As which check the error type.
14+
func TypeIs[T error](err error) bool {
15+
var expected T
16+
17+
return errors.As(err, &expected)
18+
}
19+
20+
// TagIs is wrapper around errors.As which checks the error tag.
21+
func TagIs[T Tag](err error) bool {
22+
var expected *Tagged[T]
23+
24+
return errors.As(err, &expected)
25+
}
26+
27+
// Tag is a type which can be used to tag Tagged errors.
28+
type Tag interface {
29+
~struct{}
30+
}
31+
32+
// Tagged is an error with a tag attached. Tag can only be an empty struct.
33+
//
34+
//nolint:errname
35+
type Tagged[T Tag] struct {
36+
err error
37+
}
38+
39+
// NewTagged creates a new typed error.
40+
func NewTagged[T Tag](err error) error {
41+
return &Tagged[T]{err: err}
42+
}
43+
44+
// NewTaggedf creates a new typed error.
45+
func NewTaggedf[T Tag](format string, a ...any) error {
46+
return &Tagged[T]{err: fmt.Errorf(format, a...)}
47+
}
48+
49+
// Error implements error interface.
50+
func (e *Tagged[T]) Error() string {
51+
return e.err.Error()
52+
}
53+
54+
// Unwrap implements errors.Unwrap.
55+
func (e *Tagged[T]) Unwrap() error {
56+
return e.err
57+
}

xerrors/xerrors_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package xerrors_test
6+
7+
import (
8+
"errors"
9+
"io"
10+
"testing"
11+
12+
"github.com/stretchr/testify/require"
13+
14+
"github.com/siderolabs/gen/xerrors"
15+
)
16+
17+
//nolint:unused
18+
type testTag struct{}
19+
20+
func TestTagged(t *testing.T) {
21+
stdErr := io.EOF
22+
taggedErr := xerrors.NewTagged[testTag](stdErr)
23+
24+
require.True(t, xerrors.TypeIs[*xerrors.Tagged[testTag]](taggedErr))
25+
require.True(t, xerrors.TagIs[testTag](taggedErr))
26+
require.False(t, xerrors.TypeIs[*xerrors.Tagged[testTag]](stdErr))
27+
require.False(t, xerrors.TagIs[testTag](stdErr))
28+
require.ErrorIs(t, taggedErr, stdErr)
29+
30+
taggedfErr := xerrors.NewTaggedf[testTag]("my custom error around: %w", stdErr)
31+
32+
require.True(t, xerrors.TypeIs[*xerrors.Tagged[testTag]](taggedfErr))
33+
require.True(t, xerrors.TagIs[testTag](taggedfErr))
34+
require.ErrorIs(t, taggedfErr, stdErr)
35+
require.EqualError(t, taggedErr, stdErr.Error())
36+
37+
taggedCustomErr := xerrors.NewTaggedf[testTag]("my custom error")
38+
39+
require.True(t, xerrors.TypeIs[*xerrors.Tagged[testTag]](taggedCustomErr))
40+
require.True(t, xerrors.TagIs[testTag](taggedCustomErr))
41+
require.False(t, errors.Is(taggedCustomErr, stdErr))
42+
}

0 commit comments

Comments
 (0)