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