package errutil import ( "fmt" "sort" ) // ErrorFactory is used for create or check ErrorObject type ErrorFactory interface { Error() string Name() string New(err error, params ...interface{}) ErrorObject Match(err error) bool In(err error) bool } type errorFactory struct { errtext string name string } var namedFactories = map[string]ErrorFactory{} // AllNamedFactories return all named factories func AllNamedFactories() map[string]ErrorFactory { return namedFactories } // AllSortedNamedFactories return all sorted named factories // NOTE: this is slow for sorting in runtime func AllSortedNamedFactories() []ErrorFactory { sorter := newSorter(namedFactories) sort.Sort(sorter) return sorter.data } // NewFactory return new ErrorFactory instance func NewFactory(errtext string) ErrorFactory { callinfo, _ := RuntimeCaller(1) return NewNamedFactory(callinfo.PackageName()+"->"+errtext, errtext) } // NewNamedFactory return new ErrorFactory instance with factory name, panic if name duplicated func NewNamedFactory(name string, errtext string) ErrorFactory { if _, ok := namedFactories[name]; ok { panic(fmt.Errorf("error factory name duplicated: %q", name)) } factory := &errorFactory{ errtext: errtext, name: name, } namedFactories[name] = factory return factory } // FactoryOf return factory of error, return nil if not factory found func FactoryOf(err error) ErrorFactory { errobj := castErrorObject(nil, 1, err) if errobj == nil { return nil } return errobj.Factory() } func (t errorFactory) Error() string { return t.errtext } func (t errorFactory) Name() string { return t.name } func (t *errorFactory) New(parent error, params ...interface{}) ErrorObject { errobj := castErrorObject(t, 1, fmt.Errorf(t.errtext, params...)) errobj.SetParent(castErrorObject(nil, 1, parent)) return errobj } func (t *errorFactory) Match(err error) bool { if t == nil || err == nil { return false } errcomp := castErrorObject(nil, 1, err) if errcomp == nil { return false } return errcomp.Factory() == t } func (t *errorFactory) In(err error) bool { if t == nil || err == nil { return false } exist := false if errtmp := WalkErrors(castErrorObject(nil, 1, err), func(errcomp ErrorObject) (stop bool, walkerr error) { if errcomp.Factory() == t { exist = true return true, nil } return false, nil }); errtmp != nil { panic(errtmp) } return exist } var _ ErrorFactory = (*errorFactory)(nil)