/* * 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) } }