Skip to content

Commit

Permalink
some sugar
Browse files Browse the repository at this point in the history
  • Loading branch information
calvin committed Jul 13, 2022
1 parent c8073c8 commit 9504f98
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 1 deletion.
33 changes: 33 additions & 0 deletions concurrency.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package sugar

import "sync"

type synchronize struct {
locker sync.Locker
}

func (s *synchronize) Do(cb func() error) {
s.locker.Lock()
Try(cb)
s.locker.Unlock()
}

func Synchronize(opt ...sync.Locker) synchronize {
if len(opt) > 1 {
panic("unexpected arguments")
} else if len(opt) == 0 {
opt = append(opt, &sync.Mutex{})
}

return synchronize{locker: opt[0]}
}

func Async[A any](f func() A) chan A {
ch := make(chan A)

go func() {
ch <- f()
}()

return ch
}
119 changes: 119 additions & 0 deletions condition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package sugar

func Ternary[T any](condition bool, ifOutput T, elseOutput T) T {

if condition {
return ifOutput
}

return elseOutput
}

type IfElse[T any] struct {
Result T
Ok bool
}

func If[T any](condition bool, result T) *IfElse[T] {

if condition {
return &IfElse[T]{result, true}
}

var t T
return &IfElse[T]{t, false}
}

func IfFn[T any](condition bool, resultFn func() T) *IfElse[T] {

if condition {
return &IfElse[T]{resultFn(), true}
}

var t T
return &IfElse[T]{t, false}
}

func (i *IfElse[T]) ElseIf(condition bool, result T) *IfElse[T] {

if condition && !i.Ok {
i.Result = result
i.Ok = true
}

return i
}

func (i *IfElse[T]) ElseIfFn(condition bool, resultFn func() T) *IfElse[T] {
if condition && !i.Ok {
i.Result = resultFn()
i.Ok = true
}

return i
}

func (i *IfElse[T]) Else(result T) T {
if i.Ok {
return i.Result
}

return result
}

func (i *IfElse[T]) ElseFn(resultFn func() T) T {
if i.Ok {
return i.Result
}

return resultFn()
}

type SwitchCase[T comparable, R any] struct {
Predicate T
Result R
Ok bool
}

func Switch[T comparable, R any](predicate T) *SwitchCase[T, R] {
var result R

return &SwitchCase[T, R]{
predicate,
result,
false,
}
}

func (s *SwitchCase[T, R]) Case(value T, result R) *SwitchCase[T, R] {
if !s.Ok && s.Predicate == value {
s.Result = result
s.Ok = true
}
return s
}

func (s *SwitchCase[T, R]) CaseFn(value T, resultFn func() R) *SwitchCase[T, R] {
if !s.Ok && value == s.Predicate {
s.Result = resultFn()
s.Ok = true
}

return s
}

func (s *SwitchCase[T, R]) Default(result R) R {
if !s.Ok {
s.Result = result
}

return s.Result
}

func (s *SwitchCase[T, R]) DefaultFn(resultFn func() R) R {
if !s.Ok {
s.Result = resultFn()
}

return s.Result
}
20 changes: 20 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package sugar

//Try calls the function and return false in case of error.
func Try(callback func() error) (ok bool) {
ok = true

defer func() {
if err := recover(); err != nil {
ok = false
return
}
}()

err := callback()
if err != nil {
ok = false
}

return
}
23 changes: 23 additions & 0 deletions find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package sugar

func IndexOf[T comparable](collection []T, predicate func(T) bool) int {
for i, t := range collection {
if predicate(t) {
return i
}
}

return -1
}

func LastIndexOf[T comparable](collection []T, predicate func(T) bool) int {
l := len(collection)

for i := l - 1; i >= 0; i-- {
if predicate(collection[i]) {
return i
}
}

return -1
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module sugar

go 1.18

require golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA=
golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
6 changes: 6 additions & 0 deletions intersect.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ func Contains[T comparable](collection []T, element T) bool {
}
return false
}

// Empty returns an empty value.
func Empty[T any]() T {
var t T
return t
}
2 changes: 1 addition & 1 deletion map.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,6 @@ func MapUpdateValues[K comparable, V any, R any](in map[K]V, iteratee func(K, V)
for k, v := range in {
result[k] = iteratee(k, v)
}

return result
}
15 changes: 15 additions & 0 deletions math.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sugar

import (
"golang.org/x/exp/constraints"
)

//Clamp clamps number within the inclusive lower and upper bounds.
func Clamp[T constraints.Ordered](value, min, max T) T {
if value < min {
value = min
} else if value > max {
value = max
}
return value
}
74 changes: 74 additions & 0 deletions retry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package sugar

import (
"sync"
"time"
)

type Debounce struct {
after time.Duration
mu *sync.Mutex
timer *time.Timer
done bool
callbacks []func()
}

func NewDebounce(duration time.Duration, fns ...func()) (func(), func()) {
d := &Debounce{
after: duration,
mu: new(sync.Mutex),
timer: nil,
done: false,
callbacks: fns,
}
return func() {
d.reset()
}, d.cancel
}

func (d *Debounce) reset() *Debounce {
d.mu.Lock()
defer d.mu.Unlock()
if d.done {
return d
}
if d.timer != nil {
d.timer.Stop()
}
d.timer = time.AfterFunc(d.after, func() {
for _, cb := range d.callbacks {
cb()
}
})
return d
}

func (d *Debounce) cancel() {
d.mu.Lock()
defer d.mu.Unlock()
if d.timer != nil {
d.timer.Stop()
d.timer = nil
}
d.done = true
}

// AttemptWithDelay invokes a function N times until it returns valid output,
// with a pause between each call. Returning either the caught error or nil.
// When first argument is less than `1`, the function runs until a successful
// response is returned.

func AttemptWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) error) (int, time.Duration, error) {
var err error
start := time.Now()
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
err = f(i, time.Since(start))
if err == nil {
return i + 1, time.Since(start), nil
}
if maxIteration <= 0 || i+1 < maxIteration {
time.Sleep(delay)
}
}
return maxIteration, time.Since(start), err
}
50 changes: 50 additions & 0 deletions slice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package sugar

func SliceFileter[V any](collection []V, fileter func(V, int) bool) []V {

result := []V{}

for i, v := range collection {
if fileter(v, i) {
result = append(result, v)
}
}

return result
}

func SliceUpdateElement[T any, R any](collection []T, iteratee func(T, int) R) []R {
result := make([]R, len(collection))

for i, t := range collection {
result[i] = iteratee(t, i)
}

return result
}

func SliceUniq[T any, U comparable](collection []T, iteratee func(T) U) []T {
result := make([]T, len(collection))

seen := make(map[U]struct{}, len(collection))
for _, item := range collection {
key := iteratee(item)
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
}

return result
}

func SliceGroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T {
result := map[U][]T{}

for _, item := range collection {
key := iteratee(item)

result[key] = append(result[key], item)
}
return result
}

0 comments on commit 9504f98

Please sign in to comment.