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 functionality4// 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 error12// }13package errs1415import (16 "strings"17)1819// multiError represents multiple errors combined into one.20type multiError struct {21 errors []error22}2324// Error implements the error interface by returning a single-line representation25// of all contained errors, separated by semicolons.26func (m *multiError) Error() string {27 if m == nil || len(m.errors) == 0 {28 return ""29 }3031 var b strings.Builder32 first := true33 for _, err := range m.errors {34 if first {35 first = false36 } else {37 b.WriteString("; ")38 }39 b.WriteString(err.Error())40 }41 return b.String()42}4344// 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 }4950 var b strings.Builder51 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}5859// 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 nil64 }65 return m.errors66}6768// 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 nil75 }7677 if merr, ok := err.(*multiError); ok {78 return merr.Unwrap()79 }8081 return []error{err}82}8384// Combine merges multiple errors into a single error efficiently.85// It handles several cases:86// - If all input errors are nil, returns nil87// - If there's exactly one non-nil error, returns that error directly88// - If there are multiple non-nil errors, returns a multiError containing them89// - Flattens any *multiError in the input90func Combine(errs ...error) error {91 nonNil := make([]error, 0, len(errs))92 for _, err := range errs {93 if err == nil {94 continue95 }96 if m, ok := err.(*multiError); ok && m != nil {97 nonNil = append(nonNil, m.Unwrap()...)98 } else {99 nonNil = append(nonNil, err)100 }101 }102103 switch len(nonNil) {104 case 0:105 return nil106 case 1:107 return nonNil[0]108 default:109 return &multiError{errors: nonNil}110 }111}112Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.