Skip to content

Commit 9504f98

Browse files
author
calvin
committed
some sugar
1 parent c8073c8 commit 9504f98

11 files changed

+348
-1
lines changed

concurrency.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package sugar
2+
3+
import "sync"
4+
5+
type synchronize struct {
6+
locker sync.Locker
7+
}
8+
9+
func (s *synchronize) Do(cb func() error) {
10+
s.locker.Lock()
11+
Try(cb)
12+
s.locker.Unlock()
13+
}
14+
15+
func Synchronize(opt ...sync.Locker) synchronize {
16+
if len(opt) > 1 {
17+
panic("unexpected arguments")
18+
} else if len(opt) == 0 {
19+
opt = append(opt, &sync.Mutex{})
20+
}
21+
22+
return synchronize{locker: opt[0]}
23+
}
24+
25+
func Async[A any](f func() A) chan A {
26+
ch := make(chan A)
27+
28+
go func() {
29+
ch <- f()
30+
}()
31+
32+
return ch
33+
}

condition.go

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package sugar
2+
3+
func Ternary[T any](condition bool, ifOutput T, elseOutput T) T {
4+
5+
if condition {
6+
return ifOutput
7+
}
8+
9+
return elseOutput
10+
}
11+
12+
type IfElse[T any] struct {
13+
Result T
14+
Ok bool
15+
}
16+
17+
func If[T any](condition bool, result T) *IfElse[T] {
18+
19+
if condition {
20+
return &IfElse[T]{result, true}
21+
}
22+
23+
var t T
24+
return &IfElse[T]{t, false}
25+
}
26+
27+
func IfFn[T any](condition bool, resultFn func() T) *IfElse[T] {
28+
29+
if condition {
30+
return &IfElse[T]{resultFn(), true}
31+
}
32+
33+
var t T
34+
return &IfElse[T]{t, false}
35+
}
36+
37+
func (i *IfElse[T]) ElseIf(condition bool, result T) *IfElse[T] {
38+
39+
if condition && !i.Ok {
40+
i.Result = result
41+
i.Ok = true
42+
}
43+
44+
return i
45+
}
46+
47+
func (i *IfElse[T]) ElseIfFn(condition bool, resultFn func() T) *IfElse[T] {
48+
if condition && !i.Ok {
49+
i.Result = resultFn()
50+
i.Ok = true
51+
}
52+
53+
return i
54+
}
55+
56+
func (i *IfElse[T]) Else(result T) T {
57+
if i.Ok {
58+
return i.Result
59+
}
60+
61+
return result
62+
}
63+
64+
func (i *IfElse[T]) ElseFn(resultFn func() T) T {
65+
if i.Ok {
66+
return i.Result
67+
}
68+
69+
return resultFn()
70+
}
71+
72+
type SwitchCase[T comparable, R any] struct {
73+
Predicate T
74+
Result R
75+
Ok bool
76+
}
77+
78+
func Switch[T comparable, R any](predicate T) *SwitchCase[T, R] {
79+
var result R
80+
81+
return &SwitchCase[T, R]{
82+
predicate,
83+
result,
84+
false,
85+
}
86+
}
87+
88+
func (s *SwitchCase[T, R]) Case(value T, result R) *SwitchCase[T, R] {
89+
if !s.Ok && s.Predicate == value {
90+
s.Result = result
91+
s.Ok = true
92+
}
93+
return s
94+
}
95+
96+
func (s *SwitchCase[T, R]) CaseFn(value T, resultFn func() R) *SwitchCase[T, R] {
97+
if !s.Ok && value == s.Predicate {
98+
s.Result = resultFn()
99+
s.Ok = true
100+
}
101+
102+
return s
103+
}
104+
105+
func (s *SwitchCase[T, R]) Default(result R) R {
106+
if !s.Ok {
107+
s.Result = result
108+
}
109+
110+
return s.Result
111+
}
112+
113+
func (s *SwitchCase[T, R]) DefaultFn(resultFn func() R) R {
114+
if !s.Ok {
115+
s.Result = resultFn()
116+
}
117+
118+
return s.Result
119+
}

errors.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package sugar
2+
3+
//Try calls the function and return false in case of error.
4+
func Try(callback func() error) (ok bool) {
5+
ok = true
6+
7+
defer func() {
8+
if err := recover(); err != nil {
9+
ok = false
10+
return
11+
}
12+
}()
13+
14+
err := callback()
15+
if err != nil {
16+
ok = false
17+
}
18+
19+
return
20+
}

find.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package sugar
2+
3+
func IndexOf[T comparable](collection []T, predicate func(T) bool) int {
4+
for i, t := range collection {
5+
if predicate(t) {
6+
return i
7+
}
8+
}
9+
10+
return -1
11+
}
12+
13+
func LastIndexOf[T comparable](collection []T, predicate func(T) bool) int {
14+
l := len(collection)
15+
16+
for i := l - 1; i >= 0; i-- {
17+
if predicate(collection[i]) {
18+
return i
19+
}
20+
}
21+
22+
return -1
23+
}

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module sugar
2+
3+
go 1.18
4+
5+
require golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA=
2+
golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=

intersect.go

+6
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ func Contains[T comparable](collection []T, element T) bool {
88
}
99
return false
1010
}
11+
12+
// Empty returns an empty value.
13+
func Empty[T any]() T {
14+
var t T
15+
return t
16+
}

map.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,6 @@ func MapUpdateValues[K comparable, V any, R any](in map[K]V, iteratee func(K, V)
117117
for k, v := range in {
118118
result[k] = iteratee(k, v)
119119
}
120-
120+
121121
return result
122122
}

math.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package sugar
2+
3+
import (
4+
"golang.org/x/exp/constraints"
5+
)
6+
7+
//Clamp clamps number within the inclusive lower and upper bounds.
8+
func Clamp[T constraints.Ordered](value, min, max T) T {
9+
if value < min {
10+
value = min
11+
} else if value > max {
12+
value = max
13+
}
14+
return value
15+
}

retry.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package sugar
2+
3+
import (
4+
"sync"
5+
"time"
6+
)
7+
8+
type Debounce struct {
9+
after time.Duration
10+
mu *sync.Mutex
11+
timer *time.Timer
12+
done bool
13+
callbacks []func()
14+
}
15+
16+
func NewDebounce(duration time.Duration, fns ...func()) (func(), func()) {
17+
d := &Debounce{
18+
after: duration,
19+
mu: new(sync.Mutex),
20+
timer: nil,
21+
done: false,
22+
callbacks: fns,
23+
}
24+
return func() {
25+
d.reset()
26+
}, d.cancel
27+
}
28+
29+
func (d *Debounce) reset() *Debounce {
30+
d.mu.Lock()
31+
defer d.mu.Unlock()
32+
if d.done {
33+
return d
34+
}
35+
if d.timer != nil {
36+
d.timer.Stop()
37+
}
38+
d.timer = time.AfterFunc(d.after, func() {
39+
for _, cb := range d.callbacks {
40+
cb()
41+
}
42+
})
43+
return d
44+
}
45+
46+
func (d *Debounce) cancel() {
47+
d.mu.Lock()
48+
defer d.mu.Unlock()
49+
if d.timer != nil {
50+
d.timer.Stop()
51+
d.timer = nil
52+
}
53+
d.done = true
54+
}
55+
56+
// AttemptWithDelay invokes a function N times until it returns valid output,
57+
// with a pause between each call. Returning either the caught error or nil.
58+
// When first argument is less than `1`, the function runs until a successful
59+
// response is returned.
60+
61+
func AttemptWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) error) (int, time.Duration, error) {
62+
var err error
63+
start := time.Now()
64+
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
65+
err = f(i, time.Since(start))
66+
if err == nil {
67+
return i + 1, time.Since(start), nil
68+
}
69+
if maxIteration <= 0 || i+1 < maxIteration {
70+
time.Sleep(delay)
71+
}
72+
}
73+
return maxIteration, time.Since(start), err
74+
}

slice.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package sugar
2+
3+
func SliceFileter[V any](collection []V, fileter func(V, int) bool) []V {
4+
5+
result := []V{}
6+
7+
for i, v := range collection {
8+
if fileter(v, i) {
9+
result = append(result, v)
10+
}
11+
}
12+
13+
return result
14+
}
15+
16+
func SliceUpdateElement[T any, R any](collection []T, iteratee func(T, int) R) []R {
17+
result := make([]R, len(collection))
18+
19+
for i, t := range collection {
20+
result[i] = iteratee(t, i)
21+
}
22+
23+
return result
24+
}
25+
26+
func SliceUniq[T any, U comparable](collection []T, iteratee func(T) U) []T {
27+
result := make([]T, len(collection))
28+
29+
seen := make(map[U]struct{}, len(collection))
30+
for _, item := range collection {
31+
key := iteratee(item)
32+
if _, ok := seen[key]; ok {
33+
continue
34+
}
35+
seen[key] = struct{}{}
36+
}
37+
38+
return result
39+
}
40+
41+
func SliceGroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T {
42+
result := map[U][]T{}
43+
44+
for _, item := range collection {
45+
key := iteratee(item)
46+
47+
result[key] = append(result[key], item)
48+
}
49+
return result
50+
}

0 commit comments

Comments
 (0)