Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
496c4e4f59
|
|||
deab986caf
|
|||
9d9a6f1c6e
|
|||
06a37f37b7
|
|||
b35d6ca0b0
|
3
Makefile
3
Makefile
@@ -4,3 +4,6 @@ run:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|
||||||
|
version:
|
||||||
|
_data/version.sh
|
27
_data/version.sh
Executable file
27
_data/version.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o nounset # disallow usage of unset vars ( set -u )
|
||||||
|
set -o errexit # Exit immediately if a pipeline returns non-zero. ( set -e )
|
||||||
|
set -o errtrace # Allow the above trap be inherited by all functions in the script. ( set -E )
|
||||||
|
set -o pipefail # Return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status
|
||||||
|
IFS=$'\n\t' # Set $IFS to only newline and tab.
|
||||||
|
|
||||||
|
|
||||||
|
curr_vers=$(git describe --tags --abbrev=0 | sed 's/v//g')
|
||||||
|
|
||||||
|
next_ver=$(echo "$curr_vers" | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF+1)%(10^length($NF))); print}')
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "> Current Version: ${curr_vers}"
|
||||||
|
echo "> Next Version: ${next_ver}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
git add --verbose .
|
||||||
|
|
||||||
|
git commit -a -m "v${next_ver}"
|
||||||
|
|
||||||
|
git tag "v${next_ver}"
|
||||||
|
|
||||||
|
git push
|
||||||
|
git push --tags
|
||||||
|
|
35
dataext/merge.go
Normal file
35
dataext/merge.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package dataext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ObjectMerge[T1 any, T2 any](base T1, override T2) T1 {
|
||||||
|
|
||||||
|
reflBase := reflect.ValueOf(&base).Elem()
|
||||||
|
reflOvrd := reflect.ValueOf(&override).Elem()
|
||||||
|
|
||||||
|
for i := 0; i < reflBase.NumField(); i++ {
|
||||||
|
|
||||||
|
fieldBase := reflBase.Field(i)
|
||||||
|
fieldOvrd := reflOvrd.Field(i)
|
||||||
|
|
||||||
|
if fieldBase.Kind() != reflect.Ptr || fieldOvrd.Kind() != reflect.Ptr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
kindBase := fieldBase.Type().Elem().Kind()
|
||||||
|
kindOvrd := fieldOvrd.Type().Elem().Kind()
|
||||||
|
|
||||||
|
if kindBase != kindOvrd {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fieldOvrd.IsNil() {
|
||||||
|
fieldBase.Set(fieldOvrd.Elem().Addr())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return base
|
||||||
|
}
|
70
dataext/merge_test.go
Normal file
70
dataext/merge_test.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package dataext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestObjectMerge(t *testing.T) {
|
||||||
|
type A struct {
|
||||||
|
Field1 *int
|
||||||
|
Field2 *string
|
||||||
|
Field3 *float64
|
||||||
|
Field4 *bool
|
||||||
|
OnlyA int64
|
||||||
|
DiffType int
|
||||||
|
}
|
||||||
|
type B struct {
|
||||||
|
Field1 *int
|
||||||
|
Field2 *string
|
||||||
|
Field3 *float64
|
||||||
|
Field4 *bool
|
||||||
|
OnlyB int64
|
||||||
|
DiffType string
|
||||||
|
}
|
||||||
|
|
||||||
|
valueA := A{
|
||||||
|
Field1: nil,
|
||||||
|
Field2: langext.Ptr("99"),
|
||||||
|
Field3: langext.Ptr(12.2),
|
||||||
|
Field4: nil,
|
||||||
|
OnlyA: 1,
|
||||||
|
DiffType: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
valueB := B{
|
||||||
|
Field1: langext.Ptr(12),
|
||||||
|
Field2: nil,
|
||||||
|
Field3: langext.Ptr(13.2),
|
||||||
|
Field4: nil,
|
||||||
|
OnlyB: 1,
|
||||||
|
DiffType: "X",
|
||||||
|
}
|
||||||
|
|
||||||
|
valueMerge := ObjectMerge(valueA, valueB)
|
||||||
|
|
||||||
|
assertPtrEqual(t, "Field1", valueMerge.Field1, valueB.Field1)
|
||||||
|
assertPtrEqual(t, "Field2", valueMerge.Field2, valueA.Field2)
|
||||||
|
assertPtrEqual(t, "Field3", valueMerge.Field3, valueB.Field3)
|
||||||
|
assertPtrEqual(t, "Field4", valueMerge.Field4, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertPtrEqual[T1 comparable](t *testing.T, ident string, actual *T1, expected *T1) {
|
||||||
|
if actual == nil && expected == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if actual != nil && expected != nil {
|
||||||
|
if *actual != *expected {
|
||||||
|
t.Errorf("[%s] values differ: Actual: '%v', Expected: '%v'", ident, *actual, *expected)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if actual == nil && expected != nil {
|
||||||
|
t.Errorf("[%s] values differ: Actual: nil, Expected: not-nil", ident)
|
||||||
|
}
|
||||||
|
if actual != nil && expected == nil {
|
||||||
|
t.Errorf("[%s] values differ: Actual: not-nil, Expected: nil", ident)
|
||||||
|
}
|
||||||
|
}
|
@@ -7,3 +7,11 @@ func FormatBool(v bool, strTrue string, strFalse string) string {
|
|||||||
return strFalse
|
return strFalse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Conditional[T any](v bool, resTrue T, resFalse T) T {
|
||||||
|
if v {
|
||||||
|
return resTrue
|
||||||
|
} else {
|
||||||
|
return resFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -29,3 +29,21 @@ func Min[T langext.OrderedConstraint](v1 T, v2 T) T {
|
|||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Abs[T langext.NumberConstraint](v T) T {
|
||||||
|
if v < 0 {
|
||||||
|
return -v
|
||||||
|
} else {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clamp[T langext.NumberConstraint](v T, min T, max T) T {
|
||||||
|
if v < min {
|
||||||
|
return min
|
||||||
|
} else if v > max {
|
||||||
|
return max
|
||||||
|
} else {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
27
syncext/atomic.go
Normal file
27
syncext/atomic.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package dataext
|
||||||
|
|
||||||
|
import "sync/atomic"
|
||||||
|
|
||||||
|
type AtomicBool struct {
|
||||||
|
v int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAtomicBool(value bool) *AtomicBool {
|
||||||
|
if value {
|
||||||
|
return &AtomicBool{v: 0}
|
||||||
|
} else {
|
||||||
|
return &AtomicBool{v: 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AtomicBool) Get() bool {
|
||||||
|
return atomic.LoadInt32(&a.v) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AtomicBool) Set(value bool) {
|
||||||
|
if value {
|
||||||
|
atomic.StoreInt32(&a.v, 1)
|
||||||
|
} else {
|
||||||
|
atomic.StoreInt32(&a.v, 0)
|
||||||
|
}
|
||||||
|
}
|
@@ -2,59 +2,36 @@ package timeext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromSeconds(v int) time.Duration {
|
func FromNanoseconds[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v) * int64(time.Second))
|
return time.Duration(int64(float64(v) * float64(time.Nanosecond)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromSecondsInt32(v int32) time.Duration {
|
func FromMicroseconds[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v) * int64(time.Second))
|
return time.Duration(int64(float64(v) * float64(time.Microsecond)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromSecondsInt64(v int64) time.Duration {
|
func FromMilliseconds[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(v * int64(time.Second))
|
return time.Duration(int64(float64(v) * float64(time.Millisecond)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromSecondsFloat32(v float32) time.Duration {
|
func FromSeconds[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v * float32(time.Second)))
|
return time.Duration(int64(float64(v) * float64(time.Second)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromSecondsFloat64(v float64) time.Duration {
|
func FromMinutes[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v * float64(time.Second)))
|
return time.Duration(int64(float64(v) * float64(time.Minute)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromSecondsFloat(v float64) time.Duration {
|
func FromHours[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v * float64(time.Second)))
|
return time.Duration(int64(float64(v) * float64(time.Hour)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromMinutes(v int) time.Duration {
|
func FromDays[T langext.NumberConstraint](v T) time.Duration {
|
||||||
return time.Duration(int64(v) * int64(time.Minute))
|
return time.Duration(int64(float64(v) * float64(24) * float64(time.Hour)))
|
||||||
}
|
|
||||||
|
|
||||||
func FromMinutesFloat(v float64) time.Duration {
|
|
||||||
return time.Duration(int64(v * float64(time.Minute)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromMinutesFloat64(v float64) time.Duration {
|
|
||||||
return time.Duration(int64(v * float64(time.Minute)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromHoursFloat64(v float64) time.Duration {
|
|
||||||
return time.Duration(int64(v * float64(time.Hour)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromDays(v int) time.Duration {
|
|
||||||
return time.Duration(int64(v) * int64(24) * int64(time.Hour))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromMilliseconds(v int) time.Duration {
|
|
||||||
return time.Duration(int64(v) * int64(time.Millisecond))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromMillisecondsFloat(v float64) time.Duration {
|
|
||||||
return time.Duration(int64(v * float64(time.Millisecond)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatNaturalDurationEnglish(iv time.Duration) string {
|
func FormatNaturalDurationEnglish(iv time.Duration) string {
|
||||||
|
Reference in New Issue
Block a user