Skip to content

Commit

Permalink
Add generic functions
Browse files Browse the repository at this point in the history
  • Loading branch information
nasermirzaei89 committed Feb 24, 2024
1 parent d352341 commit 098eab5
Show file tree
Hide file tree
Showing 9 changed files with 1,807 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.17', '1.18', '1.19','1.20','1.21','1.22' ]
go: [ '1.18', '1.19','1.20','1.21','1.22' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.17', '1.18', '1.19','1.20','1.21','1.22' ]
go: [ '1.18', '1.19','1.20','1.21','1.22' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
Expand Down
5 changes: 5 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ linters:
- dupl
- paralleltest
- depguard
- forcetypeassert
- funlen
- maintidx
- cyclop
- ireturn
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ func main() {

s := env.GetString("B", "hi")
fmt.Println(s) // hi (default)

// Generics

b2 := env.Get("A", true)
fmt.Println(b2) // true (default)

f2 := env.Get("B", 14.5)
fmt.Println(f2) // 14.5 (default)

i2 := env.Get("C", 12)
fmt.Println(i2) // 12 (default)

s2 := env.Get("B", "hi")
fmt.Println(s2) // hi (default)
}
```

Expand All @@ -58,6 +72,13 @@ func main() {
fmt.Println(s) // /Users/nasermirzaei89

s = env.MustGetString("NEW") // panics

// Generics

s2 := env.MustGet[string]("HOME")
fmt.Println(s2) // /Users/nasermirzaei89

s2 = env.MustGet[string]("NEW") // panics
}
```

Expand Down
40 changes: 26 additions & 14 deletions float32_slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,41 @@ import (
)

func TestGetFloat32Slice(t *testing.T) {
def := []float32{21.2, 22.3}
t.Run("GetAbsentFloat32SliceWithDefault", func(t *testing.T) {
def := []float32{21.2, 22.3}

res := env.GetFloat32Slice("V1", def)
assert.Equal(t, def, res)
res := env.GetFloat32Slice("V1", def)
assert.Equal(t, def, res)
})

expected := []float32{31.02, 32.33, 33.33}
t.Run("GetValidFloat32SliceWithDefault", func(t *testing.T) {
def := []float32{21.2, 22.3}
expected := []float32{31.02, 32.33, 33.33}

t.Setenv("V1", "31.02,32.33,33.33")
t.Setenv("V1", "31.02,32.33,33.33")

res = env.GetFloat32Slice("V1", def)
assert.Equal(t, expected, res)
res := env.GetFloat32Slice("V1", def)
assert.Equal(t, expected, res)
})

t.Setenv("V1", "1.2,2.3,Three")
t.Run("GetInvalidFloat32SliceWithDefault", func(t *testing.T) {
def := []float32{21.2, 22.3}

res = env.GetFloat32Slice("V1", def)
assert.Equal(t, def, res)
t.Setenv("V1", "1.2,2.3,Three")

expected = []float32{}
res := env.GetFloat32Slice("V1", def)
assert.Equal(t, def, res)
})

t.Setenv("V1", "")
t.Run("GetEmptyFloat32SliceWithDefault", func(t *testing.T) {
def := []float32{21.2, 22.3}
expected := make([]float32, 0)

res = env.GetFloat32Slice("V1", def)
assert.Equal(t, expected, res)
t.Setenv("V1", "")

res := env.GetFloat32Slice("V1", def)
assert.Equal(t, expected, res)
})
}

func TestMustGetFloat32Slice(t *testing.T) {
Expand Down
141 changes: 141 additions & 0 deletions generic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package env

import (
"fmt"
)

type Type interface {
bool |
float32 | []float32 | float64 | []float64 |
int | []int | int8 | []int8 | int16 | []int16 | int32 | []int32 | int64 | []int64 |
string | []string |
uint | []uint | uint8 | []uint8 | uint16 | []uint16 | uint32 | []uint32 | uint64 | []uint64
}

// Get extracts value from env based on its type. if not set, returns default value.
func Get[T Type](key string, def T) T {
var v T

switch t := any(v).(type) {
case bool:
return any(GetBool(key, any(def).(bool))).(T)
case float32:
return any(GetFloat32(key, any(def).(float32))).(T)
case []float32:
return any(GetFloat32Slice(key, any(def).([]float32))).(T)
case float64:
return any(GetFloat64(key, any(def).(float64))).(T)
case []float64:
return any(GetFloat64Slice(key, any(def).([]float64))).(T)
case int:
return any(GetInt(key, any(def).(int))).(T)
case []int:
return any(GetIntSlice(key, any(def).([]int))).(T)
case int8:
return any(GetInt8(key, any(def).(int8))).(T)
case []int8:
return any(GetInt8Slice(key, any(def).([]int8))).(T)
case int16:
return any(GetInt16(key, any(def).(int16))).(T)
case []int16:
return any(GetInt16Slice(key, any(def).([]int16))).(T)
case int32:
return any(GetInt32(key, any(def).(int32))).(T)
case []int32:
return any(GetInt32Slice(key, any(def).([]int32))).(T)
case int64:
return any(GetInt64(key, any(def).(int64))).(T)
case []int64:
return any(GetInt64Slice(key, any(def).([]int64))).(T)
case string:
return any(GetString(key, any(def).(string))).(T)
case []string:
return any(GetStringSlice(key, any(def).([]string))).(T)
case uint:
return any(GetUint(key, any(def).(uint))).(T)
case []uint:
return any(GetUintSlice(key, any(def).([]uint))).(T)
case uint8:
return any(GetUint8(key, any(def).(uint8))).(T)
case []uint8:
return any(GetUint8Slice(key, any(def).([]uint8))).(T)
case uint16:
return any(GetUint16(key, any(def).(uint16))).(T)
case []uint16:
return any(GetUint16Slice(key, any(def).([]uint16))).(T)
case uint32:
return any(GetUint32(key, any(def).(uint32))).(T)
case []uint32:
return any(GetUint32Slice(key, any(def).([]uint32))).(T)
case uint64:
return any(GetUint64(key, any(def).(uint64))).(T)
case []uint64:
return any(GetUint64Slice(key, any(def).([]uint64))).(T)
default:
panic(fmt.Sprintf("type '%T' is not supported", t))
}
}

// MustGet extracts string value from env based on its type. if not set, it panics.
func MustGet[T Type](key string) T {
var v T

switch t := any(v).(type) {
case bool:
return any(MustGetBool(key)).(T)
case float32:
return any(MustGetFloat32(key)).(T)
case []float32:
return any(MustGetFloat32Slice(key)).(T)
case float64:
return any(MustGetFloat64(key)).(T)
case []float64:
return any(MustGetFloat64Slice(key)).(T)
case int:
return any(MustGetInt(key)).(T)
case []int:
return any(MustGetIntSlice(key)).(T)
case int8:
return any(MustGetInt8(key)).(T)
case []int8:
return any(MustGetInt8Slice(key)).(T)
case int16:
return any(MustGetInt16(key)).(T)
case []int16:
return any(MustGetInt16Slice(key)).(T)
case int32:
return any(MustGetInt32(key)).(T)
case []int32:
return any(MustGetInt32Slice(key)).(T)
case int64:
return any(MustGetInt64(key)).(T)
case []int64:
return any(MustGetInt64Slice(key)).(T)
case string:
return any(MustGetString(key)).(T)
case []string:
return any(MustGetStringSlice(key)).(T)
case uint:
return any(MustGetUint(key)).(T)
case []uint:
return any(MustGetUintSlice(key)).(T)
case uint8:
return any(MustGetUint8(key)).(T)
case []uint8:
return any(MustGetUint8Slice(key)).(T)
case uint16:
return any(MustGetUint16(key)).(T)
case []uint16:
return any(MustGetUint16Slice(key)).(T)
case uint32:
return any(MustGetUint32(key)).(T)
case []uint32:
return any(MustGetUint32Slice(key)).(T)
case uint64:
return any(MustGetUint64(key)).(T)
case []uint64:
return any(MustGetUint64Slice(key)).(T)
default:
panic(fmt.Sprintf("type '%T' is not supported", t))
}
}
Loading

0 comments on commit 098eab5

Please sign in to comment.