Skip to content

Commit

Permalink
fea: added TypeIs(target)
Browse files Browse the repository at this point in the history
  • Loading branch information
hedzr committed Feb 11, 2022
1 parent d8fa44b commit 11bf2c1
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 305 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x]
go-version: [1.12.x, 1.17.x]
#os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest]
fail-fast: false
Expand All @@ -35,7 +35,7 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Test
run: go test ./...
run: go test ./... -v -race

coverage:
#needs: test
Expand All @@ -46,7 +46,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: 1.17.x
- name: Checkout code
uses: actions/checkout@v2
#with:
Expand Down
71 changes: 71 additions & 0 deletions as.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package errors

import "reflect"

// As finds the first error in `err`'s chain that matches target, and if so, sets
// target to that error value and returns true.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// As will panic if target is not a non-nil pointer to either a type that implements
// error, or to any interface type. As returns false if err is nil.
func As(err error, target interface{}) bool {
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for err != nil {
if reflect.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}

// AsSlice tests err.As for errs slice
func AsSlice(errs []error, target interface{}) bool {
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for _, err := range errs {
if reflect.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}

var errorType = reflect.TypeOf((*error)(nil)).Elem()
52 changes: 6 additions & 46 deletions coded.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,56 +325,16 @@ func (w *WithCodeInfo) Unwrap() error {
// target to that error value and returns true.
func (w *WithCodeInfo) As(target interface{}) bool {
return As(w.causer, target)
//if target == nil {
// panic("errors: target cannot be nil")
//}
//val := reflect.ValueOf(target)
//typ := val.Type()
//if typ.Kind() != reflect.Ptr || val.IsNil() {
// panic("errors: target must be a non-nil pointer")
//}
//if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
// panic("errors: *target must be interface or implement error")
//}
//targetType := typ.Elem()
//err := w.causer
//for err != nil {
// if reflect.TypeOf(err).AssignableTo(targetType) {
// val.Elem().Set(reflect.ValueOf(err))
// return true
// }
// if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
// return true
// }
// err = Unwrap(err)
//}
//return false
}

// Is reports whether any error in err's chain matches target.
func (w *WithCodeInfo) Is(target error) bool {
return w.causer == target || Is(w.causer, target)
//if target == nil {
// return w.causer == target
//}
//
//isComparable := reflect.TypeOf(target).Comparable()
//for {
// if isComparable && w.causer == target {
// return true
// }
// if x, ok := w.causer.(interface{ Is(error) bool }); ok && x.Is(target) {
// return true
// }
// // TO/DO: consider supporting target.Is(err). This would allow
// // user-definable predicates, but also may allow for coping with sloppy
// // APIs, thereby making it easier to get away with them.
// //if err := Unwrap(w.causer); err == nil {
// // return false
// //}
//
// return w.causer == target
//}
}

// TypeIs reports whether any error in err's chain matches target.
func (w *WithCodeInfo) TypeIs(target error) bool {
return w.causer == target || TypeIs(w.causer, target)
}

//
Expand Down Expand Up @@ -446,7 +406,7 @@ func (c Code) String() string {
return codeToStr[Unknown]
}

// Register register a code and its token string for using later
// Register registers a code and its token string for using later
func (c Code) Register(codeName string) (errno Code) {
errno = AlreadyExists
if c <= MinErrorCode || c > 0 {
Expand Down
34 changes: 4 additions & 30 deletions container.causes.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,36 +82,10 @@ func (w *causes) Unwrap() error {

func (w *causes) Is(target error) bool {
return IsSlice(w.Causers, target)
//if target == nil {
// //for _, e := range w.Causers {
// // if e == target {
// // return true
// // }
// //}
// return false
//}
//
//isComparable := reflect.TypeOf(target).Comparable()
//for {
// if isComparable {
// for _, e := range w.Causers {
// if e == target {
// return true
// }
// }
// // return false
// }
//
// for _, e := range w.Causers {
// if x, ok := e.(interface{ Is(error) bool }); ok && x.Is(target) {
// return true
// }
// //if err := Unwrap(e); err == nil {
// // return false
// //}
// }
// return false
//}
}

func (w *causes) TypeIs(target error) bool {
return TypeIsSlice(w.Causers, target)
}

// As finds the first error in `err`'s chain that matches target, and if so, sets
Expand Down
Loading

0 comments on commit 11bf2c1

Please sign in to comment.