Files
golib/errors/errors.go
Nicolas JUHEL 1528588499 Package errors:
- implement GOROOT/src/errors Is interface
- fix bug with GOROOT/src/errors UnWrap / Is
2025-02-28 17:37:31 +01:00

390 lines
6.5 KiB
Go

/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package errors
import (
"errors"
"fmt"
"runtime"
"strings"
)
type ers struct {
c uint16
e string
p []Error
t runtime.Frame
}
func (e *ers) is(err *ers) bool {
if e == nil || err == nil {
return false
}
var (
ss = e.GetTrace()
sd = err.GetTrace()
ts = len(ss) > 0
td = len(sd) > 0
)
if (ts || td) && !(ts && td) { // XOR Trace Source & Destination != 0
return false
} else if ts && td {
return strings.EqualFold(ss, sd)
}
ss = e.Error()
sd = err.Error()
ts = len(ss) > 0
td = len(sd) > 0
if (ts || td) && !(ts && td) { // XOR Message Source & Destination != 0
return false
} else if ts && td {
return strings.EqualFold(ss, sd)
}
var (
cs = e.Code()
cd = err.Code()
)
ts = cs > 0
td = cd > 0
if (ts || td) && !(ts && td) { // XOR Message Source & Destination != 0
return false
} else if ts && td {
return cs != cd
}
return false
}
func (e *ers) Is(err error) bool {
if er, ok := err.(*ers); ok {
return e.is(er)
} else {
return e.IsError(err)
}
}
func (e *ers) Add(parent ...error) {
for _, v := range parent {
if v == nil {
continue
}
var (
ok bool
er *ers
err Error
)
if er, ok = v.(*ers); ok {
// prevent circular addition
if e.IsError(er) {
for _, erp := range er.p {
e.Add(erp)
}
} else {
e.p = append(e.p, er)
}
} else if err, ok = v.(Error); !ok {
e.p = append(e.p, &ers{
c: 0,
e: v.Error(),
p: nil,
})
} else {
e.p = append(e.p, err)
}
}
}
func (e *ers) IsCode(code CodeError) bool {
return e.c == code.GetUint16()
}
func (e *ers) IsError(err error) bool {
return strings.EqualFold(e.e, err.Error())
}
func (e *ers) HasCode(code CodeError) bool {
if e.IsCode(code) {
return true
}
for _, p := range e.p {
if p.HasCode(code) {
return true
}
}
return false
}
func (e *ers) GetCode() CodeError {
return CodeError(e.c)
}
func (e *ers) GetParentCode() []CodeError {
var res = make([]CodeError, 0)
res = append(res, e.GetCode())
for _, p := range e.p {
res = append(res, p.GetParentCode()...)
}
return unicCodeSlice(res)
}
func (e *ers) HasError(err error) bool {
if e.IsError(err) {
return true
}
for _, p := range e.p {
if p.IsError(err) {
return true
}
}
return false
}
func (e *ers) HasParent() bool {
return len(e.p) > 0
}
func (e *ers) GetParent(withMainError bool) []error {
var res = make([]error, 0)
if withMainError {
res = append(res, &ers{
c: e.c,
e: e.e,
p: nil,
t: e.t,
})
}
if len(e.p) > 0 {
for _, er := range e.p {
res = append(res, er.GetParent(true)...)
}
}
return res
}
func (e *ers) SetParent(parent ...error) {
e.p = make([]Error, 0)
e.Add(parent...)
}
func (e *ers) Map(fct FuncMap) bool {
if !fct(e) {
return false
} else if len(e.p) > 0 {
for _, er := range e.p {
if !er.Map(fct) {
return false
}
}
}
return true
}
func (e *ers) ContainsString(s string) bool {
if strings.Contains(e.e, s) {
return true
} else {
for _, i := range e.p {
if i.ContainsString(s) {
return true
}
}
}
return false
}
func (e *ers) Code() uint16 {
return e.c
}
func (e *ers) CodeSlice() []uint16 {
var r = []uint16{e.Code()}
for _, v := range e.p {
if v.Code() > 0 {
r = append(r, v.Code())
}
}
return r
}
func (e *ers) Error() string {
return modeError.error(e)
}
func (e *ers) StringError() string {
return e.e
}
func (e *ers) StringErrorSlice() []string {
var r = []string{e.StringError()}
for _, v := range e.p {
r = append(r, v.Error())
}
return r
}
func (e *ers) GetError() error {
//nolint goerr113
return errors.New(e.e)
}
func (e *ers) GetErrorSlice() []error {
var r = []error{e.GetError()}
if len(e.p) < 1 {
return r
}
for _, v := range e.p {
if v == nil {
continue
}
r = append(r, v.GetErrorSlice()...)
}
return r
}
func (e *ers) Unwrap() []error {
if len(e.p) < 1 {
return nil
}
var r = make([]error, 0)
for _, v := range e.p {
if v == nil {
continue
}
r = append(r, v)
}
return r
}
func (e *ers) GetTrace() string {
if e.t.File != "" {
return fmt.Sprintf("%s#%d", filterPath(e.t.File), e.t.Line)
} else if e.t.Function != "" {
return fmt.Sprintf("%s#%d", e.t.Function, e.t.Line)
}
return ""
}
func (e *ers) GetTraceSlice() []string {
var r = []string{e.GetTrace()}
for _, v := range e.p {
if t := v.GetTrace(); t != "" {
r = append(r, v.GetTrace())
}
}
return r
}
func (e *ers) CodeError(pattern string) string {
if pattern == "" {
pattern = defaultPattern
}
return fmt.Sprintf(pattern, e.Code(), e.StringError())
}
func (e *ers) CodeErrorSlice(pattern string) []string {
var r = []string{e.CodeError(pattern)}
for _, v := range e.p {
r = append(r, v.CodeError(pattern))
}
return r
}
func (e *ers) CodeErrorTrace(pattern string) string {
if pattern == "" {
pattern = defaultPatternTrace
}
return fmt.Sprintf(pattern, e.Code(), e.StringError(), e.GetTrace())
}
func (e *ers) CodeErrorTraceSlice(pattern string) []string {
var r = []string{e.CodeErrorTrace(pattern)}
for _, v := range e.p {
r = append(r, v.CodeErrorTrace(pattern))
}
return r
}
func (e *ers) Return(r Return) {
e.ReturnError(r.SetError)
e.ReturnParent(r.AddParent)
}
func (e *ers) ReturnError(f ReturnError) {
if e.t.File != "" {
f(int(e.c), e.e, e.t.File, e.t.Line)
} else {
f(int(e.c), e.e, e.t.Function, e.t.Line)
}
}
func (e *ers) ReturnParent(f ReturnError) {
for _, p := range e.p {
p.ReturnError(f)
p.ReturnParent(f)
}
}