errs.gno

2.66 Kb ยท 111 lines
  1// Package errs provides utilities for combining multiple errors.
  2// This is a simplified version of https://github.com/uber-go/multierr (MIT License),
  3// adapted for the Gno programming language with a focus on core functionality
  4// and idiomatic usage patterns.
  5//
  6// Example usage:
  7//
  8//	err1 := doSomething()
  9//	err2 := doSomethingElse()
 10//	if err := errs.Combine(err1, err2); err != nil {
 11//	    return err // Returns combined errors or single error
 12//	}
 13package errs
 14
 15import (
 16	"strings"
 17)
 18
 19// multiError represents multiple errors combined into one.
 20type multiError struct {
 21	errors []error
 22}
 23
 24// Error implements the error interface by returning a single-line representation
 25// of all contained errors, separated by semicolons.
 26func (m *multiError) Error() string {
 27	if m == nil || len(m.errors) == 0 {
 28		return ""
 29	}
 30
 31	var b strings.Builder
 32	first := true
 33	for _, err := range m.errors {
 34		if first {
 35			first = false
 36		} else {
 37			b.WriteString("; ")
 38		}
 39		b.WriteString(err.Error())
 40	}
 41	return b.String()
 42}
 43
 44// String returns a multi-line representation of the error.
 45func (m *multiError) String() string {
 46	if m == nil || len(m.errors) == 0 {
 47		return ""
 48	}
 49
 50	var b strings.Builder
 51	b.WriteString("the following errors occurred:")
 52	for _, err := range m.errors {
 53		b.WriteString("\n -  ")
 54		b.WriteString(err.Error())
 55	}
 56	return b.String()
 57}
 58
 59// Unwrap returns the slice of underlying errors contained in this multiError.
 60// Returns nil if the receiver is nil.
 61func (m *multiError) Unwrap() []error {
 62	if m == nil {
 63		return nil
 64	}
 65	return m.errors
 66}
 67
 68// Errors extracts the underlying errors from an error interface.
 69// If the error is a multiError, it returns its contained errors.
 70// If the error is nil, returns nil.
 71// If the error is a regular error, returns a slice containing just that error.
 72func Errors(err error) []error {
 73	if err == nil {
 74		return nil
 75	}
 76
 77	if merr, ok := err.(*multiError); ok {
 78		return merr.Unwrap()
 79	}
 80
 81	return []error{err}
 82}
 83
 84// Combine merges multiple errors into a single error efficiently.
 85// It handles several cases:
 86//   - If all input errors are nil, returns nil
 87//   - If there's exactly one non-nil error, returns that error directly
 88//   - If there are multiple non-nil errors, returns a multiError containing them
 89//   - Flattens any *multiError in the input
 90func Combine(errs ...error) error {
 91	nonNil := make([]error, 0, len(errs))
 92	for _, err := range errs {
 93		if err == nil {
 94			continue
 95		}
 96		if m, ok := err.(*multiError); ok && m != nil {
 97			nonNil = append(nonNil, m.Unwrap()...)
 98		} else {
 99			nonNil = append(nonNil, err)
100		}
101	}
102
103	switch len(nonNil) {
104	case 0:
105		return nil
106	case 1:
107		return nonNil[0]
108	default:
109		return &multiError{errors: nonNil}
110	}
111}