Files
goutils/type/utils.go

140 lines
2.9 KiB
Go

package Type
import (
"fmt"
"reflect"
"unsafe"
)
func Expect[T any](val Unwrappable[T], msg string) T {
return val.Expect(msg)
}
func Unwrap[T any](val Unwrappable[T]) T {
return val.Unwrap()
}
func UnwrapOr[T any](val Unwrappable[T]) (def T) {
return val.UnwrapOr(def)
}
func UnwrapOrDefault[T any](val Unwrappable[T]) T {
return val.UnwrapOrDefault()
}
func UnwrapOrElse[T any](val Unwrappable[T], f func() T) T {
return val.UnwrapOrElse(f)
}
// Returns if the underlying data has a Value (false in case of None or Error)
func HasValue(val ValueContainer) bool {
return val.HasValue()
}
func ResultWrap[T any](val T, err error) Result[T] {
if err == nil {
return Ok(val)
}
return Err[T](err)
}
func ResultWrapb[T any](err error, val T) Result[T] {
if err == nil {
return Ok(val)
}
return Err[T](err)
}
func Ptr[T any](v T) *T {
return &v
}
// meant to be used as defer Type.CatchUnwrap(Type.Ptr(&res)) or Type.CatchUnwrap(&res) if res is already a pointer
// where res is a pointer to an Option or Result returned by a function (initialized to not be nil)
// func X() (res *Optional[int]) {
// res = None[int]()
// defer CatchUnwrap(&res)
//
// // Some possibly unsafe unwrapping of values
// return res
// }
// === OR ===
// func X() (res Optional[int]) {
// res = None[int]()
// defer Type.CatchUnwrap(Type.Ptr(&res))
//
// // Some possibly unsafe unwrapping of values
// return res
// }
func CatchUnwrap(ret interface{}) {
r := recover()
if r == nil {
return
}
vp := reflect.ValueOf(r)
if vp.Kind() != reflect.Pointer || vp.IsNil() {
panic(r)
}
if _, ok := r.(OptionalerMarker); ok {
if setOptionalNone(ret) {
return
}
}
if _, ok := r.(ResulterMarker); ok {
if setResultError(ret, fmt.Errorf("Tried to unwrap a failed result!")) {
return
}
}
panic(r)
}
func setOptionalNone(ret interface{}) bool {
v := reflect.ValueOf(ret)
if v.Kind() != reflect.Ptr || v.IsNil() {
return false
}
elem := v.Elem().Elem()
if elem.Kind() != reflect.Struct {
return false
}
presentField := elem.FieldByName("present")
if !presentField.IsValid() {
return false
}
if presentField.Kind() == reflect.Bool {
presentField = reflect.NewAt(presentField.Type(),
unsafe.Pointer(presentField.UnsafeAddr())).Elem()
presentField.SetBool(false) // Setting it to false (None)
} else {
return false
}
return true
}
func setResultError(ret interface{}, err error) bool {
v := reflect.ValueOf(ret)
if v.Kind() != reflect.Ptr || v.IsNil() {
return false
}
elem := v.Elem().Elem()
if elem.Kind() != reflect.Struct {
return false
}
errField := elem.FieldByName("err")
if !errField.IsValid() {
return false
}
if errField.Kind() == reflect.Interface {
errField = reflect.NewAt(errField.Type(),
unsafe.Pointer(errField.UnsafeAddr())).Elem()
errField.Set(reflect.ValueOf(err)) // Setting the error
} else {
return false
}
return true
}