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}