Kaynağa Gözat

SVI Добавление типов Result и Option; 100.0%

SVI 1 yıl önce
ebeveyn
işleme
a77bc80e24

+ 0 - 74
kc/helpers/result.txt

@@ -1,74 +0,0 @@
-package helpers
-
-// Result — аналог Result<T, E> из Rust
-//
-// Может быть либотолько полезное значение, либо только ошибка
-type Result[T any] struct {
-	value T     // Полезное значение
-	err   error // Ошибка
-}
-
-// NewResult -- возвращает успешный Result с значением
-func NewResult[T *any](result T) *Result[T] {
-	Hassert(result != nil, "NewResult(): result==nil")
-	return &Result[T]{
-		value: result,
-	}
-}
-
-// NewResultErr -- возвращает Result с ошибкой
-func NewResultErr[T any](err error) *Result[T] {
-	Hassert(err != nil, "NewError(): err==nil")
-	return &Result[T]{
-		err: err,
-	}
-}
-
-// IsOk -- возвращает true, если Result содержит значение
-func (sf *Result[T]) IsOk() bool {
-	return sf.err == nil
-}
-
-// IsErr -- возвращает true, если Result содержит ошибку
-func (sf *Result[T]) IsErr() bool {
-	return sf.err != nil
-}
-
-// Unwrap -- возвращает значение, если оно есть, иначе паникует
-func (sf *Result[T]) Unwrap() T {
-	if sf.err != nil {
-		panic(sf.err)
-	}
-	return sf.value
-}
-
-// UnwrapOr -- возвращает значение, если оно есть, или значение по умолчанию
-func (sf *Result[T]) UnwrapOr(defaultValue T) T {
-	if sf.IsErr() {
-		return defaultValue
-	}
-	return sf.value
-}
-
-// UnwrapOrElse -- возвращает значение, если оно есть, или результат выполнения функции
-func (sf *Result[T]) UnwrapOrElse(f func() T) T {
-	if sf.IsErr() {
-		return f()
-	}
-	return sf.value
-}
-
-// Error -- возвращает ошибку, если она есть
-func (sf *Result[T]) Error() error {
-	return sf.err
-}
-
-// HAssert -- проверяет, что нет ошибки (с паникой)
-func (sf *Result[T]) Hassert(msg string) {
-	Hassert(sf.err != nil, msg+", err=\n\t%v\n", sf.err)
-}
-
-// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
-func (sf *Result[T]) Assert(msg string) {
-	Assert(sf.err != nil, msg+", err=\n\t%v\n", sf.err)
-}

+ 22 - 0
kern.go

@@ -19,6 +19,8 @@ import (
 	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
 	"gitp78su.ipnodns.ru/svi/kern/krn/kmodule"
 	"gitp78su.ipnodns.ru/svi/kern/krn/kmonolit"
+	"gitp78su.ipnodns.ru/svi/kern/krn/koption"
+	"gitp78su.ipnodns.ru/svi/kern/krn/kresult"
 	"gitp78su.ipnodns.ru/svi/kern/krn/kserv_http"
 	"gitp78su.ipnodns.ru/svi/kern/krn/kstore_kv"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
@@ -167,3 +169,23 @@ func NewSafeString() ISafeString {
 	str := safe_string.NewSafeString()
 	return str
 }
+
+// NewOk -- возвращает новый положительный результат операции
+func NewOk[T any](res T) *kresult.Result[T] {
+	return kresult.NewOk(res)
+}
+
+// NewErr -- возвращает новую ошибку результат операции
+func NewErr(err error) *kresult.Result[any] {
+	return kresult.NewErr(err)
+}
+
+// NewSome -- возвращает новый не пустой результат операции
+func NewSome[T any](some T) *koption.Option[T] {
+	return koption.NewSome(some)
+}
+
+// NewNone -- возвращает новый пустой результат операции
+func NewNone() *koption.Option[any] {
+	return koption.NewNone()
+}

+ 20 - 0
kern_test.go

@@ -1,6 +1,7 @@
 package kern
 
 import (
+	"fmt"
 	"os"
 	"testing"
 
@@ -133,6 +134,25 @@ func (sf *tester) new() {
 		sf.t.Fatalf("new(): ISafeStr==nil")
 	}
 
+	res := NewOk("test ok")
+	if res == nil {
+		sf.t.Fatalf("new(): res==nil")
+	}
+	resErr := NewErr(fmt.Errorf("test err"))
+	if resErr == nil {
+		sf.t.Fatalf("new(): resErr==nil")
+	}
+
+	some := NewSome("test err")
+	if some == nil {
+		sf.t.Fatalf("new(): some==nil")
+	}
+
+	none := NewNone()
+	if none == nil {
+		sf.t.Fatalf("new(): none==nil")
+	}
+
 	kernServHttp := GetKernelServerHttp()
 	go kernServHttp.Run()
 	ctx.Cancel()

+ 72 - 0
krn/koption/koption.go

@@ -0,0 +1,72 @@
+package koption
+
+import (
+	"reflect"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+)
+
+// Option -- результат возможно содержащий nil
+type Option[T any] struct {
+	val *T
+}
+
+// NewSome - полезный результат
+func NewSome[T any](value T) *Option[T] {
+	// Для некоторых типов нужна дополнительная проверка через reflect
+	v := reflect.ValueOf(value)
+	switch v.Kind() {
+	case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface:
+		Hassert(!v.IsNil(), "NewSome[T any](): value==nil")
+	}
+	sf := &Option[T]{val: &value}
+	return sf
+}
+
+// NewNone - нет результата в ответе
+func NewNone() *Option[any] {
+	return &Option[any]{nil}
+}
+
+// IsSome - проверяет, есть ли значение
+func (sf *Option[T]) IsSome() bool {
+	return sf.val != nil
+}
+
+// IsSome - проверяет, есть ли значение
+func (sf *Option[T]) IsNone() bool {
+	return sf.val == nil
+}
+
+// Unwrap - извлекает значение (паника, если None)
+func (sf *Option[T]) Unwrap() T {
+	Hassert(sf.val != nil, "Option[T].Unwrap(): Called Unwrap on None!")
+	return *sf.val
+}
+
+// UnwrapOr - возвращает значение или дефолтное
+func (sf Option[T]) UnwrapOr(defaultValue T) T {
+	if sf.val == nil {
+		return defaultValue
+	}
+	return *sf.val
+}
+
+// UnwrapOrFn -- возвращает значение, если оно есть, или результат выполнения функции
+func (sf *Option[T]) UnwrapOrFn(fn func() T) T {
+	Hassert(fn != nil, "Result[T].UnwrapOrFn(): fn==nil")
+	if sf.val == nil {
+		return fn()
+	}
+	return *sf.val
+}
+
+// Hassert -- проверяет, что нет ошибки (с паникой)
+func (sf *Option[T]) Hassert(msg string) {
+	Hassert(sf.val != nil, msg+", val==nil\n")
+}
+
+// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
+func (sf *Option[T]) Assert(msg string) {
+	Assert(sf.val != nil, msg+", val=%v\n")
+}

+ 156 - 0
krn/koption/kresult_test.go

@@ -0,0 +1,156 @@
+package koption
+
+import (
+	"testing"
+)
+
+type tester struct {
+	t *testing.T
+}
+
+func TestResult(t *testing.T) {
+	sf := &tester{
+		t: t,
+	}
+	sf.create()
+}
+
+// Создаёт новый Result
+func (sf *tester) create() {
+	sf.t.Log("create")
+	sf.createSomeBad1()
+	sf.createSomeGood1()
+	sf.createSomeGood2()
+	sf.createNoneGood1()
+}
+
+func (sf *tester) createNoneGood1() {
+	sf.t.Log("createNoneGood1")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createNoneGood1(): panic=%v", _panic)
+		}
+	}()
+	res := NewNone()
+	if res == nil {
+		sf.t.Fatalf("createNoneGood1(): res==nil")
+	}
+	if res.IsSome() {
+		sf.t.Fatalf("createNoneGood1(): is ok")
+	}
+	if !res.IsNone() {
+		sf.t.Fatalf("createNoneGood1(): not err")
+	}
+	if val := res.UnwrapOr("test2"); val != "test2" {
+		sf.t.Fatalf("createNoneGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test1" {
+		sf.t.Fatalf("createNoneGood1(): val bad")
+	}
+	if val := res.UnwrapOrFn(sf.fnWrap2); val != "test5" {
+		sf.t.Fatalf("createNoneGood1(): val bad")
+	}
+	sf.unwrapErr(res)
+	sf.hassert(res)
+	sf.assert(res)
+}
+
+func (sf *tester) assert(res *Option[any]) {
+	sf.t.Log("assert")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("assert(): panic==nil")
+		}
+	}()
+	res.Hassert("test assert")
+}
+
+func (sf *tester) hassert(res *Option[any]) {
+	sf.t.Log("hassert")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("hassert(): panic==nil")
+		}
+	}()
+	res.Hassert("test hassert")
+}
+
+func (sf *tester) unwrapErr(res *Option[any]) {
+	sf.t.Log("unwrapErr")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("unwrapErr(): panic==nil")
+		}
+	}()
+	_ = res.Unwrap()
+}
+
+func (sf *tester) createSomeGood2() {
+	sf.t.Log("createSomeGood2")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createSomeGood2(): panic=%v", _panic)
+		}
+	}()
+	str := "test val"
+	res := NewSome(str)
+	if res == nil {
+		sf.t.Fatalf("createSomeGood1(): res==nil")
+	}
+	if !res.IsSome() {
+		sf.t.Fatalf("createSomeGood1(): not ok")
+	}
+	if res.IsNone() {
+		sf.t.Fatalf("createSomeGood1(): is err")
+	}
+	if val := res.Unwrap(); val != "test val" {
+		sf.t.Fatalf("createSomeGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test val" {
+		sf.t.Fatalf("createSomeGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test val" {
+		sf.t.Fatalf("createSomeGood1(): val bad")
+	}
+	if val := res.UnwrapOrFn(sf.fnWrap); val != "test val" {
+		sf.t.Fatalf("createSomeGood1(): val bad")
+	}
+	res.Hassert("test")
+	res.Assert("test")
+}
+
+// Функция высшего порядка для замещения ошибки
+func (sf *tester) fnWrap2() any {
+	return "test5"
+}
+
+// Функция высшего порядка для замещения ошибки
+func (sf *tester) fnWrap() string {
+	return "test1"
+}
+
+func (sf *tester) createSomeGood1() {
+	sf.t.Log("createSomeGood1")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createSomeGood1(): panic=%v", _panic)
+		}
+	}()
+	str := "test val"
+	res := NewSome(&str)
+	if res == nil {
+		sf.t.Fatalf("createSomeGood1(): res==nil")
+	}
+}
+
+// Нет результата
+func (sf *tester) createSomeBad1() {
+	sf.t.Log("createSomeBad1")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("createSomeBad1(): panic==nil")
+		}
+	}()
+	var str *string
+	_ = NewSome(str)
+}

+ 85 - 0
krn/kresult/kresult.go

@@ -0,0 +1,85 @@
+package kresult
+
+import (
+	"reflect"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+)
+
+// Result — аналог Result<T, E> из Rust
+//
+// Может быть либо только полезное значение, либо только ошибка
+type Result[T any] struct {
+	val T     // Полезное значение
+	err error // Ошибка
+}
+
+// NewOk -- возвращает успешный Result с значением
+func NewOk[T any](result T) *Result[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,
+	}
+	return sf
+}
+
+// NewErr -- возвращает Result с ошибкой
+func NewErr(err error) *Result[any] {
+	Hassert(err != nil, "NewError(): err==nil")
+	return &Result[any]{
+		err: err,
+	}
+}
+
+// IsOk -- возвращает true, если Result содержит значение
+func (sf *Result[T]) IsOk() bool {
+	return sf.err == nil
+}
+
+// IsErr -- возвращает true, если Result содержит ошибку
+func (sf *Result[T]) IsErr() bool {
+	return sf.err != nil
+}
+
+// Unwrap -- возвращает значение, если оно есть, иначе паникует
+func (sf *Result[T]) Unwrap() T {
+	Hassert(sf.err == nil, "Result[T].Unwrap(): err(%v)!=nil", sf.err)
+	return sf.val
+}
+
+// UnwrapOr -- возвращает значение, если оно есть, или значение по умолчанию
+func (sf *Result[T]) UnwrapOr(defaultValue T) T {
+	if sf.err != nil {
+		return defaultValue
+	}
+	return sf.val
+}
+
+// UnwrapOrFn -- возвращает значение, если оно есть, или результат выполнения функции
+func (sf *Result[T]) UnwrapOrFn(fn func() T) T {
+	Hassert(fn != nil, "Result[T].UnwrapOrFn(): fn==nil")
+	if sf.err != nil {
+		return fn()
+	}
+	return sf.val
+}
+
+// Error -- возвращает ошибку, если она есть
+func (sf *Result[T]) Error() error {
+	return sf.err
+}
+
+// Hassert -- проверяет, что нет ошибки (с паникой)
+func (sf *Result[T]) Hassert(msg string) {
+	Hassert(sf.err == nil, msg+", err=\n\t%v\n", sf.err)
+}
+
+// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
+func (sf *Result[T]) Assert(msg string) {
+	Assert(sf.err == nil, msg+", err=\n\t%v\n", sf.err)
+}

+ 177 - 0
krn/kresult/kresult_test.go

@@ -0,0 +1,177 @@
+package kresult
+
+import (
+	"fmt"
+	"testing"
+)
+
+type tester struct {
+	t *testing.T
+}
+
+func TestResult(t *testing.T) {
+	sf := &tester{
+		t: t,
+	}
+	sf.create()
+}
+
+// Создаёт новый Result
+func (sf *tester) create() {
+	sf.t.Log("create")
+	sf.createOkBad1()
+	sf.createOkGood1()
+	sf.createOkGood2()
+	sf.createErrBad1()
+	sf.createErrGood1()
+}
+
+func (sf *tester) createErrGood1() {
+	sf.t.Log("createErrGood1")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createErrGood1(): panic=%v", _panic)
+		}
+	}()
+	err := fmt.Errorf("test err")
+	res := NewErr(err)
+	if res == nil {
+		sf.t.Fatalf("createErrGood1(): res==nil")
+	}
+	if res.IsOk() {
+		sf.t.Fatalf("createErrGood1(): is ok")
+	}
+	if !res.IsErr() {
+		sf.t.Fatalf("createErrGood1(): not err")
+	}
+	if val := res.UnwrapOr("test2"); val != "test2" {
+		sf.t.Fatalf("createErrGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test1" {
+		sf.t.Fatalf("createErrGood1(): val bad")
+	}
+	if val := res.UnwrapOrFn(sf.fnWrap2); val != "test5" {
+		sf.t.Fatalf("createErrGood1(): val bad")
+	}
+	if err := res.Error(); err == nil {
+		sf.t.Fatalf("createErrGood1(): err == nil")
+	}
+	sf.unwrapErr(res)
+	sf.hassert(res)
+	sf.assert(res)
+}
+
+func (sf *tester) assert(res *Result[any]) {
+	sf.t.Log("assert")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("assert(): panic==nil")
+		}
+	}()
+	res.Hassert("test assert")
+}
+
+func (sf *tester) hassert(res *Result[any]) {
+	sf.t.Log("hassert")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("hassert(): panic==nil")
+		}
+	}()
+	res.Hassert("test hassert")
+}
+
+func (sf *tester) unwrapErr(res *Result[any]) {
+	sf.t.Log("unwrapErr")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("unwrapErr(): panic==nil")
+		}
+	}()
+	_ = res.Unwrap()
+}
+
+// Нет ошибки
+func (sf *tester) createErrBad1() {
+	sf.t.Log("createErrBad1")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("createErrBad1(): panic==nil")
+		}
+	}()
+	var err error
+	_ = NewErr(err)
+}
+
+func (sf *tester) createOkGood2() {
+	sf.t.Log("createOkGood2")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createOkGood2(): panic=%v", _panic)
+		}
+	}()
+	str := "test val"
+	res := NewOk(str)
+	if res == nil {
+		sf.t.Fatalf("createOkGood1(): res==nil")
+	}
+	if !res.IsOk() {
+		sf.t.Fatalf("createOkGood1(): not ok")
+	}
+	if res.IsErr() {
+		sf.t.Fatalf("createOkGood1(): is err")
+	}
+	if val := res.Unwrap(); val != "test val" {
+		sf.t.Fatalf("createOkGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test val" {
+		sf.t.Fatalf("createOkGood1(): val bad")
+	}
+	if val := res.UnwrapOr("test1"); val != "test val" {
+		sf.t.Fatalf("createOkGood1(): val bad")
+	}
+	if val := res.UnwrapOrFn(sf.fnWrap); val != "test val" {
+		sf.t.Fatalf("createOkGood1(): val bad")
+	}
+	if err := res.Error(); err != nil {
+		sf.t.Fatalf("createOkGood1(): err !=nil")
+	}
+	res.Hassert("test")
+	res.Assert("test")
+}
+
+// Функция высшего порядка для замещения ошибки
+func (sf *tester) fnWrap2() any {
+	return "test5"
+}
+
+// Функция высшего порядка для замещения ошибки
+func (sf *tester) fnWrap() string {
+	return "test1"
+}
+
+func (sf *tester) createOkGood1() {
+	sf.t.Log("createOkGood1")
+	defer func() {
+		if _panic := recover(); _panic != nil {
+			sf.t.Fatalf("createOkGood1(): panic=%v", _panic)
+		}
+	}()
+	str := "test val"
+	res := NewOk(&str)
+	if res == nil {
+		sf.t.Fatalf("createOkGood1(): res==nil")
+	}
+}
+
+// Нет результата
+func (sf *tester) createOkBad1() {
+	sf.t.Log("createOkBad1")
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			sf.t.Fatalf("createOkBad1(): panic==nil")
+		}
+	}()
+	var str *string
+	_ = NewOk(str)
+}