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 }