wp-go/helper/func.go
2024-06-22 11:32:48 +08:00

211 lines
3.6 KiB
Go

package helper
import (
"context"
"encoding/json"
"errors"
"fmt"
str "github.com/fthvgb1/wp-go/helper/strings"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"time"
)
func ToAny[T any](v T) any {
return v
}
func Or[T any](is bool, left, right T) T {
if is {
return left
}
return right
}
func StructColumnToSlice[T any, M any](arr []M, field string) (r []T) {
for i := 0; i < len(arr); i++ {
v := reflect.ValueOf(arr[i]).FieldByName(field).Interface()
if val, ok := v.(T); ok {
r = append(r, val)
}
}
return
}
func UrlScheme(u string, isHttps bool) string {
return Or(isHttps,
strings.Replace(u, "http://", "https://", 1),
strings.Replace(u, "https://", "http://", 1),
)
}
func CutUrlHost(u string) string {
ur, err := url.Parse(u)
if err != nil {
return u
}
ur.Scheme = ""
ur.Host = ""
return ur.String()
}
func Defaults[T comparable](vals ...T) T {
var val T
for _, v := range vals {
if v != val {
return v
}
}
return val
}
func DefaultVal[T any](v, defaults T) T {
var zero T
if reflect.DeepEqual(zero, v) {
return defaults
}
return v
}
func IsZero[T comparable](t T) bool {
var vv T
return vv != t
}
func IsZeros(v any) bool {
switch v.(type) {
case int64, int, int8, int16, int32, uint64, uint, uint8, uint16, uint32:
i := fmt.Sprintf("%d", v)
return str.ToInt[int64](i) == 0
case float32, float64:
f := fmt.Sprintf("%v", v)
ff, _ := strconv.ParseFloat(f, 64)
return ff == float64(0)
case bool:
return v.(bool) == false
case string:
s := v.(string)
return s == ""
}
return reflect.DeepEqual(v, reflect.Zero(reflect.TypeOf(v)).Interface())
}
func ToBool[T comparable](t T) bool {
v := any(t)
switch v.(type) {
case string:
s := v.(string)
return s != "" && s != "0"
}
var vv T
return vv != t
}
func ToBoolInt(t any) int8 {
if IsZeros(t) {
return 0
}
return 1
}
func GetContextVal[V, K any](ctx context.Context, k K, defaults V) V {
v := ctx.Value(k)
if v == nil {
return defaults
}
vv, ok := v.(V)
if !ok {
return defaults
}
return vv
}
func IsImplements[T, A any](i A) (T, bool) {
var a any = i
t, ok := a.(T)
return t, ok
}
func FileExist(path string) bool {
_, err := os.Stat(path)
return err == nil
}
func IsFile(file string) bool {
info, err := os.Stat(file)
return err == nil && !info.IsDir()
}
func GetAnyVal[T any](v any, defaults T) T {
vv, ok := v.(T)
if !ok {
return defaults
}
return vv
}
func ParseArgs[T any](defaults T, a ...any) T {
for _, aa := range a {
v, ok := aa.(T)
if ok {
return v
}
}
return defaults
}
func RunFnWithTimeout(ctx context.Context, t time.Duration, call func(), a ...any) (err error) {
ctx, cancel := context.WithTimeout(ctx, t)
defer cancel()
done := make(chan struct{}, 1)
go func() {
call()
done <- struct{}{}
}()
select {
case <-ctx.Done():
msg := ParseArgs("", a...)
if msg != "" {
return errors.New(str.Join(msg, ":", ctx.Err().Error()))
}
return ctx.Err()
case <-done:
close(done)
}
return nil
}
func RunFnWithTimeouts[A, V any](ctx context.Context, t time.Duration, ar A, call func(A) (V, error), a ...any) (v V, err error) {
ctx, cancel := context.WithTimeout(ctx, t)
defer cancel()
done := make(chan struct{}, 1)
go func() {
v, err = call(ar)
done <- struct{}{}
}()
select {
case <-ctx.Done():
msg := ParseArgs("", a...)
if msg != "" {
return v, errors.New(str.Join(msg, ":", ctx.Err().Error()))
}
return v, ctx.Err()
case <-done:
close(done)
}
return v, err
}
func JsonDecode[T any](byts []byte) (T, error) {
var v T
err := json.Unmarshal(byts, &v)
return v, err
}
func AsError[T any](err error) (T, bool) {
var v T
ok := errors.As(err, &v)
return v, ok
}