package utils
import (
"crypto/rand"
"encoding/hex"
"fmt"
"os"
"reflect"
"runtime"
"runtime/debug"
"slices"
"strings"
"github.com/lithammer/dedent"
am "github.com/pancsta/asyncmachine-go/pkg/machine"
)
const EnvAmHostname = "AM_HOSTNAME"
func J (states []string ) string {
return strings .Join (states , " " )
}
func Jw (states []string , sep string ) string {
return strings .Join (states , sep )
}
func GetVersion () string {
build , ok := debug .ReadBuildInfo ()
if !ok {
return "(devel)"
}
ver := build .Main .Version
if ver == "" {
return "(devel)"
}
return ver
}
func CloseSafe [T any ](ch chan T ) {
select {
case <- ch :
default :
close (ch )
}
}
func SlicesWithout [S ~[]E , E comparable ](coll S , el E ) S {
idx := slices .Index (coll , el )
ret := slices .Clone (coll )
if idx == -1 {
return ret
}
return slices .Delete (ret , idx , idx +1 )
}
func SlicesNone [S1 ~[]E , S2 ~[]E , E comparable ](col1 S1 , col2 S2 ) bool {
for _ , el := range col2 {
if slices .Contains (col1 , el ) {
return false
}
}
return true
}
func SlicesEvery [S1 ~[]E , S2 ~[]E , E comparable ](col1 S1 , col2 S2 ) bool {
for _ , el := range col2 {
if !slices .Contains (col1 , el ) {
return false
}
}
return true
}
func SlicesUniq [S ~[]E , E comparable ](coll S ) S {
var ret S
for _ , el := range coll {
if !slices .Contains (ret , el ) {
ret = append (ret , el )
}
}
return ret
}
func RandId (strLen int ) string {
if strLen == 0 {
strLen = 16
}
strLen ++
strLen = strLen / 2
id := make ([]byte , strLen )
_ , err := rand .Read (id )
if err != nil {
return "error"
}
return hex .EncodeToString (id )
}
func Hostname () string {
if h := os .Getenv (EnvAmHostname ); h != "" {
return h
}
host , _ := os .Hostname ()
if host == "" {
host = "localhost"
}
return host
}
func Sp (txt string , args ...any ) string {
return fmt .Sprintf (dedent .Dedent (strings .Trim (txt , "\n" )), args ...)
}
func P (txt string , args ...any ) {
fmt .Printf (dedent .Dedent (strings .Trim (txt , "\n" )), args ...)
}
func TruncateStr (s string , maxLength int ) string {
if len (s ) <= maxLength {
return s
}
if maxLength < 5 {
return s [:maxLength ]
} else {
return s [:maxLength -3 ] + "..."
}
}
func PadString (str string , length int , pad string ) string {
for {
str += pad
if len (str ) > length {
return str [0 :length ]
}
}
}
func CaptureStackTrace () string {
buf := make ([]byte , 4024 )
n := runtime .Stack (buf , false )
stack := string (buf [:n ])
lines := strings .Split (stack , "\n" )
isPanic := strings .Contains (stack , "panic" )
slices .Reverse (lines )
heads := []string {
"AddErr" , "AddErrState" , "Remove" , "Remove1" , "Add" , "Add1" , "Set" ,
}
stop := false
for i , line := range lines {
if isPanic && strings .HasPrefix (line , "panic(" ) {
lines = lines [:i -1 ]
break
}
for _ , head := range heads {
if strings .Contains ("machine.(*Machine)." +line +"(" , head ) {
lines = lines [:i -1 ]
stop = true
break
}
}
if stop {
break
}
}
slices .Reverse (lines )
join := strings .Join (lines , "\n" )
if filter := os .Getenv (am .EnvAmTraceFilter ); filter != "" {
join = strings .ReplaceAll (join , filter , "" )
}
return join
}
func StructFields (input interface {}) ([]string , error ) {
v := reflect .ValueOf (input )
t := v .Type ()
if t .Kind () != reflect .Struct {
return nil , fmt .Errorf ("expected a struct, got %s" , t .Kind ())
}
var names []string
for i := 0 ; i < t .NumField (); i ++ {
field := t .Field (i )
val := v .Field (i )
if field .Type .Kind () == reflect .Pointer {
el := field .Type .Elem ()
if el .Kind () == reflect .Struct {
if val .IsNil () {
continue
}
value := val .Elem ().Interface ()
elNames , err := StructFields (value )
if err != nil {
return nil , err
}
names = append (names , elNames ...)
}
} else {
names = append (names , field .Name )
}
}
return names , nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .