package errs import ( "log/slog" "strconv" "strings" "sync" ) type Multi []error func (mu Multi) LogValue() slog.Value { vals := make([]slog.Attr, len(mu)) for i, e := range mu { vals[i] = slog.Any(strconv.Itoa(i+1), e) } return slog.GroupValue(vals...) } func (mu Multi) Error() string { s := strings.Builder{} for i, err := range mu.Clean() { if i > 0 { s.WriteString("; ") } s.WriteString(strconv.Itoa(i + 1)) s.WriteString(". ") s.WriteString(err.Error()) } return s.String() } func (mu Multi) Clean() Multi { out := make(Multi, 0, len(mu)) for _, err := range mu { if err != nil { out = append(out, err) } } return out } func (mu Multi) Resolve() error { out := mu.Clean() if len(out) == 0 { return nil } return out } // Close closes multiple close functions in go routines // and returns all that errors in the order they are defined. // // All errors that are nil will be discarded from the list. // // If no errors met, Close returns nil. func Close(funcs ...func() error) error { if len(funcs) == 0 { return nil } errs := make(Multi, len(funcs)) wg := sync.WaitGroup{} wg.Add(len(funcs)) for i, fn := range funcs { go func(i int, fn func() error) { defer wg.Done() errs[i] = fn() }(i, fn) } wg.Wait() return errs.Resolve() } // Join joins the error into one error. // // Join discards errors that are nil. // // If all errs are nil, Join returns nil. func Join(errs ...error) error { if len(errs) == 0 { return nil } return Multi(errs).Resolve() }