From ed60d3a3e643b7366238088d9bcc861fffa505e4 Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Fri, 7 Oct 2022 15:42:25 +0200 Subject: [PATCH 1/4] Unify method receivers (pointers) Signed-off-by: Matej Gera --- merrors/merrors.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/merrors/merrors.go b/merrors/merrors.go index bb0c9dc..7567dc7 100644 --- a/merrors/merrors.go +++ b/merrors/merrors.go @@ -38,11 +38,13 @@ func (e *NilOrMultiError) Add(errs ...error) { } // Err returns the error list as an Error (also implements error) or nil if it is empty. -func (e NilOrMultiError) Err() Error { - if len(e.errs) == 0 { +func (e *NilOrMultiError) Err() Error { + if e == nil || len(e.errs) == 0 { return nil } - return multiError(e) + + return multiError(*e) +} } // Error is extended error interface that allows to use returned read-only multi error in more advanced ways. From 893aedae4afa5affeded64798ef6ac0168c7132e Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Fri, 7 Oct 2022 15:43:00 +0200 Subject: [PATCH 2/4] Add NilOrMultiSyncError Signed-off-by: Matej Gera --- merrors/merrors.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/merrors/merrors.go b/merrors/merrors.go index 7567dc7..3255900 100644 --- a/merrors/merrors.go +++ b/merrors/merrors.go @@ -8,6 +8,7 @@ import ( stderrors "errors" "fmt" "io" + "sync" ) // NilOrMultiError type allows combining multiple errors into one. @@ -45,6 +46,35 @@ func (e *NilOrMultiError) Err() Error { return multiError(*e) } + +// NilOrMultiSyncError is a thread-safe implementation of NilOrMultiError. +// It allows combining multiple errors into one. +type NilOrMultiSyncError struct { + mtx sync.Mutex + multiErr NilOrMultiError +} + +// NewSync returns NilOrMultiSyncError with provided errors added if not nil. +func NewSync(errs ...error) *NilOrMultiSyncError { + sm := &NilOrMultiSyncError{} + sm.Add(errs...) + return sm +} + +// Add adds single or many errors to the error list. It has same behavior as NilOrMultiError. +func (e *NilOrMultiSyncError) Add(errs ...error) { + e.mtx.Lock() + defer e.mtx.Unlock() + + e.multiErr.Add(errs...) +} + +// Err returns the error list as an Error (also implements error) or nil if it is empty. +func (e *NilOrMultiSyncError) Err() Error { + e.mtx.Lock() + defer e.mtx.Unlock() + + return e.multiErr.Err() } // Error is extended error interface that allows to use returned read-only multi error in more advanced ways. From 67d4e2cefab4e8fd84cc24c3eab8e5816b2a7ff2 Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Fri, 7 Oct 2022 15:43:13 +0200 Subject: [PATCH 3/4] Add tests Signed-off-by: Matej Gera --- merrors/merrors_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/merrors/merrors_test.go b/merrors/merrors_test.go index 7825d69..07703fb 100644 --- a/merrors/merrors_test.go +++ b/merrors/merrors_test.go @@ -63,6 +63,26 @@ func TestMultiError(t *testing.T) { }()) } +func TestMultiSyncError(t *testing.T) { + err := errors.New("test1") + + // Run tests with race detector to detect data races in NilOrMultiSyncError. + e := merrors.NewSync(err) + for i := 0; i < 10; i++ { + go func() { + e.Add(err) + }() + } + + testutil.NotOk(t, func() error { + return e.Err() + }()) + + testutil.Ok(t, func() error { + return merrors.NewSync(nil, nil, nil).Err() + }()) +} + func TestMultiError_Error(t *testing.T) { err := errors.New("test1") From b71ed0a74aa456a3d7ebcb43db1ef0cb807b5776 Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Fri, 7 Oct 2022 15:43:40 +0200 Subject: [PATCH 4/4] Regen docs Signed-off-by: Matej Gera --- merrors/doc.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/merrors/doc.go b/merrors/doc.go index 0ea02d3..a670493 100644 --- a/merrors/doc.go +++ b/merrors/doc.go @@ -19,12 +19,11 @@ // // Example 3: // -// func CloseAll(closers []io.Closer) error { -// errs := merrors.New() -// for _ , c := range closers { -// errs.Add(c.Close()) -// } -// return errs.Err() -// } -// +// func CloseAll(closers []io.Closer) error { +// errs := merrors.New() +// for _ , c := range closers { +// errs.Add(c.Close()) +// } +// return errs.Err() +// } package merrors