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 }