github.com/searKing/golang/go@v1.2.74/errors/multi.go (about)

     1  // Copyright 2021 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package errors
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  )
    12  
    13  var _ error = multiError{} // verify that Error implements error
    14  
    15  // Multi returns an error with the supplied errors.
    16  // If no error contained, return nil.
    17  func Multi(errs ...error) error {
    18  	me := multiError(errs).clean()
    19  	if me == nil || len(me) == 0 {
    20  		return nil
    21  	}
    22  	return me
    23  }
    24  
    25  type multiError []error
    26  
    27  func (e multiError) Error() string {
    28  	errs := e.clean()
    29  	if errs == nil || len(errs) == 0 {
    30  		return ""
    31  	}
    32  	message := errs[0].Error()
    33  	for _, err := range errs[1:] {
    34  		message += "|" + err.Error()
    35  	}
    36  
    37  	return message
    38  }
    39  
    40  func (e multiError) Format(s fmt.State, verb rune) {
    41  	errs := e.clean()
    42  	if errs == nil || len(errs) == 0 {
    43  		return
    44  	}
    45  	switch verb {
    46  	case 'v':
    47  		if s.Flag('+') {
    48  			if len(errs) == 1 {
    49  				_, _ = fmt.Fprintf(s, "%+v", errs[0])
    50  				return
    51  			}
    52  			_, _ = io.WriteString(s, "Multiple errors occurred:\n")
    53  
    54  			_, _ = fmt.Fprintf(s, "|\t%+v", errs[0])
    55  			for _, err := range errs[1:] {
    56  				_, _ = fmt.Fprintf(s, "\n|\t%+v", err)
    57  			}
    58  			return
    59  		}
    60  		fallthrough
    61  	case 's', 'q':
    62  		_, _ = io.WriteString(s, errs.Error())
    63  	}
    64  }
    65  
    66  // clean removes all none nil elem in all the errors
    67  func (e multiError) clean() multiError {
    68  	var errs []error
    69  	for _, err := range e {
    70  		if err != nil {
    71  			errs = append(errs, err)
    72  		}
    73  	}
    74  	return errs
    75  }
    76  
    77  // Is reports whether any error in multiError matches target.
    78  func (e multiError) Is(target error) bool {
    79  	if target == nil {
    80  		errs := e.clean()
    81  		if errs == nil || len(errs) == 0 {
    82  			return true
    83  		}
    84  		return false
    85  	}
    86  	for _, err := range e {
    87  		if err == nil {
    88  			continue
    89  		}
    90  		if errors.Is(err, target) {
    91  			return true
    92  		}
    93  	}
    94  	return false
    95  }
    96  
    97  // Unwrap returns the error in e, if there is exactly one. If there is more than one
    98  // error, Unwrap returns nil, since there is no way to determine which should be
    99  // returned.
   100  func (e multiError) Unwrap() error {
   101  	if len(e) == 1 {
   102  		return e[0]
   103  	}
   104  	// Return nil when e is nil, or has more than one error.
   105  	// When there are multiple errors, it doesn't make sense to return any of them.
   106  	return nil
   107  }
   108  
   109  // As finds the first error in err's chain that matches target, and if one is found, sets
   110  // target to that error value and returns true. Otherwise, it returns false.
   111  func (e multiError) As(target any) bool {
   112  	for _, err := range e {
   113  		if errors.As(err, target) {
   114  			return true
   115  		}
   116  	}
   117  	return false
   118  }