Skip to content

Commit da1a0dd

Browse files
authored
Merge pull request #26 from sashamelentyev/feat/join
2 parents 9620480 + 58d813f commit da1a0dd

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/go-faster/errors
22

3-
go 1.18
3+
go 1.20

join.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//go:build !go1.20
2+
// +build !go1.20
3+
4+
package errors
5+
6+
import "unsafe"
7+
8+
// Join returns an error that wraps the given errors.
9+
// Any nil error values are discarded.
10+
// Join returns nil if every value in errs is nil.
11+
// The error formats as the concatenation of the strings obtained
12+
// by calling the Error method of each element of errs, with a newline
13+
// between each string.
14+
//
15+
// A non-nil error returned by Join implements the Unwrap() []error method.
16+
func Join(errs ...error) error {
17+
n := 0
18+
for _, err := range errs {
19+
if err != nil {
20+
n++
21+
}
22+
}
23+
if n == 0 {
24+
return nil
25+
}
26+
e := &joinError{
27+
errs: make([]error, 0, n),
28+
}
29+
for _, err := range errs {
30+
if err != nil {
31+
e.errs = append(e.errs, err)
32+
}
33+
}
34+
return e
35+
}
36+
37+
type joinError struct {
38+
errs []error
39+
}
40+
41+
func (e *joinError) Error() string {
42+
// Since Join returns nil if every value in errs is nil,
43+
// e.errs cannot be empty.
44+
if len(e.errs) == 1 {
45+
return e.errs[0].Error()
46+
}
47+
48+
b := []byte(e.errs[0].Error())
49+
for _, err := range e.errs[1:] {
50+
b = append(b, '\n')
51+
b = append(b, err.Error()...)
52+
}
53+
// At this point, b has at least one byte '\n'.
54+
return unsafe.String(&b[0], len(b))
55+
}
56+
57+
func (e *joinError) Unwrap() []error {
58+
return e.errs
59+
}

join_go120.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build go1.20
2+
// +build go1.20
3+
4+
package errors
5+
6+
import "errors"
7+
8+
var Join = errors.Join

join_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package errors_test
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/go-faster/errors"
8+
)
9+
10+
func TestJoin(t *testing.T) {
11+
err1 := errors.New("err1")
12+
err2 := errors.New("err2")
13+
for _, test := range []struct {
14+
errs []error
15+
want []error
16+
}{{
17+
errs: []error{err1},
18+
want: []error{err1},
19+
}, {
20+
errs: []error{err1, err2},
21+
want: []error{err1, err2},
22+
}, {
23+
errs: []error{err1, nil, err2},
24+
want: []error{err1, err2},
25+
}} {
26+
got := errors.Join(test.errs...).(interface{ Unwrap() []error }).Unwrap()
27+
if !reflect.DeepEqual(got, test.want) {
28+
t.Errorf("Join(%v) = %v; want %v", test.errs, got, test.want)
29+
}
30+
if len(got) != cap(got) {
31+
t.Errorf("Join(%v) returns errors with len=%v, cap=%v; want len==cap", test.errs, len(got), cap(got))
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)