package result import ( "fmt" "reflect" "runtime" . "gitp78su.ipnodns.ru/svi/kern/v4/lev0/ktypes" . "gitp78su.ipnodns.ru/svi/kern/v4/lev1/helpers" ) // Result — обёртка вокруг результата с возможной ошибкой // // Может быть либо только полезное значение, либо только ошибка type Result[T any] struct { val T // Полезное значение isErr bool // Если содержит ошибку isCheck bool // Если проверено err error // Ошибка } // NewRes -- возвращает успешный Result с значением func NewRes[T any](result T) IResult[T] { // Для некоторых типов нужна дополнительная проверка через reflect v := reflect.ValueOf(result) switch v.Kind() { case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface: Hassert(!v.IsNil(), "NewOk(): result==nil") } sf := &Result[T]{ val: result, } runtime.SetFinalizer(sf, sf.destroy) return sf } // NewErr -- возвращает Result с ошибкой func NewErr[T any](err error) IResult[T] { Hassert(err != nil, "NewError(): err==nil") sf := &Result[T]{ err: err, isErr: true, } runtime.SetFinalizer(sf, sf.destroy) return sf } // WrapErr -- оборачивает существующий Result с ошибкой с новой ошибкой func WrapErr[T any](res IResult[T], err error) IResult[T] { Hassert(res.IsErr(), "WrapErr(): result not have error") Hassert(err != nil, "WrapErr(): err==nil") err0 := res.Err() // Чтобы не было паники при финализации и обернуть ошибку err = fmt.Errorf("%v, err=\n\t%w", err0, err) sf := NewErr[T](err) return sf } func (sf *Result[T]) destroy(res *Result[T]) { if !res.isCheck { Hassert(false, "Result[T].destroy(): err not checked") } } // IsOk -- возвращает true, если Result содержит значение func (sf *Result[T]) IsOk() bool { sf.isCheck = true return !sf.isErr } // IsErr -- возвращает true, если Result содержит ошибку func (sf *Result[T]) IsErr() bool { sf.isCheck = true return sf.isErr } // Val -- возвращает значение, если оно есть, иначе паникует func (sf *Result[T]) Val() T { Hassert(!sf.isErr, "Result[T].Val(): err(%v)!=nil", sf.err) return sf.val } // ValOr -- возвращает значение, если оно есть, или значение по умолчанию func (sf *Result[T]) ValOr(defaultValue T) T { sf.isCheck = true if sf.isErr { return defaultValue } return sf.val } // ValOrFn -- возвращает значение, если оно есть, или результат выполнения функции func (sf *Result[T]) ValOrFn(fn func() T) T { Hassert(fn != nil, "Result[T].ValOrFn(): fn==nil") sf.isCheck = true if sf.isErr { return fn() } return sf.val } // Err -- возвращает ошибку, если она есть func (sf *Result[T]) Err() error { Hassert(sf.isErr, "Result[T].Err(): err==nil") sf.isCheck = true return sf.err } // Error -- возвращает строковое представление ошибки, если она есть func (sf *Result[T]) Error() string { Hassert(sf.isErr, "Result[T].Error(): err==nil") sf.isCheck = true return sf.err.Error() } // Hassert -- проверяет, что нет ошибки (с паникой) func (sf *Result[T]) Hassert(msgFormat string, args ...any) T { strErr := "" if sf.isErr { strErr = fmt.Sprintf(", err=\n\t%v", sf.err) } msg := fmt.Sprintf(msgFormat+strErr, args...) Hassert(!sf.isErr, msg) sf.isCheck = true return sf.val } // Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде) func (sf *Result[T]) Assert(msgFormat string, args ...any) T { strErr := "" if sf.isErr { strErr = fmt.Sprintf(", err=\n\t%v", sf.err) } msg := fmt.Sprintf(msgFormat+strErr, args...) Assert(!sf.isErr, msg) sf.isCheck = true return sf.val }