From e58b48add7e2538ec60a54582e84ef52ed64d1b7 Mon Sep 17 00:00:00 2001 From: Mariusz Gronczewski Date: Tue, 2 May 2023 18:37:35 +0200 Subject: [PATCH] Must, IgnoreErr function --- README.md | 19 +++++++++++++++++-- utils.go | 19 +++++++++++++++++++ utils_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 utils.go create mode 100644 utils_test.go diff --git a/README.md b/README.md index a6ab791..6a2db1a 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,10 @@ fmt.Printf("%+v", mappedData) // map[a:0x63 b:0xfa c:0x1e d:0x09] ``` + ## Functions + ### Slice * `CompareSliceSet` - check whether slices have same elements regardless of order @@ -106,6 +108,7 @@ fmt.Printf("%+v", mappedData) * `FirstOrEmpty` - return first element or passed "default" value. `[]T -> T` * `LastOrEmpty` - return last element or passed "default" value. `[]T -> T` + ### Map * `MapMap` - Map one map to another using a function. `map[K1]V1 -> map[K2]V2` @@ -119,6 +122,7 @@ fmt.Printf("%+v", mappedData) * `MapSliceSkip` - Same as `MapSlice` but function can return true in second argument to skip the entry. `[]T1 -> []T2` * `MapSliceErrSkip` - Same as `MapSliceErr` but `ErrSkip` error type can be used to skip entry instead of erroring out. `[]T1 -> ([]T2,err)` + ### Filter * `FilterMap` - Filter thru a map using a function. `map[K]V -> map[K]V` @@ -126,6 +130,7 @@ fmt.Printf("%+v", mappedData) * `FilterChan` - Filter thru a channel using a function. `in chan T -> out chan T` * `FilterChanErr` - Filter thru a channel using a function, with separate output channel for that function errors. `in chan T -> (out chan T,err chan error)` + ### Channel tools * `ChanGen` - Feed function output to passed channel in a loop. `(f()T, chan T)` @@ -136,6 +141,7 @@ fmt.Printf("%+v", mappedData) * `ChanToSliceNTimeout` - Loads data to slice from channel to at most N elements or until timeout passes. `(chan T,count,timeout) -> []T` * `SliceToChan` - Sends slice to passed channel in background, optionally closes it. `[]T -> chan T` + ### Worker * `WorkerPool` - spawn x goroutines with workers and return after input channel is closed and all requests are parsed. Optionally close output @@ -144,6 +150,7 @@ fmt.Printf("%+v", mappedData) * `WorkerPoolDrain` - spawn x goroutines that will run a function on the channel element without returning anything * `WorkerPoolAsync` - function will run x goroutines for worker in the background and return a function that enqueues job and returns channel with result of that job, allowing to queue stuff to run in background conveniently + ### Parallel * `ParallelMap` - like `Map` but runs function in parallel up to specified number of goroutines. Ordered. @@ -153,6 +160,7 @@ fmt.Printf("%+v", mappedData) * `ParallelMapSliceChanFinisher` - runs slice elements thru function and sends it to channel. Returns `finisher chan(bool){true}` that will return single `true` message when all workers finish and close it + ### Async * `Async` - run function in background goroutine and return result as a channel. `func()T -> chan T` @@ -162,12 +170,14 @@ fmt.Printf("%+v", mappedData) * `AsyncOut` - as `AsyncPipe` but takes output channel as argument .`(in chan T1, func(T1)T2, chan T2)` * `AsyncIn` - converts value into channel with that value. `T -> chan T` + ### (Re)Try * `Retry` - retry function X times * `RetryAfter` - retry with timeout, minimal, and maximal interval between retries. * `Try` - tries each function in slice till first success + ### Generators Generator functions always return generated values. @@ -180,13 +190,13 @@ For ones that operate on passed on types look at `Type*Gen*` functions like `Sli * `GenChanNCloser` - returns channel fed from generator that returns closer() function that will stop generator from running.`func() K -> (chan T,func closer())` * `GenSliceToChan` - returns channel fed from slice, optionally closes it, `[]K -> chan T` + ### Math Not equivalent of `math` library, NaN math is ignored, zero length inputs might, sanitize your inputs. Results unless specified otherwise will follow math of type, so median of `[]int{8,9}` will be `int{8}` coz of rounding. - * `Sum` * `SumF64` - sum returning float64, for summing up small ints * `Min` @@ -204,9 +214,14 @@ Results unless specified otherwise will follow math of type, so median of `[]int * `ValueIndex` - represents slice element with index * `KeyValue` - represents map key/value pair +## Miscellaneous + +* `Must` - Turn error into panic, returning non-err arguments +* `IgnoreErr` - Ignores error, returning default type value if error is passed + ## Current project state -No API changes to existing functions will be made in 1.x.x releases +No API changes to existing functions AP will be made in 1.x.x releases ## Analytics diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..8eea8e5 --- /dev/null +++ b/utils.go @@ -0,0 +1,19 @@ +package goneric + +// Must takes any value and error, returns the value and panics if error happens. +func Must[T any](in T, err error) (out T) { + if err != nil { + panic(err) + } + return in +} + +// IgnoreErr takes any value, and on error returns the default value +// You should probably not use it... +func IgnoreErr[T any](in T, err error) (out T) { + if err != nil { + var o T + return o + } + return in +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 0000000..0118964 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,29 @@ +package goneric + +import ( + "github.com/stretchr/testify/assert" + "math/rand" + "strconv" + "testing" +) + +func TestMust(t *testing.T) { + v := make([]byte, 4) + i := Must(rand.Read(v)) + assert.Equal(t, 4, i) + + assert.Panics(t, func() { + _ = Must(strconv.Atoi("cat")) + }) +} + +func TestIgnoreErr(t *testing.T) { + v := make([]byte, 4) + i := IgnoreErr(rand.Read(v)) + assert.Equal(t, 4, i) + + assert.NotPanics(t, func() { + _ = IgnoreErr(strconv.Atoi("cat")) + }) + assert.Equal(t, 0, IgnoreErr(strconv.Atoi("cat"))) +}