github.com/searKing/golang/go@v1.2.74/errors/mark.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 = markError{} // verify that Error implements error
    14  
    15  // Mark returns an error with the supplied errors as marks.
    16  // If err is nil, return nil.
    17  // marks take effects only when Is and '%v' in fmt.
    18  // Is returns true if err or any marks match the target.
    19  func Mark(err error, marks ...error) error {
    20  	if err == nil {
    21  		return nil
    22  	}
    23  	if len(marks) == 0 {
    24  		return err
    25  	}
    26  	me := markError{
    27  		err:   err,
    28  		marks: marks,
    29  	}
    30  	return me
    31  }
    32  
    33  type markError struct {
    34  	err   error   // visual error
    35  	marks []error // hidden errors as marks, take effects only when Is and '%v' in fmt.
    36  }
    37  
    38  func (e markError) Error() string {
    39  	if e.err == nil {
    40  		return ""
    41  	}
    42  	return e.err.Error()
    43  }
    44  
    45  func (e markError) Format(s fmt.State, verb rune) {
    46  	if e.err == nil {
    47  		return
    48  	}
    49  	switch verb {
    50  	case 'v':
    51  		if s.Flag('+') {
    52  			me := e.clean()
    53  			if len(me.marks) == 0 {
    54  				_, _ = fmt.Fprintf(s, "%+v", me.err)
    55  				return
    56  			}
    57  			_, _ = io.WriteString(s, "Marked errors occurred:\n")
    58  
    59  			_, _ = fmt.Fprintf(s, "|\t%+v", me.err)
    60  			for _, mark := range me.marks {
    61  				_, _ = fmt.Fprintf(s, "\nM\t%+v", mark)
    62  			}
    63  			return
    64  		}
    65  		fallthrough
    66  	case 's', 'q':
    67  		_, _ = io.WriteString(s, e.Error())
    68  	}
    69  }
    70  
    71  // clean removes all none nil elem in all the marks
    72  func (e markError) clean() markError {
    73  	var marks []error
    74  	for _, err := range e.marks {
    75  		if err != nil {
    76  			marks = append(marks, err)
    77  		}
    78  	}
    79  	return markError{
    80  		err:   e.err,
    81  		marks: marks,
    82  	}
    83  }
    84  
    85  // Is reports whether any error in markError or it's mark errors matches target.
    86  func (e markError) Is(target error) bool {
    87  	if errors.Is(e.err, target) {
    88  		return true
    89  	}
    90  	for _, err := range e.marks {
    91  		if errors.Is(err, target) {
    92  			return true
    93  		}
    94  	}
    95  	return false
    96  }
    97  
    98  // Unwrap returns the error in e, if there is exactly one. If there is more than one
    99  // error, Unwrap returns nil, since there is no way to determine which should be
   100  // returned.
   101  func (e markError) Unwrap() error {
   102  	return e.err
   103  }
   104  
   105  // As finds the first error in err's chain that matches target, and if one is found, sets
   106  // target to that error value and returns true. Otherwise, it returns false.
   107  func (e markError) As(target any) bool {
   108  	if errors.As(e.err, target) {
   109  		return true
   110  	}
   111  	for _, err := range e.marks {
   112  		if errors.As(err, target) {
   113  			return true
   114  		}
   115  	}
   116  	return false
   117  }