package result import ( "reflect" "runtime" mKs "gitp78su.ipnodns.ru/svi/kern/v4/lev0/core_spec" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/defs" mKh "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers" ) // Result — обёртка вокруг результата с возможной ошибкой. // // Может быть либо только полезное значение, либо только ошибка. type Result[T any] struct { val T // Полезное значение isCheck bool // Если проверено err defs.IErr // Ошибка } var ( str5 = defs.AStr("NewOk(): result==nil") ) // NewOk -- возвращает успешный Result с значением. func NewOk[T any](result T) mKs.IResult[T] { // Для некоторых типов нужна дополнительная проверка через reflect v := reflect.ValueOf(result) switch v.Kind() { case reflect.Pointer, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface: mKh.Hassert(!v.IsNil(), str5) } sf := &Result[T]{ val: result, } runtime.SetFinalizer(sf, sf.destroy) return sf } var ( str6 = defs.AStr("NewErr(): err==nil") ) // NewErr -- возвращает Result с ошибкой. func NewErr[T any](err defs.IErr) mKs.IResult[T] { mKh.Hassert(err != nil, str6) sf := &Result[T]{ err: err, } runtime.SetFinalizer(sf, sf.destroy) return sf } var ( str7 = defs.AStr("WrapErr(): result not have error") str8 = defs.AStr("WrapErr(): err==nil") ) // WrapErr -- оборачивает существующий Result с ошибкой с новой ошибкой. func WrapErr[T any](res mKs.IResult[T], err defs.IErr) mKs.IResult[T] { mKh.Hassert(res.IsErr(), str7) mKh.Hassert(err != nil, str8) err0 := res.Err() // Чтобы не было паники при финализации и обернуть ошибку err = defs.NewErr("%v, err=\n\t%w", err0, err) sf := NewErr[T](err) return sf } var ( str9 = defs.AStr("Result[T].destroy(): err not checked") ) func (sf *Result[T]) destroy(res *Result[T]) { if !res.isCheck { mKh.Hassert(false, str9) } } // IsOk -- возвращает true, если Result содержит значение. func (sf *Result[T]) IsOk() bool { sf.isCheck = true return sf.err == nil } // IsErr -- возвращает true, если Result содержит ошибку. func (sf *Result[T]) IsErr() bool { sf.isCheck = true return sf.err != nil } // Ok -- возвращает значение, если оно есть, иначе паникует. func (sf *Result[T]) Ok() T { mKh.Hassert(sf.err == nil, "Result[T].Ok(): err!=nil, err=\n\t%v", sf.err) sf.isCheck = true return sf.val } // OkOr -- возвращает значение, если оно есть, или значение по умолчанию. func (sf *Result[T]) OkOr(defaultValue T) T { sf.isCheck = true if sf.err != nil { sf.val = defaultValue sf.err = nil } return sf.Ok() } var ( str11 = defs.AStr("Result[T].OkOrFn(): fn==nil") ) // OkOrFn -- возвращает значение, если оно есть, или результат выполнения функции. func (sf *Result[T]) OkOrFn(fn func() T) T { mKh.Hassert(fn != nil, str11) sf.isCheck = true if sf.err != nil { sf.val = fn() sf.err = nil } return sf.Ok() } var ( str12 = defs.AStr("Result[T].Err(): err==nil") ) // Err -- возвращает ошибку, если она есть. func (sf *Result[T]) Err() error { mKh.Hassert(sf.err != nil, str12) sf.isCheck = true return sf.err } const str13 = "Result[T].Error(): err==nil" // Error -- возвращает строковое представление ошибки, если она есть. func (sf *Result[T]) Error() string { mKh.Hassert(sf.err != nil, str13) sf.isCheck = true return sf.err.Error() } // Hassert -- проверяет, что нет ошибки (с паникой). func (sf *Result[T]) Hassert(msgFormat defs.AStr, args ...any) T { strErr := defs.AStr("") if !sf.isCheck { strErr = defs.Str("Result[T].Hassert(): not check error, err=\n\t%v", sf.err) } strErr = defs.Str(msgFormat+strErr, args...) mKh.Hassert(sf.err == nil, strErr) sf.isCheck = true return sf.val } // Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде). func (sf *Result[T]) Assert(msgFormat defs.AStr, args ...any) T { strErr := defs.AStr("") if !sf.isCheck { strErr = defs.Str("Result[T].Assert(): not check error, , err=\n\t%v", sf.err).Str() } mKh.Assert(sf.err == nil, msgFormat+strErr, args...) sf.isCheck = true return sf.val }