package result import ( "fmt" "runtime" "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/def_spec_base" "gitp78su.ipnodns.ru/svi/kern/v4/d0/helpers" ) // Result — обёртка вокруг результата с возможной ошибкой. // // Может быть либо только полезное значение, либо только ошибка. type Result[T any] struct { val T // Полезное значение isCheck def_spec_base.Bool // Если проверено err error // Ошибка } const ( str5 = def_spec_base.Txt("NewOk(): result==nil") ) // ResOk -- возвращает успешный Result с значением. func ResOk[T any](result T) *Result[T] { helpers.If(helpers.IsNil(result)).Hassert(str5) sf := &Result[T]{ val: result, } runtime.SetFinalizer(sf, sf.destroy) return sf } var ( str6 = def_spec_base.Txt("NewErr(): err==nil") ) // ResErr -- возвращает Result с ошибкой. func ResErr[T any](err error) *Result[T] { helpers.If(err == nil).Hassert(str6) sf := &Result[T]{ err: err, } runtime.SetFinalizer(sf, sf.destroy) return sf } var ( str7 = def_spec_base.Txt("WrapErr(): result not have error") str8 = def_spec_base.Txt("WrapErr(): err==nil") ) // WrapErr -- оборачивает существующий Result с ошибкой с новой ошибкой. func WrapErr[T any](res *Result[T], err error) *Result[T] { helpers.If(res.IsOk()).Hassert(str7) helpers.If(err == nil).Hassert(str8) err0 := res.Err() // Чтобы не было паники при финализации и обернуть ошибку err = fmt.Errorf("%v, err=\n\t%w", err0, err) sf := ResErr[T](err) return sf } var ( str9 = def_spec_base.Txt("Result[T].destroy(): err not checked") ) func (sf *Result[T]) destroy(res *Result[T]) { helpers.If(!res.isCheck).Hassert(str9) } // IsOk -- возвращает true, если Result содержит значение. func (sf *Result[T]) IsOk() def_spec_base.Bool { sf.isCheck = true return sf.err == nil } // IsErr -- возвращает true, если Result содержит ошибку. func (sf *Result[T]) IsErr() def_spec_base.Bool { sf.isCheck = true return sf.err != nil } // Ok -- возвращает значение, если оно есть, иначе паникует. func (sf *Result[T]) Ok() T { helpers.If(sf.err != nil).Hassert("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 = def_spec_base.Txt("Result[T].OkOrFn(): fn==nil") ) // OkOrFn -- возвращает значение, если оно есть, или результат выполнения функции. func (sf *Result[T]) OkOrFn(fn func() T) T { helpers.If(fn == nil).Hassert(str11) sf.isCheck = true if sf.err != nil { sf.val = fn() sf.err = nil } return sf.Ok() } var ( str12 = def_spec_base.Txt("Result[T].Err(): err==nil") ) // Err -- возвращает ошибку, если она есть. func (sf *Result[T]) Err() error { helpers.If(sf.err == nil).Hassert(str12) sf.isCheck = true return sf.err } const str13 = "Result[T].Error(): err==nil" // Error -- возвращает строковое представление ошибки, если она есть. func (sf *Result[T]) Error() string { helpers.If(sf.err == nil).Hassert(str13) sf.isCheck = true return sf.err.Error() } // Hassert -- проверяет, что нет ошибки (с паникой). func (sf *Result[T]) Hassert(msgFormat def_spec_base.Txt, args ...any) T { if sf.err != nil { txtErr := fmt.Sprintf("Result[T].Hassert(): have error, err=\n\t%v", sf.err) msgErr := def_spec_base.Txt(txtErr) helpers.If(sf.err != nil).Hassert(msgErr) } sf.isCheck = true return sf.val } // Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде). func (sf *Result[T]) Assert(msgFormat def_spec_base.Txt, args ...any) T { if sf.err != nil { strErr := fmt.Sprintf("Result[T].Assert(): have error, , err=\n\t%v", sf.err) txtErr:=def_spec_base.Txt(strErr) helpers.If(sf.err != nil).Assert(txtErr, args...) } sf.isCheck = true return sf.val }